00001 /* 00002 # 00003 # File : CImg.h 00004 # ( C++ header file ) 00005 # 00006 # Description : The C++ Template Image Processing Toolkit. 00007 # This file is the main component of the CImg Library project. 00008 # ( http://cimg.sourceforge.net ) 00009 # 00010 # Project manager : David Tschumperle. 00011 # ( http://www.greyc.ensicaen.fr/~dtschump/ ) 00012 # 00013 # The complete list of contributors is available in file 'README.txt' 00014 # distributed within the CImg package. 00015 # 00016 # Licenses : This file is 'dual-licensed', you have to choose one 00017 # of the two licenses below to apply. 00018 # 00019 # CeCILL-C 00020 # The CeCILL-C license is close to the GNU LGPL. 00021 # ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html ) 00022 # 00023 # or CeCILL v2.0 00024 # The CeCILL license is compatible with the GNU GPL. 00025 # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) 00026 # 00027 # This software is governed either by the CeCILL or the CeCILL-C license 00028 # under French law and abiding by the rules of distribution of free software. 00029 # You can use, modify and or redistribute the software under the terms of 00030 # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA 00031 # at the following URL : "http://www.cecill.info". 00032 # 00033 # As a counterpart to the access to the source code and rights to copy, 00034 # modify and redistribute granted by the license, users are provided only 00035 # with a limited warranty and the software's author, the holder of the 00036 # economic rights, and the successive licensors have only limited 00037 # liability. 00038 # 00039 # In this respect, the user's attention is drawn to the risks associated 00040 # with loading, using, modifying and/or developing or reproducing the 00041 # software by the user in light of its specific status of free software, 00042 # that may mean that it is complicated to manipulate, and that also 00043 # therefore means that it is reserved for developers and experienced 00044 # professionals having in-depth computer knowledge. Users are therefore 00045 # encouraged to load and test the software's suitability as regards their 00046 # requirements in conditions enabling the security of their systems and/or 00047 # data to be ensured and, more generally, to use and operate it in the 00048 # same conditions as regards security. 00049 # 00050 # The fact that you are presently reading this means that you have had 00051 # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms. 00052 # 00053 */ 00054 00055 // Define version number of the library file. 00056 #ifndef cimg_version 00057 #define cimg_version 134 00058 00059 /*----------------------------------------------------------- 00060 # 00061 # Test and auto-set CImg configuration variables 00062 # and include required headers. 00063 # 00064 # If you find that default configuration variables are 00065 # not adapted to your case, you can override their values 00066 # before including the header file "CImg.h" 00067 # (use the #define directive). 00068 # 00069 ------------------------------------------------------------*/ 00070 00071 // Include required standard C++ headers. 00072 #include <cstdio> 00073 #include <cstdlib> 00074 #include <cstdarg> 00075 #include <cstring> 00076 #include <cmath> 00077 #include <ctime> 00078 #include <exception> 00079 00080 // Operating system configuration. 00081 // 00082 // Define 'cimg_OS' to : '0' for an unknown OS (will try to minize library dependancies). 00083 // '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...). 00084 // '2' for Microsoft Windows. 00085 // (autodetection is done by default). 00086 #ifndef cimg_OS 00087 #if defined(unix) || defined(__unix) || defined(__unix__) \ 00088 || defined(linux) || defined(__linux) || defined(__linux__) \ 00089 || defined(sun) || defined(__sun) \ 00090 || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \ 00091 || defined(__FreeBSD__) || defined __DragonFly__ \ 00092 || defined(sgi) || defined(__sgi) \ 00093 || defined(__MACOSX__) || defined(__APPLE__) \ 00094 || defined(__CYGWIN__) 00095 #define cimg_OS 1 00096 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ 00097 || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) 00098 #define cimg_OS 2 00099 #else 00100 #define cimg_OS 0 00101 #endif 00102 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2) 00103 #error CImg Library : Configuration variable 'cimg_OS' is badly defined. 00104 #error (valid values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows'). 00105 #endif 00106 00107 // Disable silly warnings on Microsoft VC++ compilers. 00108 #ifdef _MSC_VER 00109 #pragma warning(push) 00110 #pragma warning(disable:4311) 00111 #pragma warning(disable:4312) 00112 #pragma warning(disable:4800) 00113 #pragma warning(disable:4804) 00114 #pragma warning(disable:4996) 00115 #define _CRT_SECURE_NO_DEPRECATE 1 00116 #define _CRT_NONSTDC_NO_DEPRECATE 1 00117 #endif 00118 00119 // Include OS-specific headers for system management. 00120 #if cimg_OS==1 00121 #include <sys/time.h> 00122 #include <unistd.h> 00123 #elif cimg_OS==2 00124 #include <windows.h> 00125 #ifndef _WIN32_IE 00126 #define _WIN32_IE 0x0400 00127 #endif 00128 #include <shlobj.h> 00129 #endif 00130 00131 // Filename separator configuration. 00132 // 00133 // Default separator is '/' for Unix-based OS, and '\' or Windows. 00134 #ifndef cimg_file_separator 00135 #if cimg_OS==2 00136 #define cimg_file_separator '\\' 00137 #else 00138 #define cimg_file_separator '/' 00139 #endif 00140 #endif 00141 00142 // Output messages verbosity configuration. 00143 // 00144 // Define 'cimg_verbosity' to : '0' to hide library messages (quiet mode). 00145 // '1' to print library messages on the console. 00146 // '2' to display library messages on a dialog window (default behavior). 00147 // '3' to do as '1' + add extra warnings (may slow down the code !). 00148 // '4' to do as '2' + add extra warnings (may slow down the code !). 00149 // 00150 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns. 00151 // 00152 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal). 00153 #ifndef cimg_verbosity 00154 #define cimg_verbosity 2 00155 #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4) 00156 #error CImg Library : Configuration variable 'cimg_verbosity' is badly defined. 00157 #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }). 00158 #endif 00159 00160 // Display framework configuration. 00161 // 00162 // Define 'cimg_display' to : '0' to disable display capabilities. 00163 // '1' to use X-Window framework (X11). 00164 // '2' to use Microsoft GDI32 framework. 00165 #ifndef cimg_display 00166 #if cimg_OS==0 00167 #define cimg_display 0 00168 #elif cimg_OS==1 00169 #if defined(__MACOSX__) || defined(__APPLE__) 00170 #define cimg_display 1 00171 #else 00172 #define cimg_display 1 00173 #endif 00174 #elif cimg_OS==2 00175 #define cimg_display 2 00176 #endif 00177 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2) 00178 #error CImg Library : Configuration variable 'cimg_display' is badly defined. 00179 #error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }). 00180 #endif 00181 00182 // Include display-specific headers. 00183 #if cimg_display==1 00184 #include <X11/Xlib.h> 00185 #include <X11/Xutil.h> 00186 #include <X11/keysym.h> 00187 #include <pthread.h> 00188 #ifdef cimg_use_xshm 00189 #include <sys/ipc.h> 00190 #include <sys/shm.h> 00191 #include <X11/extensions/XShm.h> 00192 #endif 00193 #ifdef cimg_use_xrandr 00194 #include <X11/extensions/Xrandr.h> 00195 #endif 00196 #endif 00197 00198 // OpenMP configuration. 00199 // (http://www.openmp.org) 00200 // 00201 // Define 'cimg_use_openmp' to enable OpenMP support. 00202 // 00203 // OpenMP directives can be used in few CImg functions to get 00204 // advantages of multi-core CPUs. Using OpenMP is not mandatory. 00205 #ifdef cimg_use_openmp 00206 #include <omp.h> 00207 #endif 00208 00209 // LibPNG configuration. 00210 // (http://www.libpng.org) 00211 // 00212 // Define 'cimg_use_png' to enable LibPNG support. 00213 // 00214 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()' 00215 // to get a builtin support of PNG files. Using LibPNG is not mandatory. 00216 #ifdef cimg_use_png 00217 extern "C" { 00218 #include <png.h> 00219 } 00220 #endif 00221 00222 // LibJPEG configuration. 00223 // (http://en.wikipedia.org/wiki/Libjpeg) 00224 // 00225 // Define 'cimg_use_jpeg' to enable LibJPEG support. 00226 // 00227 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()' 00228 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory. 00229 #ifdef cimg_use_jpeg 00230 extern "C" { 00231 #include <jpeglib.h> 00232 } 00233 #endif 00234 00235 // LibTIFF configuration. 00236 // (http://www.libtiff.org) 00237 // 00238 // Define 'cimg_use_tiff' to enable LibTIFF support. 00239 // 00240 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()' 00241 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory. 00242 #ifdef cimg_use_tiff 00243 extern "C" { 00244 #include <tiffio.h> 00245 } 00246 #endif 00247 00248 // FFMPEG Avcodec and Avformat libraries configuration. 00249 // (http://www.ffmpeg.org) 00250 // 00251 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support. 00252 // 00253 // Avcodec and Avformat libraries can be used in functions 00254 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin 00255 // support of various image sequences files. 00256 // Using FFMPEG libraries is not mandatory. 00257 #ifdef cimg_use_ffmpeg 00258 extern "C" { 00259 #include <avformat.h> 00260 #include <avcodec.h> 00261 #include <swscale.h> 00262 } 00263 #endif 00264 00265 // Zlib configuration 00266 // (http://www.zlib.net) 00267 // 00268 // Define 'cimg_use_zlib' to enable Zlib support. 00269 // 00270 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()' 00271 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory. 00272 #ifdef cimg_use_zlib 00273 extern "C" { 00274 #include <zlib.h> 00275 } 00276 #endif 00277 00278 // Magick++ configuration. 00279 // (http://www.imagemagick.org/Magick++) 00280 // 00281 // Define 'cimg_use_magick' to enable Magick++ support. 00282 // 00283 // Magick++ library can be used in functions 'CImg<T>::{load,save}()' 00284 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...). 00285 // Using Magick++ is not mandatory. 00286 #ifdef cimg_use_magick 00287 #include <Magick++.h> 00288 #endif 00289 00290 // FFTW3 configuration. 00291 // (http://www.fftw.org) 00292 // 00293 // Define 'cimg_use_fftw3' to enable libFFTW3 support. 00294 // 00295 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to 00296 // efficiently compute the Fast Fourier Transform of image data. 00297 #ifdef cimg_use_fftw3 00298 extern "C" { 00299 #include <fftw3.h> 00300 } 00301 #endif 00302 00303 // Board configuration 00304 // (http://libboard.sourceforge.net/) 00305 // 00306 // Define 'cimg_use_board' to enable Board support. 00307 // 00308 // Board library can be used in functions 'CImg<T>::draw_object3d()' 00309 // to draw objects 3d in vector-graphics canvas that can be saved 00310 // as .PS or .SVG files afterwards. 00311 #ifdef cimg_use_board 00312 #ifdef None 00313 #undef None 00314 #define _cimg_redefine_None 00315 #endif 00316 #include <Board.h> 00317 #endif 00318 00319 // OpenEXR configuration 00320 // (http://www.openexr.com/) 00321 // 00322 // Define 'cimg_use_openexr' to enable OpenEXR support. 00323 // 00324 // OpenEXR can be used to read/write .exr file formats. 00325 #ifdef cimg_use_openexr 00326 #include "ImfRgbaFile.h" 00327 #include "ImfInputFile.h" 00328 #include "ImfChannelList.h" 00329 #include "ImfMatrixAttribute.h" 00330 #include "ImfArray.h" 00331 #endif 00332 00333 // Lapack configuration. 00334 // (http://www.netlib.org/lapack) 00335 // 00336 // Define 'cimg_use_lapack' to enable LAPACK support. 00337 // 00338 // Lapack can be used in various CImg functions dealing with 00339 // matrix computation and algorithms (eigenvalues, inverse, ...). 00340 // Using Lapack is not mandatory. 00341 #ifdef cimg_use_lapack 00342 extern "C" { 00343 extern void sgetrf_(int*, int*, float*, int*, int*, int*); 00344 extern void sgetri_(int*, float*, int*, int*, float*, int*, int*); 00345 extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*); 00346 extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*); 00347 extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*); 00348 extern void dgetrf_(int*, int*, double*, int*, int*, int*); 00349 extern void dgetri_(int*, double*, int*, int*, double*, int*, int*); 00350 extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*); 00351 extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*); 00352 extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*); 00353 } 00354 #endif 00355 00356 // Check if min/max/PI macros are defined. 00357 // 00358 // CImg does not compile if macros 'min', 'max' or 'PI' are defined, 00359 // because min(), max() and PI labels are defined and used in the cimg:: namespace. 00360 // so it '#undef' these macros if necessary, and restore them to reasonable 00361 // values at the end of the file. 00362 #ifdef min 00363 #undef min 00364 #define _cimg_redefine_min 00365 #endif 00366 #ifdef max 00367 #undef max 00368 #define _cimg_redefine_max 00369 #endif 00370 #ifdef PI 00371 #undef PI 00372 #define _cimg_redefine_PI 00373 #endif 00374 00375 /*------------------------------------------------------------------------------ 00376 # 00377 # Define user-friendly macros. 00378 # 00379 # User macros are prefixed by 'cimg_' and can be used in your own code. 00380 # They are particularly useful for option parsing, and image loops creation. 00381 # 00382 ------------------------------------------------------------------------------*/ 00383 00384 // Define the program usage, and retrieve command line arguments. 00385 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage,false) 00386 #define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0) 00387 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage) 00388 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv) 00389 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0) 00390 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1) 00391 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2) 00392 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3) 00393 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4) 00394 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5) 00395 #define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) cimg_library::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6) 00396 #define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) cimg_library::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7) 00397 #define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) cimg_library::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8) 00398 00399 // Define and manipulate local neighborhoods. 00400 #define CImg_2x2(I,T) T I[4]; \ 00401 T& I##cc = I[0]; T& I##nc = I[1]; \ 00402 T& I##cn = I[2]; T& I##nn = I[3]; \ 00403 I##cc = I##nc = \ 00404 I##cn = I##nn = 0 00405 00406 #define CImg_3x3(I,T) T I[9]; \ 00407 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \ 00408 T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \ 00409 T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \ 00410 I##pp = I##cp = I##np = \ 00411 I##pc = I##cc = I##nc = \ 00412 I##pn = I##cn = I##nn = 0 00413 00414 #define CImg_4x4(I,T) T I[16]; \ 00415 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \ 00416 T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \ 00417 T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \ 00418 T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \ 00419 I##pp = I##cp = I##np = I##ap = \ 00420 I##pc = I##cc = I##nc = I##ac = \ 00421 I##pn = I##cn = I##nn = I##an = \ 00422 I##pa = I##ca = I##na = I##aa = 0 00423 00424 #define CImg_5x5(I,T) T I[25]; \ 00425 T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \ 00426 T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \ 00427 T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \ 00428 T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \ 00429 T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \ 00430 I##bb = I##pb = I##cb = I##nb = I##ab = \ 00431 I##bp = I##pp = I##cp = I##np = I##ap = \ 00432 I##bc = I##pc = I##cc = I##nc = I##ac = \ 00433 I##bn = I##pn = I##cn = I##nn = I##an = \ 00434 I##ba = I##pa = I##ca = I##na = I##aa = 0 00435 00436 #define CImg_2x2x2(I,T) T I[8]; \ 00437 T& I##ccc = I[0]; T& I##ncc = I[1]; \ 00438 T& I##cnc = I[2]; T& I##nnc = I[3]; \ 00439 T& I##ccn = I[4]; T& I##ncn = I[5]; \ 00440 T& I##cnn = I[6]; T& I##nnn = I[7]; \ 00441 I##ccc = I##ncc = \ 00442 I##cnc = I##nnc = \ 00443 I##ccn = I##ncn = \ 00444 I##cnn = I##nnn = 0 00445 00446 #define CImg_3x3x3(I,T) T I[27]; \ 00447 T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \ 00448 T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \ 00449 T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \ 00450 T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \ 00451 T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \ 00452 T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \ 00453 T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \ 00454 T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \ 00455 T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \ 00456 I##ppp = I##cpp = I##npp = \ 00457 I##pcp = I##ccp = I##ncp = \ 00458 I##pnp = I##cnp = I##nnp = \ 00459 I##ppc = I##cpc = I##npc = \ 00460 I##pcc = I##ccc = I##ncc = \ 00461 I##pnc = I##cnc = I##nnc = \ 00462 I##ppn = I##cpn = I##npn = \ 00463 I##pcn = I##ccn = I##ncn = \ 00464 I##pnn = I##cnn = I##nnn = 0 00465 00466 #define cimg_get2x2(img,x,y,z,c,I,T) \ 00467 I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), I[3] = (T)(img)(_n1##x,_n1##y,z,c) 00468 00469 #define cimg_get3x3(img,x,y,z,c,I,T) \ 00470 I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), I[3] = (T)(img)(_p1##x,y,z,c), \ 00471 I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), \ 00472 I[8] = (T)(img)(_n1##x,_n1##y,z,c) 00473 00474 #define cimg_get4x4(img,x,y,z,c,I,T) \ 00475 I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), I[3] = (T)(img)(_n2##x,_p1##y,z,c), \ 00476 I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), \ 00477 I[8] = (T)(img)(_p1##x,_n1##y,z,c), I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \ 00478 I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), I[15] = (T)(img)(_n2##x,_n2##y,z,c) 00479 00480 #define cimg_get5x5(img,x,y,z,c,I,T) \ 00481 I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), I[3] = (T)(img)(_n1##x,_p2##y,z,c), \ 00482 I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), \ 00483 I[8] = (T)(img)(_n1##x,_p1##y,z,c), I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \ 00484 I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), I[15] = (T)(img)(_p2##x,_n1##y,z,c), \ 00485 I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), \ 00486 I[20] = (T)(img)(_p2##x,_n2##y,z,c), I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \ 00487 I[24] = (T)(img)(_n2##x,_n2##y,z,c) 00488 00489 #define cimg_get6x6(img,x,y,z,c,I,T) \ 00490 I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), I[3] = (T)(img)(_n1##x,_p2##y,z,c), \ 00491 I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), \ 00492 I[8] = (T)(img)(x,_p1##y,z,c), I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \ 00493 I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), I[15] = (T)(img)(_n1##x,y,z,c), \ 00494 I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), \ 00495 I[20] = (T)(img)(x,_n1##y,z,c), I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \ 00496 I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), I[27] = (T)(img)(_n1##x,_n2##y,z,c), \ 00497 I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), \ 00498 I[32] = (T)(img)(x,_n3##y,z,c), I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c) 00499 00500 #define cimg_get7x7(img,x,y,z,c,I,T) \ 00501 I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), I[3] = (T)(img)(x,_p3##y,z,c), \ 00502 I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), \ 00503 I[8] = (T)(img)(_p2##x,_p2##y,z,c), I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \ 00504 I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), I[15] = (T)(img)(_p2##x,_p1##y,z,c), \ 00505 I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), \ 00506 I[20] = (T)(img)(_n3##x,_p1##y,z,c), I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \ 00507 I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), I[27] = (T)(img)(_n3##x,y,z,c), \ 00508 I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), \ 00509 I[32] = (T)(img)(_n1##x,_n1##y,z,c), I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \ 00510 I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), I[39] = (T)(img)(_n1##x,_n2##y,z,c), \ 00511 I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), \ 00512 I[44] = (T)(img)(_p1##x,_n3##y,z,c), I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \ 00513 I[48] = (T)(img)(_n3##x,_n3##y,z,c) 00514 00515 #define cimg_get8x8(img,x,y,z,c,I,T) \ 00516 I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), I[3] = (T)(img)(x,_p3##y,z,c), \ 00517 I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), \ 00518 I[8] = (T)(img)(_p3##x,_p2##y,z,c), I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \ 00519 I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), I[15] = (T)(img)(_n4##x,_p2##y,z,c), \ 00520 I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), \ 00521 I[20] = (T)(img)(_n1##x,_p1##y,z,c), I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \ 00522 I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), I[27] = (T)(img)(x,y,z,c), \ 00523 I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), \ 00524 I[32] = (T)(img)(_p3##x,_n1##y,z,c), I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \ 00525 I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), I[39] = (T)(img)(_n4##x,_n1##y,z,c), \ 00526 I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), \ 00527 I[44] = (T)(img)(_n1##x,_n2##y,z,c), I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \ 00528 I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), I[51] = (T)(img)(x,_n3##y,z,c), \ 00529 I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), \ 00530 I[56] = (T)(img)(_p3##x,_n4##y,z,c), I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \ 00531 I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), I[63] = (T)(img)(_n4##x,_n4##y,z,c); 00532 00533 #define cimg_get9x9(img,x,y,z,c,I,T) \ 00534 I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), I[3] = (T)(img)(_p1##x,_p4##y,z,c), \ 00535 I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), \ 00536 I[8] = (T)(img)(_n4##x,_p4##y,z,c), I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \ 00537 I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), I[15] = (T)(img)(_n2##x,_p3##y,z,c), \ 00538 I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), \ 00539 I[20] = (T)(img)(_p2##x,_p2##y,z,c), I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \ 00540 I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), I[27] = (T)(img)(_p4##x,_p1##y,z,c), \ 00541 I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), \ 00542 I[32] = (T)(img)(_n1##x,_p1##y,z,c), I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \ 00543 I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), I[39] = (T)(img)(_p1##x,y,z,c), \ 00544 I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), \ 00545 I[44] = (T)(img)(_n4##x,y,z,c), I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \ 00546 I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), I[51] = (T)(img)(_n2##x,_n1##y,z,c), \ 00547 I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), \ 00548 I[56] = (T)(img)(_p2##x,_n2##y,z,c), I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \ 00549 I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), I[63] = (T)(img)(_p4##x,_n3##y,z,c), \ 00550 I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), \ 00551 I[68] = (T)(img)(_n1##x,_n3##y,z,c), I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \ 00552 I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), I[75] = (T)(img)(_p1##x,_n4##y,z,c), \ 00553 I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), \ 00554 I[80] = (T)(img)(_n4##x,_n4##y,z,c) 00555 00556 #define cimg_get2x2x2(img,x,y,z,c,I,T) \ 00557 I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), I[3] = (T)(img)(_n1##x,_n1##y,z,c), \ 00558 I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c) 00559 00560 #define cimg_get3x3x3(img,x,y,z,c,I,T) \ 00561 I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), \ 00562 I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), I[5] = (T)(img)(_n1##x,y,_p1##z,c), \ 00563 I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), \ 00564 I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), I[11] = (T)(img)(_n1##x,_p1##y,z,c), \ 00565 I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), I[14] = (T)(img)(_n1##x,y,z,c), \ 00566 I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), I[17] = (T)(img)(_n1##x,_n1##y,z,c), \ 00567 I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), \ 00568 I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), I[23] = (T)(img)(_n1##x,y,_n1##z,c), \ 00569 I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c) 00570 00571 // Define various image loops. 00572 // 00573 // These macros generally avoid the use of iterators, but you are not forced to used them ! 00574 #define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; ) 00575 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off) 00576 00577 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i) 00578 #define cimg_forX(img,x) cimg_for1((img)._width,x) 00579 #define cimg_forY(img,y) cimg_for1((img)._height,y) 00580 #define cimg_forZ(img,z) cimg_for1((img)._depth,z) 00581 #define cimg_forC(img,c) cimg_for1((img)._spectrum,c) 00582 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x) 00583 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x) 00584 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y) 00585 #define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x) 00586 #define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y) 00587 #define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z) 00588 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y) 00589 #define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y) 00590 #define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z) 00591 #define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z) 00592 #define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z) 00593 00594 #define cimg_for_in1(bound,i0,i1,i) \ 00595 for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i) 00596 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x) 00597 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y) 00598 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z) 00599 #define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c) 00600 #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x) 00601 #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x) 00602 #define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x) 00603 #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y) 00604 #define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y) 00605 #define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z) 00606 #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y) 00607 #define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y) 00608 #define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z) 00609 #define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z) 00610 #define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00611 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width-1-(n),x) 00612 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height-1-(n),y) 00613 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth-1-(n),z) 00614 #define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum-1-(n),c) 00615 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y) 00616 #define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) 00617 #define cimg_for_insideXYZC(img,x,y,z,c,n) cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) 00618 00619 #define cimg_for_out1(boundi,i0,i1,i) \ 00620 for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i) 00621 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \ 00622 for (int j = 0; j<(int)(boundj); ++j) \ 00623 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \ 00624 ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i)) 00625 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \ 00626 for (int k = 0; k<(int)(boundk); ++k) \ 00627 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ 00628 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \ 00629 ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i)) 00630 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \ 00631 for (int l = 0; l<(int)(boundl); ++l) \ 00632 for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \ 00633 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ 00634 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \ 00635 ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i)) 00636 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x) 00637 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y) 00638 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z) 00639 #define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c) 00640 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y) 00641 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z) 00642 #define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c) 00643 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z) 00644 #define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c) 00645 #define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c) 00646 #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z) 00647 #define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c) 00648 #define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c) 00649 #define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c) 00650 #define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ 00651 cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) 00652 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width-1-(n),x) 00653 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height-1-(n),y) 00654 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth-1-(n),z) 00655 #define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum-1-(n),c) 00656 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y) 00657 #define cimg_for_borderXYZ(img,x,y,z,n) cimg_for_outXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z) 00658 #define cimg_for_borderXYZC(img,x,y,z,c,n) \ 00659 cimg_for_outXYZC(img,n,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),(img)._spectrum-1-(n),x,y,z,c) 00660 00661 #define cimg_for_spiralXY(img,x,y) \ 00662 for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \ 00663 --_n1##y, _n1##x+=(_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width-1-++x:((_n1##x&3)==2?(img)._height-1-++y:--x))))?0:1) 00664 00665 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \ 00666 for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \ 00667 _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \ 00668 _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \ 00669 _counter = _dx, \ 00670 _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \ 00671 _counter>=0; \ 00672 --_counter, x+=_steep? \ 00673 (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \ 00674 (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx)) 00675 00676 #define cimg_for2(bound,i) \ 00677 for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \ 00678 _n1##i<(int)(bound) || i==--_n1##i; \ 00679 ++i, ++_n1##i) 00680 #define cimg_for2X(img,x) cimg_for2((img)._width,x) 00681 #define cimg_for2Y(img,y) cimg_for2((img)._height,y) 00682 #define cimg_for2Z(img,z) cimg_for2((img)._depth,z) 00683 #define cimg_for2C(img,c) cimg_for2((img)._spectrum,c) 00684 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x) 00685 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x) 00686 #define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x) 00687 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y) 00688 #define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y) 00689 #define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z) 00690 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y) 00691 #define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z) 00692 #define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z) 00693 #define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z) 00694 00695 #define cimg_for_in2(bound,i0,i1,i) \ 00696 for (int i = (int)(i0)<0?0:(int)(i0), \ 00697 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \ 00698 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ 00699 ++i, ++_n1##i) 00700 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x) 00701 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y) 00702 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z) 00703 #define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c) 00704 #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x) 00705 #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x) 00706 #define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x) 00707 #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y) 00708 #define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y) 00709 #define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z) 00710 #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y) 00711 #define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z) 00712 #define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) 00713 #define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00714 00715 #define cimg_for3(bound,i) \ 00716 for (int i = 0, _p1##i = 0, \ 00717 _n1##i = 1>=(bound)?(int)(bound)-1:1; \ 00718 _n1##i<(int)(bound) || i==--_n1##i; \ 00719 _p1##i = i++, ++_n1##i) 00720 #define cimg_for3X(img,x) cimg_for3((img)._width,x) 00721 #define cimg_for3Y(img,y) cimg_for3((img)._height,y) 00722 #define cimg_for3Z(img,z) cimg_for3((img)._depth,z) 00723 #define cimg_for3C(img,c) cimg_for3((img)._spectrum,c) 00724 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x) 00725 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x) 00726 #define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x) 00727 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y) 00728 #define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y) 00729 #define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z) 00730 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y) 00731 #define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z) 00732 #define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z) 00733 #define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z) 00734 00735 #define cimg_for_in3(bound,i0,i1,i) \ 00736 for (int i = (int)(i0)<0?0:(int)(i0), \ 00737 _p1##i = i-1<0?0:i-1, \ 00738 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \ 00739 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ 00740 _p1##i = i++, ++_n1##i) 00741 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x) 00742 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y) 00743 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z) 00744 #define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c) 00745 #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x) 00746 #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x) 00747 #define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x) 00748 #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y) 00749 #define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y) 00750 #define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z) 00751 #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y) 00752 #define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z) 00753 #define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) 00754 #define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00755 00756 #define cimg_for4(bound,i) \ 00757 for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \ 00758 _n2##i = 2>=(bound)?(int)(bound)-1:2; \ 00759 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ 00760 _p1##i = i++, ++_n1##i, ++_n2##i) 00761 #define cimg_for4X(img,x) cimg_for4((img)._width,x) 00762 #define cimg_for4Y(img,y) cimg_for4((img)._height,y) 00763 #define cimg_for4Z(img,z) cimg_for4((img)._depth,z) 00764 #define cimg_for4C(img,c) cimg_for4((img)._spectrum,c) 00765 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x) 00766 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x) 00767 #define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x) 00768 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y) 00769 #define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y) 00770 #define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z) 00771 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y) 00772 #define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z) 00773 #define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z) 00774 #define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z) 00775 00776 #define cimg_for_in4(bound,i0,i1,i) \ 00777 for (int i = (int)(i0)<0?0:(int)(i0), \ 00778 _p1##i = i-1<0?0:i-1, \ 00779 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 00780 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \ 00781 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ 00782 _p1##i = i++, ++_n1##i, ++_n2##i) 00783 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x) 00784 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y) 00785 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z) 00786 #define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c) 00787 #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x) 00788 #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x) 00789 #define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x) 00790 #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y) 00791 #define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y) 00792 #define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z) 00793 #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y) 00794 #define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z) 00795 #define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) 00796 #define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00797 00798 #define cimg_for5(bound,i) \ 00799 for (int i = 0, _p2##i = 0, _p1##i = 0, \ 00800 _n1##i = 1>=(bound)?(int)(bound)-1:1, \ 00801 _n2##i = 2>=(bound)?(int)(bound)-1:2; \ 00802 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ 00803 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) 00804 #define cimg_for5X(img,x) cimg_for5((img)._width,x) 00805 #define cimg_for5Y(img,y) cimg_for5((img)._height,y) 00806 #define cimg_for5Z(img,z) cimg_for5((img)._depth,z) 00807 #define cimg_for5C(img,c) cimg_for5((img)._spectrum,c) 00808 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x) 00809 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x) 00810 #define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x) 00811 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y) 00812 #define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y) 00813 #define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z) 00814 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y) 00815 #define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z) 00816 #define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z) 00817 #define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z) 00818 00819 #define cimg_for_in5(bound,i0,i1,i) \ 00820 for (int i = (int)(i0)<0?0:(int)(i0), \ 00821 _p2##i = i-2<0?0:i-2, \ 00822 _p1##i = i-1<0?0:i-1, \ 00823 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 00824 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \ 00825 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ 00826 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) 00827 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x) 00828 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y) 00829 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z) 00830 #define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c) 00831 #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x) 00832 #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x) 00833 #define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x) 00834 #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y) 00835 #define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y) 00836 #define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z) 00837 #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y) 00838 #define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z) 00839 #define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) 00840 #define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00841 00842 #define cimg_for6(bound,i) \ 00843 for (int i = 0, _p2##i = 0, _p1##i = 0, \ 00844 _n1##i = 1>=(bound)?(int)(bound)-1:1, \ 00845 _n2##i = 2>=(bound)?(int)(bound)-1:2, \ 00846 _n3##i = 3>=(bound)?(int)(bound)-1:3; \ 00847 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ 00848 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) 00849 #define cimg_for6X(img,x) cimg_for6((img)._width,x) 00850 #define cimg_for6Y(img,y) cimg_for6((img)._height,y) 00851 #define cimg_for6Z(img,z) cimg_for6((img)._depth,z) 00852 #define cimg_for6C(img,c) cimg_for6((img)._spectrum,c) 00853 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x) 00854 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x) 00855 #define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x) 00856 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y) 00857 #define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y) 00858 #define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z) 00859 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y) 00860 #define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z) 00861 #define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z) 00862 #define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z) 00863 00864 #define cimg_for_in6(bound,i0,i1,i) \ 00865 for (int i = (int)(i0)<0?0:(int)(i0), \ 00866 _p2##i = i-2<0?0:i-2, \ 00867 _p1##i = i-1<0?0:i-1, \ 00868 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 00869 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ 00870 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \ 00871 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ 00872 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) 00873 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x) 00874 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y) 00875 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z) 00876 #define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c) 00877 #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x) 00878 #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x) 00879 #define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x) 00880 #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y) 00881 #define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y) 00882 #define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z) 00883 #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y) 00884 #define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z) 00885 #define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) 00886 #define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00887 00888 #define cimg_for7(bound,i) \ 00889 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ 00890 _n1##i = 1>=(bound)?(int)(bound)-1:1, \ 00891 _n2##i = 2>=(bound)?(int)(bound)-1:2, \ 00892 _n3##i = 3>=(bound)?(int)(bound)-1:3; \ 00893 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ 00894 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) 00895 #define cimg_for7X(img,x) cimg_for7((img)._width,x) 00896 #define cimg_for7Y(img,y) cimg_for7((img)._height,y) 00897 #define cimg_for7Z(img,z) cimg_for7((img)._depth,z) 00898 #define cimg_for7C(img,c) cimg_for7((img)._spectrum,c) 00899 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x) 00900 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x) 00901 #define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x) 00902 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y) 00903 #define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y) 00904 #define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z) 00905 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y) 00906 #define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z) 00907 #define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z) 00908 #define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z) 00909 00910 #define cimg_for_in7(bound,i0,i1,i) \ 00911 for (int i = (int)(i0)<0?0:(int)(i0), \ 00912 _p3##i = i-3<0?0:i-3, \ 00913 _p2##i = i-2<0?0:i-2, \ 00914 _p1##i = i-1<0?0:i-1, \ 00915 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 00916 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ 00917 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \ 00918 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ 00919 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) 00920 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x) 00921 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y) 00922 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z) 00923 #define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c) 00924 #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x) 00925 #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x) 00926 #define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x) 00927 #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y) 00928 #define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y) 00929 #define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z) 00930 #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y) 00931 #define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z) 00932 #define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) 00933 #define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00934 00935 #define cimg_for8(bound,i) \ 00936 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ 00937 _n1##i = 1>=(bound)?(int)(bound)-1:1, \ 00938 _n2##i = 2>=(bound)?(int)(bound)-1:2, \ 00939 _n3##i = 3>=(bound)?(int)(bound)-1:3, \ 00940 _n4##i = 4>=(bound)?(int)(bound)-1:4; \ 00941 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ 00942 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ 00943 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) 00944 #define cimg_for8X(img,x) cimg_for8((img)._width,x) 00945 #define cimg_for8Y(img,y) cimg_for8((img)._height,y) 00946 #define cimg_for8Z(img,z) cimg_for8((img)._depth,z) 00947 #define cimg_for8C(img,c) cimg_for8((img)._spectrum,c) 00948 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x) 00949 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x) 00950 #define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x) 00951 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y) 00952 #define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y) 00953 #define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z) 00954 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y) 00955 #define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z) 00956 #define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z) 00957 #define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z) 00958 00959 #define cimg_for_in8(bound,i0,i1,i) \ 00960 for (int i = (int)(i0)<0?0:(int)(i0), \ 00961 _p3##i = i-3<0?0:i-3, \ 00962 _p2##i = i-2<0?0:i-2, \ 00963 _p1##i = i-1<0?0:i-1, \ 00964 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 00965 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ 00966 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \ 00967 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \ 00968 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ 00969 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ 00970 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) 00971 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x) 00972 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y) 00973 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z) 00974 #define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c) 00975 #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x) 00976 #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x) 00977 #define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x) 00978 #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y) 00979 #define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y) 00980 #define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z) 00981 #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y) 00982 #define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z) 00983 #define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) 00984 #define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 00985 00986 #define cimg_for9(bound,i) \ 00987 for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ 00988 _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \ 00989 _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \ 00990 _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \ 00991 _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \ 00992 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ 00993 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ 00994 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) 00995 #define cimg_for9X(img,x) cimg_for9((img)._width,x) 00996 #define cimg_for9Y(img,y) cimg_for9((img)._height,y) 00997 #define cimg_for9Z(img,z) cimg_for9((img)._depth,z) 00998 #define cimg_for9C(img,c) cimg_for9((img)._spectrum,c) 00999 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x) 01000 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x) 01001 #define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x) 01002 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y) 01003 #define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y) 01004 #define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z) 01005 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y) 01006 #define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z) 01007 #define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z) 01008 #define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z) 01009 01010 #define cimg_for_in9(bound,i0,i1,i) \ 01011 for (int i = (int)(i0)<0?0:(int)(i0), \ 01012 _p4##i = i-4<0?0:i-4, \ 01013 _p3##i = i-3<0?0:i-3, \ 01014 _p2##i = i-2<0?0:i-2, \ 01015 _p1##i = i-1<0?0:i-1, \ 01016 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \ 01017 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \ 01018 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \ 01019 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \ 01020 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ 01021 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ 01022 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) 01023 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x) 01024 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y) 01025 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z) 01026 #define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c) 01027 #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x) 01028 #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x) 01029 #define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x) 01030 #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y) 01031 #define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y) 01032 #define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z) 01033 #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y) 01034 #define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z) 01035 #define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) 01036 #define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) 01037 01038 #define cimg_for2x2(img,x,y,z,c,I,T) \ 01039 cimg_for2((img)._height,y) for (int x = 0, \ 01040 _n1##x = (int)( \ 01041 (I[0] = (T)(img)(0,y,z,c)), \ 01042 (I[2] = (T)(img)(0,_n1##y,z,c)), \ 01043 1>=(img)._width?(img).width()-1:1); \ 01044 (_n1##x<(img).width() && ( \ 01045 (I[1] = (T)(img)(_n1##x,y,z,c)), \ 01046 (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 01047 x==--_n1##x; \ 01048 I[0] = I[1], \ 01049 I[2] = I[3], \ 01050 ++x, ++_n1##x) 01051 01052 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01053 cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01054 _n1##x = (int)( \ 01055 (I[0] = (T)(img)(x,y,z,c)), \ 01056 (I[2] = (T)(img)(x,_n1##y,z,c)), \ 01057 x+1>=(int)(img)._width?(img).width()-1:x+1); \ 01058 x<=(int)(x1) && ((_n1##x<(img).width() && ( \ 01059 (I[1] = (T)(img)(_n1##x,y,z,c)), \ 01060 (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 01061 x==--_n1##x); \ 01062 I[0] = I[1], \ 01063 I[2] = I[3], \ 01064 ++x, ++_n1##x) 01065 01066 #define cimg_for3x3(img,x,y,z,c,I,T) \ 01067 cimg_for3((img)._height,y) for (int x = 0, \ 01068 _p1##x = 0, \ 01069 _n1##x = (int)( \ 01070 (I[0] = I[1] = (T)(img)(0,_p1##y,z,c)), \ 01071 (I[3] = I[4] = (T)(img)(0,y,z,c)), \ 01072 (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ 01073 1>=(img)._width?(img).width()-1:1); \ 01074 (_n1##x<(img).width() && ( \ 01075 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01076 (I[5] = (T)(img)(_n1##x,y,z,c)), \ 01077 (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 01078 x==--_n1##x; \ 01079 I[0] = I[1], I[1] = I[2], \ 01080 I[3] = I[4], I[4] = I[5], \ 01081 I[6] = I[7], I[7] = I[8], \ 01082 _p1##x = x++, ++_n1##x) 01083 01084 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01085 cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01086 _p1##x = x-1<0?0:x-1, \ 01087 _n1##x = (int)( \ 01088 (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01089 (I[3] = (T)(img)(_p1##x,y,z,c)), \ 01090 (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01091 (I[1] = (T)(img)(x,_p1##y,z,c)), \ 01092 (I[4] = (T)(img)(x,y,z,c)), \ 01093 (I[7] = (T)(img)(x,_n1##y,z,c)), \ 01094 x+1>=(int)(img)._width?(img).width()-1:x+1); \ 01095 x<=(int)(x1) && ((_n1##x<(img).width() && ( \ 01096 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01097 (I[5] = (T)(img)(_n1##x,y,z,c)), \ 01098 (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 01099 x==--_n1##x); \ 01100 I[0] = I[1], I[1] = I[2], \ 01101 I[3] = I[4], I[4] = I[5], \ 01102 I[6] = I[7], I[7] = I[8], \ 01103 _p1##x = x++, ++_n1##x) 01104 01105 #define cimg_for4x4(img,x,y,z,c,I,T) \ 01106 cimg_for4((img)._height,y) for (int x = 0, \ 01107 _p1##x = 0, \ 01108 _n1##x = 1>=(img)._width?(img).width()-1:1, \ 01109 _n2##x = (int)( \ 01110 (I[0] = I[1] = (T)(img)(0,_p1##y,z,c)), \ 01111 (I[4] = I[5] = (T)(img)(0,y,z,c)), \ 01112 (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \ 01113 (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \ 01114 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01115 (I[6] = (T)(img)(_n1##x,y,z,c)), \ 01116 (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01117 (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01118 2>=(img)._width?(img).width()-1:2); \ 01119 (_n2##x<(img).width() && ( \ 01120 (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01121 (I[7] = (T)(img)(_n2##x,y,z,c)), \ 01122 (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01123 (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ 01124 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ 01125 I[0] = I[1], I[1] = I[2], I[2] = I[3], \ 01126 I[4] = I[5], I[5] = I[6], I[6] = I[7], \ 01127 I[8] = I[9], I[9] = I[10], I[10] = I[11], \ 01128 I[12] = I[13], I[13] = I[14], I[14] = I[15], \ 01129 _p1##x = x++, ++_n1##x, ++_n2##x) 01130 01131 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01132 cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01133 _p1##x = x-1<0?0:x-1, \ 01134 _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ 01135 _n2##x = (int)( \ 01136 (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01137 (I[4] = (T)(img)(_p1##x,y,z,c)), \ 01138 (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01139 (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01140 (I[1] = (T)(img)(x,_p1##y,z,c)), \ 01141 (I[5] = (T)(img)(x,y,z,c)), \ 01142 (I[9] = (T)(img)(x,_n1##y,z,c)), \ 01143 (I[13] = (T)(img)(x,_n2##y,z,c)), \ 01144 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01145 (I[6] = (T)(img)(_n1##x,y,z,c)), \ 01146 (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01147 (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01148 x+2>=(int)(img)._width?(img).width()-1:x+2); \ 01149 x<=(int)(x1) && ((_n2##x<(img).width() && ( \ 01150 (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01151 (I[7] = (T)(img)(_n2##x,y,z,c)), \ 01152 (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01153 (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ 01154 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ 01155 I[0] = I[1], I[1] = I[2], I[2] = I[3], \ 01156 I[4] = I[5], I[5] = I[6], I[6] = I[7], \ 01157 I[8] = I[9], I[9] = I[10], I[10] = I[11], \ 01158 I[12] = I[13], I[13] = I[14], I[14] = I[15], \ 01159 _p1##x = x++, ++_n1##x, ++_n2##x) 01160 01161 #define cimg_for5x5(img,x,y,z,c,I,T) \ 01162 cimg_for5((img)._height,y) for (int x = 0, \ 01163 _p2##x = 0, _p1##x = 0, \ 01164 _n1##x = 1>=(img)._width?(img).width()-1:1, \ 01165 _n2##x = (int)( \ 01166 (I[0] = I[1] = I[2] = (T)(img)(0,_p2##y,z,c)), \ 01167 (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \ 01168 (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \ 01169 (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \ 01170 (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \ 01171 (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01172 (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01173 (I[13] = (T)(img)(_n1##x,y,z,c)), \ 01174 (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01175 (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01176 2>=(img)._width?(img).width()-1:2); \ 01177 (_n2##x<(img).width() && ( \ 01178 (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01179 (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01180 (I[14] = (T)(img)(_n2##x,y,z,c)), \ 01181 (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01182 (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ 01183 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ 01184 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ 01185 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ 01186 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ 01187 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ 01188 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ 01189 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) 01190 01191 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01192 cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01193 _p2##x = x-2<0?0:x-2, \ 01194 _p1##x = x-1<0?0:x-1, \ 01195 _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ 01196 _n2##x = (int)( \ 01197 (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ 01198 (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \ 01199 (I[10] = (T)(img)(_p2##x,y,z,c)), \ 01200 (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \ 01201 (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \ 01202 (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ 01203 (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01204 (I[11] = (T)(img)(_p1##x,y,z,c)), \ 01205 (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01206 (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01207 (I[2] = (T)(img)(x,_p2##y,z,c)), \ 01208 (I[7] = (T)(img)(x,_p1##y,z,c)), \ 01209 (I[12] = (T)(img)(x,y,z,c)), \ 01210 (I[17] = (T)(img)(x,_n1##y,z,c)), \ 01211 (I[22] = (T)(img)(x,_n2##y,z,c)), \ 01212 (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01213 (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01214 (I[13] = (T)(img)(_n1##x,y,z,c)), \ 01215 (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01216 (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01217 x+2>=(int)(img)._width?(img).width()-1:x+2); \ 01218 x<=(int)(x1) && ((_n2##x<(img).width() && ( \ 01219 (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01220 (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01221 (I[14] = (T)(img)(_n2##x,y,z,c)), \ 01222 (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01223 (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ 01224 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ 01225 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ 01226 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ 01227 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ 01228 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ 01229 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ 01230 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) 01231 01232 #define cimg_for6x6(img,x,y,z,c,I,T) \ 01233 cimg_for6((img)._height,y) for (int x = 0, \ 01234 _p2##x = 0, _p1##x = 0, \ 01235 _n1##x = 1>=(img)._width?(img).width()-1:1, \ 01236 _n2##x = 2>=(img)._width?(img).width()-1:2, \ 01237 _n3##x = (int)( \ 01238 (I[0] = I[1] = I[2] = (T)(img)(0,_p2##y,z,c)), \ 01239 (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \ 01240 (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \ 01241 (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \ 01242 (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \ 01243 (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \ 01244 (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01245 (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01246 (I[15] = (T)(img)(_n1##x,y,z,c)), \ 01247 (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01248 (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01249 (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01250 (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01251 (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01252 (I[16] = (T)(img)(_n2##x,y,z,c)), \ 01253 (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01254 (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01255 (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01256 3>=(img)._width?(img).width()-1:3); \ 01257 (_n3##x<(img).width() && ( \ 01258 (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01259 (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01260 (I[17] = (T)(img)(_n3##x,y,z,c)), \ 01261 (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01262 (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01263 (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ 01264 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \ 01265 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ 01266 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ 01267 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ 01268 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ 01269 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ 01270 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ 01271 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) 01272 01273 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01274 cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \ 01275 _p2##x = x-2<0?0:x-2, \ 01276 _p1##x = x-1<0?0:x-1, \ 01277 _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ 01278 _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \ 01279 _n3##x = (int)( \ 01280 (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ 01281 (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \ 01282 (I[12] = (T)(img)(_p2##x,y,z,c)), \ 01283 (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \ 01284 (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \ 01285 (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \ 01286 (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ 01287 (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01288 (I[13] = (T)(img)(_p1##x,y,z,c)), \ 01289 (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01290 (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01291 (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \ 01292 (I[2] = (T)(img)(x,_p2##y,z,c)), \ 01293 (I[8] = (T)(img)(x,_p1##y,z,c)), \ 01294 (I[14] = (T)(img)(x,y,z,c)), \ 01295 (I[20] = (T)(img)(x,_n1##y,z,c)), \ 01296 (I[26] = (T)(img)(x,_n2##y,z,c)), \ 01297 (I[32] = (T)(img)(x,_n3##y,z,c)), \ 01298 (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01299 (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01300 (I[15] = (T)(img)(_n1##x,y,z,c)), \ 01301 (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01302 (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01303 (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01304 (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01305 (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01306 (I[16] = (T)(img)(_n2##x,y,z,c)), \ 01307 (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01308 (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01309 (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01310 x+3>=(int)(img)._width?(img).width()-1:x+3); \ 01311 x<=(int)(x1) && ((_n3##x<(img).width() && ( \ 01312 (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01313 (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01314 (I[17] = (T)(img)(_n3##x,y,z,c)), \ 01315 (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01316 (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01317 (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ 01318 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \ 01319 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ 01320 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ 01321 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ 01322 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ 01323 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ 01324 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ 01325 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) 01326 01327 #define cimg_for7x7(img,x,y,z,c,I,T) \ 01328 cimg_for7((img)._height,y) for (int x = 0, \ 01329 _p3##x = 0, _p2##x = 0, _p1##x = 0, \ 01330 _n1##x = 1>=(img)._width?(img).width()-1:1, \ 01331 _n2##x = 2>=(img)._width?(img).width()-1:2, \ 01332 _n3##x = (int)( \ 01333 (I[0] = I[1] = I[2] = I[3] = (T)(img)(0,_p3##y,z,c)), \ 01334 (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \ 01335 (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \ 01336 (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \ 01337 (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \ 01338 (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \ 01339 (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \ 01340 (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01341 (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01342 (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01343 (I[25] = (T)(img)(_n1##x,y,z,c)), \ 01344 (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01345 (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01346 (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01347 (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01348 (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01349 (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01350 (I[26] = (T)(img)(_n2##x,y,z,c)), \ 01351 (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01352 (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01353 (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01354 3>=(img)._width?(img).width()-1:3); \ 01355 (_n3##x<(img).width() && ( \ 01356 (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01357 (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01358 (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01359 (I[27] = (T)(img)(_n3##x,y,z,c)), \ 01360 (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01361 (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01362 (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ 01363 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \ 01364 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ 01365 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ 01366 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ 01367 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ 01368 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ 01369 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ 01370 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ 01371 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) 01372 01373 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01374 cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01375 _p3##x = x-3<0?0:x-3, \ 01376 _p2##x = x-2<0?0:x-2, \ 01377 _p1##x = x-1<0?0:x-1, \ 01378 _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \ 01379 _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \ 01380 _n3##x = (int)( \ 01381 (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ 01382 (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \ 01383 (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \ 01384 (I[21] = (T)(img)(_p3##x,y,z,c)), \ 01385 (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \ 01386 (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \ 01387 (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \ 01388 (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ 01389 (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \ 01390 (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \ 01391 (I[22] = (T)(img)(_p2##x,y,z,c)), \ 01392 (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \ 01393 (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \ 01394 (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \ 01395 (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ 01396 (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \ 01397 (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01398 (I[23] = (T)(img)(_p1##x,y,z,c)), \ 01399 (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01400 (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01401 (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \ 01402 (I[3] = (T)(img)(x,_p3##y,z,c)), \ 01403 (I[10] = (T)(img)(x,_p2##y,z,c)), \ 01404 (I[17] = (T)(img)(x,_p1##y,z,c)), \ 01405 (I[24] = (T)(img)(x,y,z,c)), \ 01406 (I[31] = (T)(img)(x,_n1##y,z,c)), \ 01407 (I[38] = (T)(img)(x,_n2##y,z,c)), \ 01408 (I[45] = (T)(img)(x,_n3##y,z,c)), \ 01409 (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01410 (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01411 (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01412 (I[25] = (T)(img)(_n1##x,y,z,c)), \ 01413 (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01414 (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01415 (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01416 (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01417 (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01418 (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01419 (I[26] = (T)(img)(_n2##x,y,z,c)), \ 01420 (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01421 (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01422 (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01423 x+3>=(int)(img)._width?(img).width()-1:x+3); \ 01424 x<=(int)(x1) && ((_n3##x<(img).width() && ( \ 01425 (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01426 (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01427 (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01428 (I[27] = (T)(img)(_n3##x,y,z,c)), \ 01429 (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01430 (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01431 (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ 01432 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \ 01433 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ 01434 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ 01435 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ 01436 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ 01437 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ 01438 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ 01439 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ 01440 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) 01441 01442 #define cimg_for8x8(img,x,y,z,c,I,T) \ 01443 cimg_for8((img)._height,y) for (int x = 0, \ 01444 _p3##x = 0, _p2##x = 0, _p1##x = 0, \ 01445 _n1##x = 1>=((img)._width)?(img).width()-1:1, \ 01446 _n2##x = 2>=((img)._width)?(img).width()-1:2, \ 01447 _n3##x = 3>=((img)._width)?(img).width()-1:3, \ 01448 _n4##x = (int)( \ 01449 (I[0] = I[1] = I[2] = I[3] = (T)(img)(0,_p3##y,z,c)), \ 01450 (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \ 01451 (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \ 01452 (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \ 01453 (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \ 01454 (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \ 01455 (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \ 01456 (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \ 01457 (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01458 (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01459 (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01460 (I[28] = (T)(img)(_n1##x,y,z,c)), \ 01461 (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01462 (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01463 (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01464 (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ 01465 (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01466 (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01467 (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01468 (I[29] = (T)(img)(_n2##x,y,z,c)), \ 01469 (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01470 (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01471 (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01472 (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ 01473 (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01474 (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01475 (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01476 (I[30] = (T)(img)(_n3##x,y,z,c)), \ 01477 (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01478 (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01479 (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ 01480 (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ 01481 4>=((img)._width)?(img).width()-1:4); \ 01482 (_n4##x<(img).width() && ( \ 01483 (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ 01484 (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ 01485 (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ 01486 (I[31] = (T)(img)(_n4##x,y,z,c)), \ 01487 (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ 01488 (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ 01489 (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ 01490 (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ 01491 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ 01492 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ 01493 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ 01494 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ 01495 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ 01496 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ 01497 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ 01498 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ 01499 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ 01500 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) 01501 01502 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01503 cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01504 _p3##x = x-3<0?0:x-3, \ 01505 _p2##x = x-2<0?0:x-2, \ 01506 _p1##x = x-1<0?0:x-1, \ 01507 _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \ 01508 _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \ 01509 _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \ 01510 _n4##x = (int)( \ 01511 (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ 01512 (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \ 01513 (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \ 01514 (I[24] = (T)(img)(_p3##x,y,z,c)), \ 01515 (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \ 01516 (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \ 01517 (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \ 01518 (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \ 01519 (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ 01520 (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \ 01521 (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \ 01522 (I[25] = (T)(img)(_p2##x,y,z,c)), \ 01523 (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \ 01524 (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \ 01525 (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \ 01526 (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \ 01527 (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ 01528 (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \ 01529 (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01530 (I[26] = (T)(img)(_p1##x,y,z,c)), \ 01531 (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01532 (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01533 (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \ 01534 (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \ 01535 (I[3] = (T)(img)(x,_p3##y,z,c)), \ 01536 (I[11] = (T)(img)(x,_p2##y,z,c)), \ 01537 (I[19] = (T)(img)(x,_p1##y,z,c)), \ 01538 (I[27] = (T)(img)(x,y,z,c)), \ 01539 (I[35] = (T)(img)(x,_n1##y,z,c)), \ 01540 (I[43] = (T)(img)(x,_n2##y,z,c)), \ 01541 (I[51] = (T)(img)(x,_n3##y,z,c)), \ 01542 (I[59] = (T)(img)(x,_n4##y,z,c)), \ 01543 (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01544 (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01545 (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01546 (I[28] = (T)(img)(_n1##x,y,z,c)), \ 01547 (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01548 (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01549 (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01550 (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ 01551 (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01552 (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01553 (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01554 (I[29] = (T)(img)(_n2##x,y,z,c)), \ 01555 (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01556 (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01557 (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01558 (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ 01559 (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01560 (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01561 (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01562 (I[30] = (T)(img)(_n3##x,y,z,c)), \ 01563 (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01564 (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01565 (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ 01566 (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ 01567 x+4>=(img).width()?(img).width()-1:x+4); \ 01568 x<=(int)(x1) && ((_n4##x<(img).width() && ( \ 01569 (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ 01570 (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ 01571 (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ 01572 (I[31] = (T)(img)(_n4##x,y,z,c)), \ 01573 (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ 01574 (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ 01575 (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ 01576 (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ 01577 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ 01578 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ 01579 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ 01580 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ 01581 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ 01582 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ 01583 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ 01584 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ 01585 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ 01586 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) 01587 01588 #define cimg_for9x9(img,x,y,z,c,I,T) \ 01589 cimg_for9((img)._height,y) for (int x = 0, \ 01590 _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \ 01591 _n1##x = 1>=((img)._width)?(img).width()-1:1, \ 01592 _n2##x = 2>=((img)._width)?(img).width()-1:2, \ 01593 _n3##x = 3>=((img)._width)?(img).width()-1:3, \ 01594 _n4##x = (int)( \ 01595 (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(0,_p4##y,z,c)), \ 01596 (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \ 01597 (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \ 01598 (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \ 01599 (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \ 01600 (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \ 01601 (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \ 01602 (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \ 01603 (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \ 01604 (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ 01605 (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01606 (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01607 (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01608 (I[41] = (T)(img)(_n1##x,y,z,c)), \ 01609 (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01610 (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01611 (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01612 (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ 01613 (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ 01614 (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01615 (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01616 (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01617 (I[42] = (T)(img)(_n2##x,y,z,c)), \ 01618 (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01619 (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01620 (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01621 (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ 01622 (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ 01623 (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01624 (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01625 (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01626 (I[43] = (T)(img)(_n3##x,y,z,c)), \ 01627 (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01628 (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01629 (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ 01630 (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ 01631 4>=((img)._width)?(img).width()-1:4); \ 01632 (_n4##x<(img).width() && ( \ 01633 (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ 01634 (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ 01635 (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ 01636 (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ 01637 (I[44] = (T)(img)(_n4##x,y,z,c)), \ 01638 (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ 01639 (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ 01640 (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ 01641 (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ 01642 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ 01643 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ 01644 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ 01645 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \ 01646 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ 01647 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \ 01648 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \ 01649 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \ 01650 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ 01651 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \ 01652 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) 01653 01654 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \ 01655 cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01656 _p4##x = x-4<0?0:x-4, \ 01657 _p3##x = x-3<0?0:x-3, \ 01658 _p2##x = x-2<0?0:x-2, \ 01659 _p1##x = x-1<0?0:x-1, \ 01660 _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \ 01661 _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \ 01662 _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \ 01663 _n4##x = (int)( \ 01664 (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \ 01665 (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \ 01666 (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \ 01667 (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \ 01668 (I[36] = (T)(img)(_p4##x,y,z,c)), \ 01669 (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \ 01670 (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \ 01671 (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \ 01672 (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \ 01673 (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \ 01674 (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \ 01675 (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \ 01676 (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \ 01677 (I[37] = (T)(img)(_p3##x,y,z,c)), \ 01678 (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \ 01679 (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \ 01680 (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \ 01681 (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \ 01682 (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \ 01683 (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \ 01684 (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \ 01685 (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \ 01686 (I[38] = (T)(img)(_p2##x,y,z,c)), \ 01687 (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \ 01688 (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \ 01689 (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \ 01690 (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \ 01691 (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \ 01692 (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \ 01693 (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \ 01694 (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01695 (I[39] = (T)(img)(_p1##x,y,z,c)), \ 01696 (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01697 (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \ 01698 (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \ 01699 (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \ 01700 (I[4] = (T)(img)(x,_p4##y,z,c)), \ 01701 (I[13] = (T)(img)(x,_p3##y,z,c)), \ 01702 (I[22] = (T)(img)(x,_p2##y,z,c)), \ 01703 (I[31] = (T)(img)(x,_p1##y,z,c)), \ 01704 (I[40] = (T)(img)(x,y,z,c)), \ 01705 (I[49] = (T)(img)(x,_n1##y,z,c)), \ 01706 (I[58] = (T)(img)(x,_n2##y,z,c)), \ 01707 (I[67] = (T)(img)(x,_n3##y,z,c)), \ 01708 (I[76] = (T)(img)(x,_n4##y,z,c)), \ 01709 (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ 01710 (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ 01711 (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ 01712 (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01713 (I[41] = (T)(img)(_n1##x,y,z,c)), \ 01714 (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01715 (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ 01716 (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ 01717 (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ 01718 (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ 01719 (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ 01720 (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ 01721 (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ 01722 (I[42] = (T)(img)(_n2##x,y,z,c)), \ 01723 (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ 01724 (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ 01725 (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ 01726 (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ 01727 (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ 01728 (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ 01729 (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ 01730 (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ 01731 (I[43] = (T)(img)(_n3##x,y,z,c)), \ 01732 (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ 01733 (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ 01734 (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ 01735 (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ 01736 x+4>=(img).width()?(img).width()-1:x+4); \ 01737 x<=(int)(x1) && ((_n4##x<(img).width() && ( \ 01738 (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ 01739 (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ 01740 (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ 01741 (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ 01742 (I[44] = (T)(img)(_n4##x,y,z,c)), \ 01743 (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ 01744 (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ 01745 (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ 01746 (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ 01747 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ 01748 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ 01749 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ 01750 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \ 01751 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ 01752 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \ 01753 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \ 01754 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \ 01755 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ 01756 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \ 01757 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) 01758 01759 #define cimg_for2x2x2(img,x,y,z,c,I,T) \ 01760 cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \ 01761 _n1##x = (int)( \ 01762 (I[0] = (T)(img)(0,y,z,c)), \ 01763 (I[2] = (T)(img)(0,_n1##y,z,c)), \ 01764 (I[4] = (T)(img)(0,y,_n1##z,c)), \ 01765 (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \ 01766 1>=(img)._width?(img).width()-1:1); \ 01767 (_n1##x<(img).width() && ( \ 01768 (I[1] = (T)(img)(_n1##x,y,z,c)), \ 01769 (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01770 (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ 01771 (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ 01772 x==--_n1##x; \ 01773 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ 01774 ++x, ++_n1##x) 01775 01776 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ 01777 cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01778 _n1##x = (int)( \ 01779 (I[0] = (T)(img)(x,y,z,c)), \ 01780 (I[2] = (T)(img)(x,_n1##y,z,c)), \ 01781 (I[4] = (T)(img)(x,y,_n1##z,c)), \ 01782 (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \ 01783 x+1>=(int)(img)._width?(img).width()-1:x+1); \ 01784 x<=(int)(x1) && ((_n1##x<(img).width() && ( \ 01785 (I[1] = (T)(img)(_n1##x,y,z,c)), \ 01786 (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01787 (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ 01788 (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ 01789 x==--_n1##x); \ 01790 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ 01791 ++x, ++_n1##x) 01792 01793 #define cimg_for3x3x3(img,x,y,z,c,I,T) \ 01794 cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \ 01795 _p1##x = 0, \ 01796 _n1##x = (int)( \ 01797 (I[0] = I[1] = (T)(img)(0,_p1##y,_p1##z,c)), \ 01798 (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)), \ 01799 (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \ 01800 (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \ 01801 (I[12] = I[13] = (T)(img)(0,y,z,c)), \ 01802 (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \ 01803 (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \ 01804 (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \ 01805 (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \ 01806 1>=(img)._width?(img).width()-1:1); \ 01807 (_n1##x<(img).width() && ( \ 01808 (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ 01809 (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ 01810 (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ 01811 (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01812 (I[14] = (T)(img)(_n1##x,y,z,c)), \ 01813 (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01814 (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ 01815 (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ 01816 (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ 01817 x==--_n1##x; \ 01818 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ 01819 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ 01820 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ 01821 _p1##x = x++, ++_n1##x) 01822 01823 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ 01824 cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ 01825 _p1##x = x-1<0?0:x-1, \ 01826 _n1##x = (int)( \ 01827 (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ 01828 (I[3] = (T)(img)(_p1##x,y,_p1##z,c)), \ 01829 (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \ 01830 (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \ 01831 (I[12] = (T)(img)(_p1##x,y,z,c)), \ 01832 (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \ 01833 (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \ 01834 (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \ 01835 (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \ 01836 (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \ 01837 (I[4] = (T)(img)(x,y,_p1##z,c)), \ 01838 (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \ 01839 (I[10] = (T)(img)(x,_p1##y,z,c)), \ 01840 (I[13] = (T)(img)(x,y,z,c)), \ 01841 (I[16] = (T)(img)(x,_n1##y,z,c)), \ 01842 (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \ 01843 (I[22] = (T)(img)(x,y,_n1##z,c)), \ 01844 (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \ 01845 x+1>=(int)(img)._width?(img).width()-1:x+1); \ 01846 x<=(int)(x1) && ((_n1##x<(img).width() && ( \ 01847 (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ 01848 (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ 01849 (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ 01850 (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ 01851 (I[14] = (T)(img)(_n1##x,y,z,c)), \ 01852 (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ 01853 (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ 01854 (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ 01855 (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ 01856 x==--_n1##x); \ 01857 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ 01858 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ 01859 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ 01860 _p1##x = x++, ++_n1##x) 01861 01862 #define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l) 01863 #define cimglist_for_in(list,l0,l1,l) \ 01864 for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width-1; l<=_max##l; ++l) 01865 01866 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn 01867 01868 // Define macros used when exceptions are thrown. 01869 #define _cimgdisplay_instance "[instance(%u,%u,%u,%c%s%c)] CImgDisplay::" 01870 #define cimgdisplay_instance _width,_height,_normalization,_title?'\"':'[',_title?_title:"untitled",_title?'\"':']' 01871 #define _cimg_instance "[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::" 01872 #define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?"":"non-",pixel_type() 01873 #define _cimglist_instance "[instance(%u,%u,%p)] CImgList<%s>::" 01874 #define cimglist_instance _width,_allocated_width,_data,pixel_type() 01875 01876 /*------------------------------------------------ 01877 # 01878 # 01879 # Definition of the cimg_library:: namespace 01880 # 01881 # 01882 -------------------------------------------------*/ 01883 //! This namespace encompasses all classes and functions of the %CImg library. 01884 /** 01885 This namespace is defined to avoid functions and class names collisions 01886 that could happen with the include of other C++ header files. 01887 Anyway, it should not happen often and you should reasonnably start most of your 01888 %CImg-based programs with 01889 \code 01890 #include "CImg.h" 01891 using namespace cimg_library; 01892 \endcode 01893 to simplify the declaration of %CImg Library variables afterwards. 01894 **/ 01895 namespace cimg_library { 01896 01897 // Declare the only four classes of the CImg Library. 01898 template<typename T=float> struct CImg; 01899 template<typename T=float> struct CImgList; 01900 struct CImgDisplay; 01901 struct CImgException; 01902 01903 // (Pre)declare the cimg namespace. 01904 // This is not the complete namespace declaration. It only contains some 01905 // necessary stuffs to ensure a correct declaration order of classes and functions 01906 // defined afterwards. 01907 namespace cimg { 01908 01909 #ifdef cimg_use_vt100 01910 const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 }; 01911 const char t_red[] = { 0x1b, '[', '4', ';', '3', '1', ';', '5', '9', 'm', 0 }; 01912 const char t_bold[] = { 0x1b, '[', '1', 'm', 0 }; 01913 const char t_purple[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 }; 01914 const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 }; 01915 #else 01916 const char t_normal[] = { 0 }; 01917 const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal, 01918 *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal; 01919 #endif 01920 01921 inline std::FILE* output(std::FILE *file=0); 01922 inline void info(); 01923 01924 // Function used to avoid warning messages due to unused parameters. 01925 template<typename T> 01926 inline void unused(const T&, ...) {} 01927 01928 //! Get/set the current CImg exception mode. 01929 /** 01930 The way error messages are handled by CImg can be changed dynamically, using this function. 01931 Possible values are : 01932 - '0' to hide library messages (quiet mode). 01933 - '1' to print library messages on the console. 01934 - '2' to display library messages on a dialog window (default behavior). 01935 - '3' to do as '1' + add extra warnings (may slow down the code !). 01936 - '4' to do as '2' + add extra warnings (may slow down the code !). 01937 **/ 01938 inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) { 01939 static unsigned int mode = cimg_verbosity; 01940 if (is_set) mode = value; 01941 return mode; 01942 } 01943 inline unsigned int& exception_mode() { 01944 return _exception_mode(0,false); 01945 } 01946 inline unsigned int& exception_mode(const unsigned int mode) { 01947 return _exception_mode(mode,true); 01948 } 01949 01950 inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK", 01951 const char *const button2_label=0, const char *const button3_label=0, 01952 const char *const button4_label=0, const char *const button5_label=0, 01953 const char *const button6_label=0, const bool centering=false); 01954 01955 //! Evaluate math expression. 01956 inline double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0); 01957 } 01958 01959 /*---------------------------------------------- 01960 # 01961 # Definition of the CImgException structures 01962 # 01963 ----------------------------------------------*/ 01964 //! Instances of this class are thrown when errors occur during a %CImg library function call. 01965 /** 01966 \section ex1 Overview 01967 01968 CImgException is the base class of %CImg exceptions. 01969 Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call. 01970 CImgException is seldom thrown itself. Children classes that specify the kind of error encountered 01971 are generally used instead. These sub-classes are : 01972 01973 - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not 01974 correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example 01975 below will throw a \a CImgInstanceException. 01976 \code 01977 CImg<float> img; // Construct an empty image. 01978 img.blur(10); // Try to blur the image. 01979 \endcode 01980 01981 - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct. 01982 Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values. 01983 The example below will throw a \a CImgArgumentException. 01984 \code 01985 CImg<float> img(100,100,1,3); // Define a 100x100 color image with float pixels. 01986 img = 0; // Try to fill pixels from the 0 pointer (invalid argument to operator=() ). 01987 \endcode 01988 01989 - \b CImgIOException : Thrown when an error occured when trying to load or save image files. 01990 The example below will throw a \a CImgIOException. 01991 \code 01992 CImg<float> img("file_doesnt_exist.jpg"); // Try to load a file that doesn't exist. 01993 \endcode 01994 01995 - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window. 01996 This exception is thrown when image display request cannot be satisfied. 01997 01998 The parent class CImgException may be thrown itself when errors that cannot be classified in one of 01999 the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally 02000 reserved to %CImg Library functions. 02001 \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple 02002 subclasses of CImgException and are thus not detailled more in this reference documentation. 02003 02004 \section ex2 Exception handling 02005 02006 When an error occurs, the %CImg Library first displays the error in a modal window. 02007 Then, it throws an instance of the corresponding exception class, generally leading the program to stop 02008 (this is the default behavior). 02009 You can bypass this default behavior by handling the exceptions yourself, 02010 using a code block <tt>try { ... } catch () { ... }</tt>. 02011 In this case, you can avoid the apparition of the modal window, by 02012 defining the environment variable <tt>cimg_verbosity</tt> to 0 before including the %CImg header file. 02013 The example below shows how to cleanly handle %CImg Library exceptions : 02014 \code 02015 #define cimg_verbosity 0 // Disable modal window in CImg exceptions. 02016 #define "CImg.h" 02017 int main() { 02018 try { 02019 ...; // Here, do what you want. 02020 } 02021 catch (CImgInstanceException &e) { 02022 std::fprintf(stderr,"CImg Library Error : %s",e.what()); // Display your own error message 02023 ... // Do what you want now. 02024 } 02025 } 02026 \endcode 02027 **/ 02028 struct CImgException : public std::exception { 02029 #define _cimg_exception_err(etype,disp_flag) \ 02030 std::va_list ap; va_start(ap,format); std::vsprintf(_message,format,ap); va_end(ap); \ 02031 if (cimg::exception_mode()) { \ 02032 std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ 02033 if (cimg_display && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } catch (CImgException&) {} \ 02034 if (cimg::exception_mode()>=3) cimg_library::cimg::info(); \ 02035 } 02036 02037 char _message[16384]; 02038 CImgException() { *_message = 0; } 02039 CImgException(const char *const format, ...) { _cimg_exception_err("CImgException",true); } 02040 const char *what() const throw() { return _message; } 02041 }; 02042 02043 // The \ref CImgInstanceException class is used to throw an exception related 02044 // to a non suitable instance encountered in a library function call. 02045 struct CImgInstanceException : public CImgException { 02046 CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } 02047 }; 02048 02049 // The \ref CImgArgumentException class is used to throw an exception related 02050 // to invalid arguments encountered in a library function call. 02051 struct CImgArgumentException : public CImgException { 02052 CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); } 02053 }; 02054 02055 // The \ref CImgIOException class is used to throw an exception related 02056 // to Input/Output file problems encountered in a library function call. 02057 struct CImgIOException : public CImgException { 02058 CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); } 02059 }; 02060 02061 // The CImgDisplayException class is used to throw an exception related to display problems 02062 // encountered in a library function call. 02063 struct CImgDisplayException : public CImgException { 02064 CImgDisplayException(const char *const format, ...) { 02065 const unsigned int current_mode = cimg::exception_mode(); 02066 cimg::exception_mode(current_mode==2?1:current_mode==4?3:current_mode); 02067 _cimg_exception_err("CImgDisplayException",false); 02068 } 02069 }; 02070 02071 // The CImgWarningException class is used to throw an exception for warnings 02072 // encountered in a library function call. 02073 struct CImgWarningException : public CImgException { 02074 CImgWarningException(const char *const format, ...) { _cimg_exception_err("CImgWarningException",false); } 02075 }; 02076 02077 /*------------------------------------- 02078 # 02079 # Definition of the namespace 'cimg' 02080 # 02081 --------------------------------------*/ 02082 //! Namespace that encompasses \a low-level functions and variables of the %CImg Library. 02083 /** 02084 Most of the functions and variables within this namespace are used by the library for low-level processing. 02085 Nevertheless, documented variables and functions of this namespace may be used safely in your own source code. 02086 02087 \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the 02088 <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>. 02089 **/ 02090 namespace cimg { 02091 02092 // Define the traits that will be used to determine the best data type to work with. 02093 // 02094 template<typename T> struct type { 02095 static const char* string() { 02096 static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24", 02097 "unknown32", "unknown40", "unknown48", "unknown56", 02098 "unknown64", "unknown72", "unknown80", "unknown88", 02099 "unknown96", "unknown104", "unknown112", "unknown120", 02100 "unknown128" }; 02101 return s[(sizeof(T)<17)?sizeof(T):0]; 02102 } 02103 static bool is_float() { return false; } 02104 static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); } 02105 static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); } 02106 static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; } 02107 static const char* format() { return "%s"; } 02108 static const char* format(const T val) { static const char *const s = "unknown"; return s; } 02109 }; 02110 02111 template<> struct type<bool> { 02112 static const char* string() { static const char *const s = "bool"; return s; } 02113 static bool is_float() { return false; } 02114 static bool min() { return false; } 02115 static bool max() { return true; } 02116 static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; } 02117 static const char* format() { return "%s"; } 02118 static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; } 02119 }; 02120 02121 template<> struct type<unsigned char> { 02122 static const char* string() { static const char *const s = "unsigned char"; return s; } 02123 static bool is_float() { return false; } 02124 static unsigned char min() { return 0; } 02125 static unsigned char max() { return (unsigned char)~0U; } 02126 static unsigned char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } 02127 static const char* format() { return "%u"; } 02128 static unsigned int format(const unsigned char val) { return (unsigned int)val; } 02129 }; 02130 02131 template<> struct type<char> { 02132 static const char* string() { static const char *const s = "char"; return s; } 02133 static bool is_float() { return false; } 02134 static char min() { return (char)(-1L<<(8*sizeof(char)-1)); } 02135 static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); } 02136 static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; } 02137 static const char* format() { return "%d"; } 02138 static int format(const char val) { return (int)val; } 02139 }; 02140 02141 template<> struct type<signed char> { 02142 static const char* string() { static const char *const s = "signed char"; return s; } 02143 static bool is_float() { return false; } 02144 static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); } 02145 static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); } 02146 static signed char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(signed char)val; } 02147 static const char* format() { return "%d"; } 02148 static unsigned int format(const signed char val) { return (int)val; } 02149 }; 02150 02151 template<> struct type<unsigned short> { 02152 static const char* string() { static const char *const s = "unsigned short"; return s; } 02153 static bool is_float() { return false; } 02154 static unsigned short min() { return 0; } 02155 static unsigned short max() { return (unsigned short)~0U; } 02156 static unsigned short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; } 02157 static const char* format() { return "%u"; } 02158 static unsigned int format(const unsigned short val) { return (unsigned int)val; } 02159 }; 02160 02161 template<> struct type<short> { 02162 static const char* string() { static const char *const s = "short"; return s; } 02163 static bool is_float() { return false; } 02164 static short min() { return (short)(-1L<<(8*sizeof(short)-1)); } 02165 static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); } 02166 static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; } 02167 static const char* format() { return "%d"; } 02168 static int format(const short val) { return (int)val; } 02169 }; 02170 02171 template<> struct type<unsigned int> { 02172 static const char* string() { static const char *const s = "unsigned int"; return s; } 02173 static bool is_float() { return false; } 02174 static unsigned int min() { return 0; } 02175 static unsigned int max() { return (unsigned int)~0U; } 02176 static unsigned int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; } 02177 static const char* format() { return "%u"; } 02178 static unsigned int format(const unsigned int val) { return val; } 02179 }; 02180 02181 template<> struct type<int> { 02182 static const char* string() { static const char *const s = "int"; return s; } 02183 static bool is_float() { return false; } 02184 static int min() { return (int)(-1L<<(8*sizeof(int)-1)); } 02185 static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); } 02186 static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; } 02187 static const char* format() { return "%d"; } 02188 static int format(const int val) { return val; } 02189 }; 02190 02191 template<> struct type<unsigned long> { 02192 static const char* string() { static const char *const s = "unsigned long"; return s; } 02193 static bool is_float() { return false; } 02194 static unsigned long min() { return 0; } 02195 static unsigned long max() { return (unsigned long)~0UL; } 02196 static unsigned long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned long)val; } 02197 static const char* format() { return "%lu"; } 02198 static unsigned long format(const unsigned long val) { return val; } 02199 }; 02200 02201 template<> struct type<long> { 02202 static const char* string() { static const char *const s = "long"; return s; } 02203 static bool is_float() { return false; } 02204 static long min() { return (long)(-1L<<(8*sizeof(long)-1)); } 02205 static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); } 02206 static long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(long)val; } 02207 static const char* format() { return "%ld"; } 02208 static long format(const long val) { return val; } 02209 }; 02210 02211 template<> struct type<double> { 02212 static const char* string() { static const char *const s = "double"; return s; } 02213 static bool is_float() { return true; } 02214 static double min() { return -1.7E308; } 02215 static double max() { return 1.7E308; } 02216 static double cut(const double val) { return val<min()?min():val>max()?max():val; } 02217 static double inf() { return max()*max(); } 02218 static double nan() { static const double v_nan = std::sqrt(-1.0); return v_nan; } 02219 static const char* format() { return "%g"; } 02220 static double format(const double val) { return val; } 02221 }; 02222 02223 template<> struct type<float> { 02224 static const char* string() { static const char *const s = "float"; return s; } 02225 static bool is_float() { return true; } 02226 static float min() { return -3.4E38f; } 02227 static float max() { return 3.4E38f; } 02228 static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; } 02229 static float inf() { return (float)cimg::type<double>::inf(); } 02230 static float nan() { return (float)cimg::type<double>::nan(); } 02231 static const char* format() { return "%g"; } 02232 static double format(const float val) { return (double)val; } 02233 }; 02234 02235 template<typename T, typename t> struct superset { typedef T type; }; 02236 template<> struct superset<bool,unsigned char> { typedef unsigned char type; }; 02237 template<> struct superset<bool,char> { typedef char type; }; 02238 template<> struct superset<bool,signed char> { typedef signed char type; }; 02239 template<> struct superset<bool,unsigned short> { typedef unsigned short type; }; 02240 template<> struct superset<bool,short> { typedef short type; }; 02241 template<> struct superset<bool,unsigned int> { typedef unsigned int type; }; 02242 template<> struct superset<bool,int> { typedef int type; }; 02243 template<> struct superset<bool,unsigned long> { typedef unsigned long type; }; 02244 template<> struct superset<bool,long> { typedef long type; }; 02245 template<> struct superset<bool,float> { typedef float type; }; 02246 template<> struct superset<bool,double> { typedef double type; }; 02247 template<> struct superset<unsigned char,char> { typedef short type; }; 02248 template<> struct superset<unsigned char,signed char> { typedef short type; }; 02249 template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; }; 02250 template<> struct superset<unsigned char,short> { typedef short type; }; 02251 template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; }; 02252 template<> struct superset<unsigned char,int> { typedef int type; }; 02253 template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; }; 02254 template<> struct superset<unsigned char,long> { typedef long type; }; 02255 template<> struct superset<unsigned char,float> { typedef float type; }; 02256 template<> struct superset<unsigned char,double> { typedef double type; }; 02257 template<> struct superset<signed char,unsigned char> { typedef short type; }; 02258 template<> struct superset<signed char,char> { typedef short type; }; 02259 template<> struct superset<signed char,unsigned short> { typedef int type; }; 02260 template<> struct superset<signed char,short> { typedef short type; }; 02261 template<> struct superset<signed char,unsigned int> { typedef long type; }; 02262 template<> struct superset<signed char,int> { typedef int type; }; 02263 template<> struct superset<signed char,unsigned long> { typedef long type; }; 02264 template<> struct superset<signed char,long> { typedef long type; }; 02265 template<> struct superset<signed char,float> { typedef float type; }; 02266 template<> struct superset<signed char,double> { typedef double type; }; 02267 template<> struct superset<char,unsigned char> { typedef short type; }; 02268 template<> struct superset<char,signed char> { typedef short type; }; 02269 template<> struct superset<char,unsigned short> { typedef int type; }; 02270 template<> struct superset<char,short> { typedef short type; }; 02271 template<> struct superset<char,unsigned int> { typedef long type; }; 02272 template<> struct superset<char,int> { typedef int type; }; 02273 template<> struct superset<char,unsigned long> { typedef long type; }; 02274 template<> struct superset<char,long> { typedef long type; }; 02275 template<> struct superset<char,float> { typedef float type; }; 02276 template<> struct superset<char,double> { typedef double type; }; 02277 template<> struct superset<unsigned short,char> { typedef int type; }; 02278 template<> struct superset<unsigned short,signed char> { typedef int type; }; 02279 template<> struct superset<unsigned short,short> { typedef int type; }; 02280 template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; }; 02281 template<> struct superset<unsigned short,int> { typedef int type; }; 02282 template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; }; 02283 template<> struct superset<unsigned short,long> { typedef long type; }; 02284 template<> struct superset<unsigned short,float> { typedef float type; }; 02285 template<> struct superset<unsigned short,double> { typedef double type; }; 02286 template<> struct superset<short,unsigned short> { typedef int type; }; 02287 template<> struct superset<short,unsigned int> { typedef long type; }; 02288 template<> struct superset<short,int> { typedef int type; }; 02289 template<> struct superset<short,unsigned long> { typedef long type; }; 02290 template<> struct superset<short,long> { typedef long type; }; 02291 template<> struct superset<short,float> { typedef float type; }; 02292 template<> struct superset<short,double> { typedef double type; }; 02293 template<> struct superset<unsigned int,char> { typedef long type; }; 02294 template<> struct superset<unsigned int,signed char> { typedef long type; }; 02295 template<> struct superset<unsigned int,short> { typedef long type; }; 02296 template<> struct superset<unsigned int,int> { typedef long type; }; 02297 template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; }; 02298 template<> struct superset<unsigned int,long> { typedef long type; }; 02299 template<> struct superset<unsigned int,float> { typedef float type; }; 02300 template<> struct superset<unsigned int,double> { typedef double type; }; 02301 template<> struct superset<int,unsigned int> { typedef long type; }; 02302 template<> struct superset<int,unsigned long> { typedef long type; }; 02303 template<> struct superset<int,long> { typedef long type; }; 02304 template<> struct superset<int,float> { typedef float type; }; 02305 template<> struct superset<int,double> { typedef double type; }; 02306 template<> struct superset<unsigned long,char> { typedef long type; }; 02307 template<> struct superset<unsigned long,signed char> { typedef long type; }; 02308 template<> struct superset<unsigned long,short> { typedef long type; }; 02309 template<> struct superset<unsigned long,int> { typedef long type; }; 02310 template<> struct superset<unsigned long,long> { typedef long type; }; 02311 template<> struct superset<unsigned long,float> { typedef float type; }; 02312 template<> struct superset<unsigned long,double> { typedef double type; }; 02313 template<> struct superset<long,float> { typedef float type; }; 02314 template<> struct superset<long,double> { typedef double type; }; 02315 template<> struct superset<float,double> { typedef double type; }; 02316 02317 template<typename t1, typename t2, typename t3> struct superset2 { 02318 typedef typename superset<t1, typename superset<t2,t3>::type>::type type; 02319 }; 02320 02321 template<typename t1, typename t2, typename t3, typename t4> struct superset3 { 02322 typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type; 02323 }; 02324 02325 template<typename t1, typename t2> struct last { typedef t2 type; }; 02326 02327 #define _cimg_Tt typename cimg::superset<T,t>::type 02328 #define _cimg_Tfloat typename cimg::superset<T,float>::type 02329 #define _cimg_Ttfloat typename cimg::superset2<T,t,float>::type 02330 02331 // Define internal library variables. 02332 #if cimg_display==1 02333 struct X11_info { 02334 volatile unsigned int nb_wins; 02335 pthread_t* event_thread; 02336 CImgDisplay* wins[1024]; 02337 Display* display; 02338 unsigned int nb_bits; 02339 GC* gc; 02340 bool blue_first; 02341 bool byte_order; 02342 bool shm_enabled; 02343 #ifdef cimg_use_xrandr 02344 XRRScreenSize *resolutions; 02345 Rotation curr_rotation; 02346 unsigned int curr_resolution; 02347 unsigned int nb_resolutions; 02348 #endif 02349 X11_info():nb_wins(0),event_thread(0),display(0), 02350 nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) { 02351 #ifdef cimg_use_xrandr 02352 resolutions = 0; 02353 curr_rotation = 0; 02354 curr_resolution = nb_resolutions = 0; 02355 #endif 02356 } 02357 }; 02358 #if defined(cimg_module) 02359 X11_info& X11_attr(); 02360 #elif defined(cimg_main) 02361 X11_info& X11_attr() { static X11_info val; return val; } 02362 #else 02363 inline X11_info& X11_attr() { static X11_info val; return val; } 02364 #endif 02365 02366 #elif cimg_display==2 02367 struct Win32_info { 02368 HANDLE wait_event; 02369 Win32_info() { wait_event = CreateEvent(0,FALSE,FALSE,0); } 02370 }; 02371 #if defined(cimg_module) 02372 Win32_info& Win32_attr(); 02373 #elif defined(cimg_main) 02374 Win32_info& Win32_attr() { static Win32_info val; return val; } 02375 #else 02376 inline Win32_info& Win32_attr() { static Win32_info val; return val; } 02377 #endif 02378 #endif 02379 02380 #if cimg_display==1 02381 // Keycodes for X11-based graphical systems. 02382 const unsigned int keyESC = XK_Escape; 02383 const unsigned int keyF1 = XK_F1; 02384 const unsigned int keyF2 = XK_F2; 02385 const unsigned int keyF3 = XK_F3; 02386 const unsigned int keyF4 = XK_F4; 02387 const unsigned int keyF5 = XK_F5; 02388 const unsigned int keyF6 = XK_F6; 02389 const unsigned int keyF7 = XK_F7; 02390 const unsigned int keyF8 = XK_F8; 02391 const unsigned int keyF9 = XK_F9; 02392 const unsigned int keyF10 = XK_F10; 02393 const unsigned int keyF11 = XK_F11; 02394 const unsigned int keyF12 = XK_F12; 02395 const unsigned int keyPAUSE = XK_Pause; 02396 const unsigned int key1 = XK_1; 02397 const unsigned int key2 = XK_2; 02398 const unsigned int key3 = XK_3; 02399 const unsigned int key4 = XK_4; 02400 const unsigned int key5 = XK_5; 02401 const unsigned int key6 = XK_6; 02402 const unsigned int key7 = XK_7; 02403 const unsigned int key8 = XK_8; 02404 const unsigned int key9 = XK_9; 02405 const unsigned int key0 = XK_0; 02406 const unsigned int keyBACKSPACE = XK_BackSpace; 02407 const unsigned int keyINSERT = XK_Insert; 02408 const unsigned int keyHOME = XK_Home; 02409 const unsigned int keyPAGEUP = XK_Page_Up; 02410 const unsigned int keyTAB = XK_Tab; 02411 const unsigned int keyQ = XK_q; 02412 const unsigned int keyW = XK_w; 02413 const unsigned int keyE = XK_e; 02414 const unsigned int keyR = XK_r; 02415 const unsigned int keyT = XK_t; 02416 const unsigned int keyY = XK_y; 02417 const unsigned int keyU = XK_u; 02418 const unsigned int keyI = XK_i; 02419 const unsigned int keyO = XK_o; 02420 const unsigned int keyP = XK_p; 02421 const unsigned int keyDELETE = XK_Delete; 02422 const unsigned int keyEND = XK_End; 02423 const unsigned int keyPAGEDOWN = XK_Page_Down; 02424 const unsigned int keyCAPSLOCK = XK_Caps_Lock; 02425 const unsigned int keyA = XK_a; 02426 const unsigned int keyS = XK_s; 02427 const unsigned int keyD = XK_d; 02428 const unsigned int keyF = XK_f; 02429 const unsigned int keyG = XK_g; 02430 const unsigned int keyH = XK_h; 02431 const unsigned int keyJ = XK_j; 02432 const unsigned int keyK = XK_k; 02433 const unsigned int keyL = XK_l; 02434 const unsigned int keyENTER = XK_Return; 02435 const unsigned int keySHIFTLEFT = XK_Shift_L; 02436 const unsigned int keyZ = XK_z; 02437 const unsigned int keyX = XK_x; 02438 const unsigned int keyC = XK_c; 02439 const unsigned int keyV = XK_v; 02440 const unsigned int keyB = XK_b; 02441 const unsigned int keyN = XK_n; 02442 const unsigned int keyM = XK_m; 02443 const unsigned int keySHIFTRIGHT = XK_Shift_R; 02444 const unsigned int keyARROWUP = XK_Up; 02445 const unsigned int keyCTRLLEFT = XK_Control_L; 02446 const unsigned int keyAPPLEFT = XK_Super_L; 02447 const unsigned int keyALT = XK_Alt_L; 02448 const unsigned int keySPACE = XK_space; 02449 const unsigned int keyALTGR = XK_Alt_R; 02450 const unsigned int keyAPPRIGHT = XK_Super_R; 02451 const unsigned int keyMENU = XK_Menu; 02452 const unsigned int keyCTRLRIGHT = XK_Control_R; 02453 const unsigned int keyARROWLEFT = XK_Left; 02454 const unsigned int keyARROWDOWN = XK_Down; 02455 const unsigned int keyARROWRIGHT = XK_Right; 02456 const unsigned int keyPAD0 = XK_KP_0; 02457 const unsigned int keyPAD1 = XK_KP_1; 02458 const unsigned int keyPAD2 = XK_KP_2; 02459 const unsigned int keyPAD3 = XK_KP_3; 02460 const unsigned int keyPAD4 = XK_KP_4; 02461 const unsigned int keyPAD5 = XK_KP_5; 02462 const unsigned int keyPAD6 = XK_KP_6; 02463 const unsigned int keyPAD7 = XK_KP_7; 02464 const unsigned int keyPAD8 = XK_KP_8; 02465 const unsigned int keyPAD9 = XK_KP_9; 02466 const unsigned int keyPADADD = XK_KP_Add; 02467 const unsigned int keyPADSUB = XK_KP_Subtract; 02468 const unsigned int keyPADMUL = XK_KP_Multiply; 02469 const unsigned int keyPADDIV = XK_KP_Divide; 02470 02471 #elif cimg_display==2 02472 // Keycodes for Windows. 02473 const unsigned int keyESC = VK_ESCAPE; 02474 const unsigned int keyF1 = VK_F1; 02475 const unsigned int keyF2 = VK_F2; 02476 const unsigned int keyF3 = VK_F3; 02477 const unsigned int keyF4 = VK_F4; 02478 const unsigned int keyF5 = VK_F5; 02479 const unsigned int keyF6 = VK_F6; 02480 const unsigned int keyF7 = VK_F7; 02481 const unsigned int keyF8 = VK_F8; 02482 const unsigned int keyF9 = VK_F9; 02483 const unsigned int keyF10 = VK_F10; 02484 const unsigned int keyF11 = VK_F11; 02485 const unsigned int keyF12 = VK_F12; 02486 const unsigned int keyPAUSE = VK_PAUSE; 02487 const unsigned int key1 = '1'; 02488 const unsigned int key2 = '2'; 02489 const unsigned int key3 = '3'; 02490 const unsigned int key4 = '4'; 02491 const unsigned int key5 = '5'; 02492 const unsigned int key6 = '6'; 02493 const unsigned int key7 = '7'; 02494 const unsigned int key8 = '8'; 02495 const unsigned int key9 = '9'; 02496 const unsigned int key0 = '0'; 02497 const unsigned int keyBACKSPACE = VK_BACK; 02498 const unsigned int keyINSERT = VK_INSERT; 02499 const unsigned int keyHOME = VK_HOME; 02500 const unsigned int keyPAGEUP = VK_PRIOR; 02501 const unsigned int keyTAB = VK_TAB; 02502 const unsigned int keyQ = 'Q'; 02503 const unsigned int keyW = 'W'; 02504 const unsigned int keyE = 'E'; 02505 const unsigned int keyR = 'R'; 02506 const unsigned int keyT = 'T'; 02507 const unsigned int keyY = 'Y'; 02508 const unsigned int keyU = 'U'; 02509 const unsigned int keyI = 'I'; 02510 const unsigned int keyO = 'O'; 02511 const unsigned int keyP = 'P'; 02512 const unsigned int keyDELETE = VK_DELETE; 02513 const unsigned int keyEND = VK_END; 02514 const unsigned int keyPAGEDOWN = VK_NEXT; 02515 const unsigned int keyCAPSLOCK = VK_CAPITAL; 02516 const unsigned int keyA = 'A'; 02517 const unsigned int keyS = 'S'; 02518 const unsigned int keyD = 'D'; 02519 const unsigned int keyF = 'F'; 02520 const unsigned int keyG = 'G'; 02521 const unsigned int keyH = 'H'; 02522 const unsigned int keyJ = 'J'; 02523 const unsigned int keyK = 'K'; 02524 const unsigned int keyL = 'L'; 02525 const unsigned int keyENTER = VK_RETURN; 02526 const unsigned int keySHIFTLEFT = VK_SHIFT; 02527 const unsigned int keyZ = 'Z'; 02528 const unsigned int keyX = 'X'; 02529 const unsigned int keyC = 'C'; 02530 const unsigned int keyV = 'V'; 02531 const unsigned int keyB = 'B'; 02532 const unsigned int keyN = 'N'; 02533 const unsigned int keyM = 'M'; 02534 const unsigned int keySHIFTRIGHT = VK_SHIFT; 02535 const unsigned int keyARROWUP = VK_UP; 02536 const unsigned int keyCTRLLEFT = VK_CONTROL; 02537 const unsigned int keyAPPLEFT = VK_LWIN; 02538 const unsigned int keyALT = VK_LMENU; 02539 const unsigned int keySPACE = VK_SPACE; 02540 const unsigned int keyALTGR = VK_CONTROL; 02541 const unsigned int keyAPPRIGHT = VK_RWIN; 02542 const unsigned int keyMENU = VK_APPS; 02543 const unsigned int keyCTRLRIGHT = VK_CONTROL; 02544 const unsigned int keyARROWLEFT = VK_LEFT; 02545 const unsigned int keyARROWDOWN = VK_DOWN; 02546 const unsigned int keyARROWRIGHT = VK_RIGHT; 02547 const unsigned int keyPAD0 = 0x60; 02548 const unsigned int keyPAD1 = 0x61; 02549 const unsigned int keyPAD2 = 0x62; 02550 const unsigned int keyPAD3 = 0x63; 02551 const unsigned int keyPAD4 = 0x64; 02552 const unsigned int keyPAD5 = 0x65; 02553 const unsigned int keyPAD6 = 0x66; 02554 const unsigned int keyPAD7 = 0x67; 02555 const unsigned int keyPAD8 = 0x68; 02556 const unsigned int keyPAD9 = 0x69; 02557 const unsigned int keyPADADD = VK_ADD; 02558 const unsigned int keyPADSUB = VK_SUBTRACT; 02559 const unsigned int keyPADMUL = VK_MULTIPLY; 02560 const unsigned int keyPADDIV = VK_DIVIDE; 02561 02562 #else 02563 // Define unknow keycodes when no display are available. 02564 // (should rarely be used then !). 02565 const unsigned int keyESC = 1U; 02566 const unsigned int keyF1 = 2U; 02567 const unsigned int keyF2 = 3U; 02568 const unsigned int keyF3 = 4U; 02569 const unsigned int keyF4 = 5U; 02570 const unsigned int keyF5 = 6U; 02571 const unsigned int keyF6 = 7U; 02572 const unsigned int keyF7 = 8U; 02573 const unsigned int keyF8 = 9U; 02574 const unsigned int keyF9 = 10U; 02575 const unsigned int keyF10 = 11U; 02576 const unsigned int keyF11 = 12U; 02577 const unsigned int keyF12 = 13U; 02578 const unsigned int keyPAUSE = 14U; 02579 const unsigned int key1 = 15U; 02580 const unsigned int key2 = 16U; 02581 const unsigned int key3 = 17U; 02582 const unsigned int key4 = 18U; 02583 const unsigned int key5 = 19U; 02584 const unsigned int key6 = 20U; 02585 const unsigned int key7 = 21U; 02586 const unsigned int key8 = 22U; 02587 const unsigned int key9 = 23U; 02588 const unsigned int key0 = 24U; 02589 const unsigned int keyBACKSPACE = 25U; 02590 const unsigned int keyINSERT = 26U; 02591 const unsigned int keyHOME = 27U; 02592 const unsigned int keyPAGEUP = 28U; 02593 const unsigned int keyTAB = 29U; 02594 const unsigned int keyQ = 30U; 02595 const unsigned int keyW = 31U; 02596 const unsigned int keyE = 32U; 02597 const unsigned int keyR = 33U; 02598 const unsigned int keyT = 34U; 02599 const unsigned int keyY = 35U; 02600 const unsigned int keyU = 36U; 02601 const unsigned int keyI = 37U; 02602 const unsigned int keyO = 38U; 02603 const unsigned int keyP = 39U; 02604 const unsigned int keyDELETE = 40U; 02605 const unsigned int keyEND = 41U; 02606 const unsigned int keyPAGEDOWN = 42U; 02607 const unsigned int keyCAPSLOCK = 43U; 02608 const unsigned int keyA = 44U; 02609 const unsigned int keyS = 45U; 02610 const unsigned int keyD = 46U; 02611 const unsigned int keyF = 47U; 02612 const unsigned int keyG = 48U; 02613 const unsigned int keyH = 49U; 02614 const unsigned int keyJ = 50U; 02615 const unsigned int keyK = 51U; 02616 const unsigned int keyL = 52U; 02617 const unsigned int keyENTER = 53U; 02618 const unsigned int keySHIFTLEFT = 54U; 02619 const unsigned int keyZ = 55U; 02620 const unsigned int keyX = 56U; 02621 const unsigned int keyC = 57U; 02622 const unsigned int keyV = 58U; 02623 const unsigned int keyB = 59U; 02624 const unsigned int keyN = 60U; 02625 const unsigned int keyM = 61U; 02626 const unsigned int keySHIFTRIGHT = 62U; 02627 const unsigned int keyARROWUP = 63U; 02628 const unsigned int keyCTRLLEFT = 64U; 02629 const unsigned int keyAPPLEFT = 65U; 02630 const unsigned int keyALT = 66U; 02631 const unsigned int keySPACE = 67U; 02632 const unsigned int keyALTGR = 68U; 02633 const unsigned int keyAPPRIGHT = 69U; 02634 const unsigned int keyMENU = 70U; 02635 const unsigned int keyCTRLRIGHT = 71U; 02636 const unsigned int keyARROWLEFT = 72U; 02637 const unsigned int keyARROWDOWN = 73U; 02638 const unsigned int keyARROWRIGHT = 74U; 02639 const unsigned int keyPAD0 = 75U; 02640 const unsigned int keyPAD1 = 76U; 02641 const unsigned int keyPAD2 = 77U; 02642 const unsigned int keyPAD3 = 78U; 02643 const unsigned int keyPAD4 = 79U; 02644 const unsigned int keyPAD5 = 80U; 02645 const unsigned int keyPAD6 = 81U; 02646 const unsigned int keyPAD7 = 82U; 02647 const unsigned int keyPAD8 = 83U; 02648 const unsigned int keyPAD9 = 84U; 02649 const unsigned int keyPADADD = 85U; 02650 const unsigned int keyPADSUB = 86U; 02651 const unsigned int keyPADMUL = 87U; 02652 const unsigned int keyPADDIV = 88U; 02653 #endif 02654 02655 const double PI = 3.14159265358979323846; //!< Definition of the mathematical constant PI 02656 02657 // Definition of a 10x13 font (small size). 02658 const unsigned int font10x13[256*10*13/32] = { 02659 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02660 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0, 02661 0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02662 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02663 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120, 02664 0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02665 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02666 0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02667 0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001, 02668 0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801, 02669 0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0, 02670 0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0, 02671 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010, 02672 0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480, 02673 0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140, 02674 0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010, 02675 0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008, 02676 0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006, 02677 0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088, 02678 0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000, 02679 0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220, 02680 0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208, 02681 0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040, 02682 0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508, 02683 0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088, 02684 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018, 02685 0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220, 02686 0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02687 0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484, 02688 0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808, 02689 0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264, 02690 0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010, 02691 0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100, 02692 0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800, 02693 0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044, 02694 0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822, 02695 0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200, 02696 0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000, 02697 0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02698 0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8, 02699 0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008, 02700 0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000, 02701 0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220, 02702 0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402, 02703 0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980, 02704 0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421, 02705 0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0, 02706 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020, 02707 0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701, 02708 0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0, 02709 0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c, 02710 0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0, 02711 0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000, 02712 0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000, 02713 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0, 02714 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000, 02715 0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000, 02716 0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0, 02717 0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040 02718 }; 02719 02720 // Definition of a 12x24 font (normal size). 02721 const unsigned int font12x24[12*24*256/32] = { 02722 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02723 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0, 02724 0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c, 02725 0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02726 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02727 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0, 02728 0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003, 02729 0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02730 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02731 0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019, 02732 0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0, 02733 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02734 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000, 02735 0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000, 02736 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000, 02737 0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6, 02738 0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f, 02739 0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603, 02740 0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8, 02741 0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3, 02742 0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00, 02743 0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019, 02744 0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc, 02745 0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003, 02746 0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f, 02747 0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006, 02748 0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009, 02749 0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0, 02750 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018, 02751 0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00, 02752 0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000, 02753 0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000, 02754 0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3, 02755 0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980, 02756 0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000, 02757 0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60, 02758 0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600, 02759 0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f, 02760 0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600, 02761 0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0, 02762 0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000, 02763 0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606, 02764 0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6, 02765 0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f, 02766 0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001, 02767 0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061, 02768 0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6, 02769 0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000, 02770 0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660, 02771 0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d, 02772 0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180, 02773 0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020, 02774 0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660, 02775 0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060, 02776 0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000, 02777 0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006, 02778 0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06, 02779 0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090, 02780 0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006, 02781 0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066, 02782 0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183, 02783 0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044, 02784 0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001, 02785 0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003, 02786 0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1, 02787 0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f, 02788 0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660, 02789 0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60, 02790 0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000, 02791 0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001, 02792 0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003, 02793 0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603, 02794 0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00, 02795 0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066, 02796 0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, 02797 0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004, 02798 0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006, 02799 0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06, 02800 0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de, 02801 0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6, 02802 0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066, 02803 0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, 02804 0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000, 02805 0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006, 02806 0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06, 02807 0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc, 02808 0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000, 02809 0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8, 02810 0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000, 02811 0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000, 02812 0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e, 02813 0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c, 02814 0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000, 02815 0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140, 02816 0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060, 02817 0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0, 02818 0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030, 02819 0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60, 02820 0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c, 02821 0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000, 02822 0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240, 02823 0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0, 02824 0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71, 02825 0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300, 02826 0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8, 02827 0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8, 02828 0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0, 02829 0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000, 02830 0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000, 02831 0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83, 02832 0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000, 02833 0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6, 02834 0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6, 02835 0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0, 02836 0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0, 02837 0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f, 02838 0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c, 02839 0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0, 02840 0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0, 02841 0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6, 02842 0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02843 0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000, 02844 0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000, 02845 0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000, 02846 0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0, 02847 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0, 02848 0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000, 02849 0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0, 02850 0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02851 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0, 02852 0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02853 0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0, 02854 0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02855 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02856 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02857 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; 02858 02859 // Definition of a 16x32 font (large size). 02860 const unsigned int font16x32[16*32*256/32] = { 02861 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02862 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02863 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02864 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730, 02865 0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02866 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02867 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02868 0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02869 0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180, 02870 0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02871 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02872 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000, 02873 0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380, 02874 0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380, 02875 0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02876 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02877 0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0, 02878 0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000, 02879 0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070, 02880 0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02881 0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02882 0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c, 02883 0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000, 02884 0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02885 0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700, 02886 0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180, 02887 0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0, 02888 0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000, 02889 0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000, 02890 0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f, 02891 0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0, 02892 0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038, 02893 0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0, 02894 0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0, 02895 0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0, 02896 0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007, 02897 0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0, 02898 0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0, 02899 0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000, 02900 0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc, 02901 0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0, 02902 0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0, 02903 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0, 02904 0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0, 02905 0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000, 02906 0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0, 02907 0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e, 02908 0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0, 02909 0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038, 02910 0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0, 02911 0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300, 02912 0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08, 02913 0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380, 02914 0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0, 02915 0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c, 02916 0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00, 02917 0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838, 02918 0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0, 02919 0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0, 02920 0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000, 02921 0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0, 02922 0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0, 02923 0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0, 02924 0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000, 02925 0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000, 02926 0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000, 02927 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180, 02928 0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000, 02929 0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000, 02930 0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007, 02931 0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70, 02932 0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180, 02933 0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000, 02934 0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0, 02935 0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838, 02936 0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180, 02937 0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770, 02938 0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770, 02939 0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc, 02940 0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380, 02941 0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12, 02942 0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770, 02943 0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038, 02944 0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0, 02945 0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02946 0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380, 02947 0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00, 02948 0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c, 02949 0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400, 02950 0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe, 02951 0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770, 02952 0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038, 02953 0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78, 02954 0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 02955 0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0, 02956 0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c, 02957 0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0, 02958 0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8, 02959 0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0, 02960 0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0, 02961 0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c, 02962 0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c, 02963 0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0, 02964 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0, 02965 0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0, 02966 0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800, 02967 0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380, 02968 0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0, 02969 0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860, 02970 0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0, 02971 0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c, 02972 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70, 02973 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe, 02974 0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc, 02975 0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc, 02976 0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70, 02977 0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180, 02978 0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0, 02979 0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0, 02980 0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc, 02981 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70, 02982 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe, 02983 0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000, 02984 0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0, 02985 0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc, 02986 0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0, 02987 0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000, 02988 0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000, 02989 0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc, 02990 0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838, 02991 0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0, 02992 0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000, 02993 0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0, 02994 0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc, 02995 0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0, 02996 0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838, 02997 0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 02998 0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c, 02999 0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0, 03000 0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180, 03001 0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000, 03002 0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0, 03003 0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c, 03004 0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0, 03005 0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838, 03006 0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 03007 0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c, 03008 0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0, 03009 0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180, 03010 0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c, 03011 0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c, 03012 0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0, 03013 0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0, 03014 0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0, 03015 0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8, 03016 0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800, 03017 0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0, 03018 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000, 03019 0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000, 03020 0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0, 03021 0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78, 03022 0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000, 03023 0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838, 03024 0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 03025 0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c, 03026 0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0, 03027 0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180, 03028 0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18, 03029 0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380, 03030 0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78, 03031 0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0, 03032 0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000, 03033 0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000, 03034 0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c, 03035 0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78, 03036 0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000, 03037 0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8, 03038 0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380, 03039 0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8, 03040 0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380, 03041 0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe, 03042 0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc, 03043 0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc, 03044 0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8, 03045 0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180, 03046 0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8, 03047 0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0, 03048 0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38, 03049 0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000, 03050 0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000, 03051 0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078, 03052 0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0, 03053 0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0, 03054 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0, 03055 0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000, 03056 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03057 0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0, 03058 0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000, 03059 0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000, 03060 0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0, 03061 0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0, 03062 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000, 03063 0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0, 03064 0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000, 03065 0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0, 03066 0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000, 03067 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000, 03068 0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0, 03069 0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0, 03070 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03071 0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0, 03072 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000, 03073 0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03074 0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03075 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000, 03076 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03077 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03078 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03079 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03080 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0, 03081 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03082 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03083 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03084 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03085 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03086 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03087 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03088 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03089 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03090 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03091 0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; 03092 03093 // Definition of a 29x57 font (extra large size). 03094 const unsigned int font29x57[29*57*256/32] = { 03095 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03096 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03097 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03098 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03099 0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03100 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7, 03101 0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000, 03102 0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03103 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03104 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03105 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03106 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03107 0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00, 03108 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000, 03109 0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000, 03110 0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0, 03111 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03112 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03113 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03114 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03115 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0, 03116 0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03117 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f, 03118 0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00, 03119 0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03120 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03121 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03122 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03123 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03124 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0, 03125 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03126 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800, 03127 0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3, 03128 0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03129 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03130 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03131 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03132 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03133 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03134 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03135 0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e, 03136 0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0, 03137 0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03138 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03139 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03140 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03141 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03142 0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0, 03143 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003, 03144 0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0, 03145 0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000, 03146 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03147 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03148 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03149 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03150 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03151 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03152 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03153 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03154 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03155 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03156 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03157 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03158 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03159 0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0, 03160 0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03161 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0, 03162 0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0, 03163 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03164 0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03165 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000, 03166 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03167 0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0, 03168 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00, 03169 0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0, 03170 0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000, 03171 0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03172 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0, 03173 0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0, 03174 0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0, 03175 0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000, 03176 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0, 03177 0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000, 03178 0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000, 03179 0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000, 03180 0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800, 03181 0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3, 03182 0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03183 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0, 03184 0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000, 03185 0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80, 03186 0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0, 03187 0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000, 03188 0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000, 03189 0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000, 03190 0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f, 03191 0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000, 03192 0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc, 03193 0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00, 03194 0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e, 03195 0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000, 03196 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03197 0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe, 03198 0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000, 03199 0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff, 03200 0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00, 03201 0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0, 03202 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80, 03203 0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000, 03204 0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0, 03205 0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff, 03206 0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0, 03207 0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003, 03208 0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d, 03209 0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0, 03210 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, 03211 0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc, 03212 0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff, 03213 0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff, 03214 0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000, 03215 0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0, 03216 0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f, 03217 0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000, 03218 0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0, 03219 0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff, 03220 0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8, 03221 0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003, 03222 0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380, 03223 0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0, 03224 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000, 03225 0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80, 03226 0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff, 03227 0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c, 03228 0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000, 03229 0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80, 03230 0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0, 03231 0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00, 03232 0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000, 03233 0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe, 03234 0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800, 03235 0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f, 03236 0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700, 03237 0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03238 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f, 03239 0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007, 03240 0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007, 03241 0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f, 03242 0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0, 03243 0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000, 03244 0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000, 03245 0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000, 03246 0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000, 03247 0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 03248 0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007, 03249 0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003, 03250 0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000, 03251 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03252 0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000, 03253 0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007, 03254 0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00, 03255 0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1, 03256 0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0, 03257 0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0, 03258 0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c, 03259 0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000, 03260 0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000, 03261 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00, 03262 0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000, 03263 0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007, 03264 0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03265 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80, 03266 0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0, 03267 0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f, 03268 0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800, 03269 0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000, 03270 0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000, 03271 0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000, 03272 0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0, 03273 0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000, 03274 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00, 03275 0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03276 0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03277 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803, 03278 0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f, 03279 0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780, 03280 0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e, 03281 0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000, 03282 0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0, 03283 0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0, 03284 0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078, 03285 0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007, 03286 0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780, 03287 0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0, 03288 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000, 03289 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03290 0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e, 03291 0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003, 03292 0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800, 03293 0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001, 03294 0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc, 03295 0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000, 03296 0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03, 03297 0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0, 03298 0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000, 03299 0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, 03300 0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc, 03301 0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0, 03302 0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0, 03303 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000, 03304 0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780, 03305 0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0, 03306 0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000, 03307 0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f, 03308 0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff, 03309 0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000, 03310 0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0, 03311 0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c, 03312 0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0, 03313 0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000, 03314 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00, 03315 0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f, 03316 0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f, 03317 0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c, 03318 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, 03319 0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f, 03320 0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e, 03321 0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001, 03322 0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001, 03323 0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f, 03324 0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780, 03325 0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007, 03326 0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000, 03327 0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0, 03328 0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787, 03329 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f, 03330 0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001, 03331 0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f, 03332 0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001, 03333 0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03334 0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00, 03335 0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0, 03336 0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079, 03337 0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c, 03338 0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00, 03339 0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f, 03340 0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000, 03341 0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000, 03342 0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780, 03343 0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00, 03344 0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000, 03345 0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e, 03346 0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff, 03347 0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff, 03348 0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0, 03349 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, 03350 0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e, 03351 0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c, 03352 0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001, 03353 0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801, 03354 0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc, 03355 0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780, 03356 0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f, 03357 0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000, 03358 0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078, 03359 0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001, 03360 0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, 03361 0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8, 03362 0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0, 03363 0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007, 03364 0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03365 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00, 03366 0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0, 03367 0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007, 03368 0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807, 03369 0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c, 03370 0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000, 03371 0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18, 03372 0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0, 03373 0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe, 03374 0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078, 03375 0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000, 03376 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, 03377 0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008, 03378 0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0, 03379 0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003, 03380 0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03381 0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00, 03382 0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80, 03383 0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e, 03384 0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000, 03385 0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000, 03386 0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c, 03387 0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00, 03388 0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00, 03389 0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000, 03390 0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00, 03391 0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000, 03392 0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00, 03393 0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c, 03394 0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00, 03395 0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03396 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0, 03397 0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078, 03398 0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000, 03399 0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0, 03400 0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c, 03401 0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000, 03402 0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0, 03403 0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e, 03404 0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c, 03405 0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0, 03406 0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e, 03407 0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0, 03408 0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007, 03409 0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000, 03410 0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800, 03411 0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03412 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1, 03413 0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff, 03414 0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000, 03415 0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000, 03416 0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000, 03417 0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000, 03418 0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003, 03419 0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce, 03420 0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00, 03421 0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f, 03422 0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0, 03423 0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e, 03424 0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800, 03425 0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0, 03426 0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03427 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007, 03428 0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00, 03429 0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff, 03430 0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0, 03431 0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0, 03432 0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00, 03433 0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000, 03434 0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000, 03435 0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f, 03436 0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0, 03437 0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007, 03438 0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8, 03439 0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0, 03440 0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000, 03441 0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00, 03442 0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03443 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80, 03444 0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0, 03445 0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e, 03446 0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c, 03447 0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f, 03448 0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c, 03449 0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003, 03450 0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000, 03451 0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303, 03452 0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc, 03453 0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000, 03454 0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780, 03455 0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000, 03456 0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078, 03457 0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0, 03458 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007, 03459 0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00, 03460 0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f, 03461 0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0, 03462 0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c, 03463 0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000, 03464 0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000, 03465 0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000, 03466 0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800, 03467 0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0, 03468 0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000, 03469 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, 03470 0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003, 03471 0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00, 03472 0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f, 03473 0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03474 0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3, 03475 0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070, 03476 0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0, 03477 0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0, 03478 0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e, 03479 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0, 03480 0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000, 03481 0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80, 03482 0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303, 03483 0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00, 03484 0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 03485 0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000, 03486 0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe, 03487 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07, 03488 0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03489 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f, 03490 0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f, 03491 0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007, 03492 0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800, 03493 0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007, 03494 0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003, 03495 0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0, 03496 0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00, 03497 0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00, 03498 0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000, 03499 0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000, 03500 0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c, 03501 0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01, 03502 0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000, 03503 0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800, 03504 0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03505 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000, 03506 0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070, 03507 0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0, 03508 0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0, 03509 0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e, 03510 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0, 03511 0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff, 03512 0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001, 03513 0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000, 03514 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801, 03515 0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 03516 0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000, 03517 0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe, 03518 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, 03519 0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03520 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000, 03521 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000, 03522 0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800, 03523 0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000, 03524 0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, 03525 0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800, 03526 0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0, 03527 0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078, 03528 0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000, 03529 0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0, 03530 0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000, 03531 0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0, 03532 0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000, 03533 0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078, 03534 0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0, 03535 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001, 03536 0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e, 03537 0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007, 03538 0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001, 03539 0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007, 03540 0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000, 03541 0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003, 03542 0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff, 03543 0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00, 03544 0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80, 03545 0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000, 03546 0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00, 03547 0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000, 03548 0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, 03549 0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03550 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000, 03551 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000, 03552 0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800, 03553 0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001, 03554 0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, 03555 0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003, 03556 0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001, 03557 0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800, 03558 0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000, 03559 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03, 03560 0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 03561 0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000, 03562 0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000, 03563 0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c, 03564 0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03565 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00, 03566 0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff, 03567 0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e, 03568 0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c, 03569 0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f, 03570 0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e, 03571 0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f, 03572 0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000, 03573 0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0, 03574 0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807, 03575 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f, 03576 0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80, 03577 0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000, 03578 0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800, 03579 0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03580 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00, 03581 0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03, 03582 0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800, 03583 0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, 03584 0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, 03585 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000, 03586 0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff, 03587 0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c, 03588 0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81, 03589 0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000, 03590 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0, 03591 0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c, 03592 0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00, 03593 0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f, 03594 0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03595 0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e, 03596 0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03, 03597 0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780, 03598 0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, 03599 0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, 03600 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000, 03601 0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f, 03602 0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000, 03603 0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00, 03604 0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, 03605 0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f, 03606 0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07, 03607 0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00, 03608 0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0, 03609 0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03610 0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, 03611 0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000, 03612 0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e, 03613 0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf, 03614 0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f, 03615 0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e, 03616 0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000, 03617 0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000, 03618 0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0, 03619 0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, 03620 0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e, 03621 0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80, 03622 0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000, 03623 0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00, 03624 0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03625 0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, 03626 0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000, 03627 0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e, 03628 0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf, 03629 0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f, 03630 0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e, 03631 0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000, 03632 0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0, 03633 0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0, 03634 0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00, 03635 0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007, 03636 0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c, 03637 0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000, 03638 0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0, 03639 0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03640 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0, 03641 0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007, 03642 0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0, 03643 0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f, 03644 0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007, 03645 0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000, 03646 0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018, 03647 0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0, 03648 0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00, 03649 0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070, 03650 0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003, 03651 0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8, 03652 0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80, 03653 0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0, 03654 0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0, 03655 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f, 03656 0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780, 03657 0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff, 03658 0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000, 03659 0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000, 03660 0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff, 03661 0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000, 03662 0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f, 03663 0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000, 03664 0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1, 03665 0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0, 03666 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f, 03667 0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff, 03668 0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8, 03669 0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0, 03670 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f, 03671 0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780, 03672 0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff, 03673 0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000, 03674 0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000, 03675 0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff, 03676 0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000, 03677 0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007, 03678 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7, 03679 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381, 03680 0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0, 03681 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f, 03682 0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3, 03683 0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0, 03684 0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0, 03685 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003, 03686 0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780, 03687 0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff, 03688 0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000, 03689 0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000, 03690 0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff, 03691 0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000, 03692 0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002, 03693 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7, 03694 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff, 03695 0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0, 03696 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007, 03697 0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1, 03698 0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0, 03699 0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0, 03700 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000, 03701 0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000, 03702 0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000, 03703 0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000, 03704 0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e, 03705 0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03706 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0, 03707 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0, 03708 0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f, 03709 0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800, 03710 0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0, 03711 0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03712 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03713 0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0, 03714 0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000, 03715 0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0, 03716 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000, 03717 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0, 03718 0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03719 0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0, 03720 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000, 03721 0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000, 03722 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0, 03723 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000, 03724 0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03725 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03726 0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03727 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03728 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03729 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000, 03730 0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03731 0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000, 03732 0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0, 03733 0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03734 0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000, 03735 0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03736 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03737 0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03738 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03739 0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000, 03740 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0, 03741 0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0, 03742 0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000, 03743 0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff, 03744 0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03745 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000, 03746 0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03747 0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0, 03748 0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f, 03749 0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, 03750 0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03751 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0, 03752 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f, 03753 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0, 03754 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03755 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0, 03756 0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0, 03757 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0, 03758 0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0, 03759 0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03760 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0, 03761 0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03762 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03763 0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03764 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03765 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03766 0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, 03767 0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03768 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03769 0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0, 03770 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0, 03771 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03772 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03773 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03774 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0, 03775 0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0, 03776 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03777 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0, 03778 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0, 03779 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03780 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03781 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03782 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000, 03783 0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0, 03784 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03785 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03786 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03787 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03788 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03789 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03790 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03791 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03792 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03793 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03794 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03795 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03796 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03797 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03798 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0, 03799 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03800 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03801 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 03802 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; 03803 03804 // Definition of a 40x38 'danger' color logo. 03805 const unsigned char logo40x38[4576] = { 03806 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, 03807 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, 03808 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, 03809 1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0, 03810 2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255, 03811 255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189, 03812 189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189, 03813 189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123, 03814 22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200, 03815 1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0, 03816 0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1, 03817 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189, 03818 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255, 03819 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189, 03820 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255, 03821 0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123, 03822 123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189, 03823 189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255, 03824 0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189, 03825 189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1, 03826 0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255, 03827 255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123, 03828 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,123,123,123,86, 03829 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0}; 03830 03831 //! Set/get output stream for CImg library messages. 03832 inline std::FILE* output(std::FILE *file) { 03833 static std::FILE *res = stderr; 03834 if (file) res = file; 03835 return res; 03836 } 03837 03838 //! Display a warning message. 03839 /** 03840 \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>. 03841 **/ 03842 inline void warn(const char *const format, ...) { 03843 if (cimg::exception_mode()>=1) { 03844 char message[8192] = { 0 }; 03845 std::va_list ap; 03846 va_start(ap,format); 03847 std::vsprintf(message,format,ap); 03848 va_end(ap); 03849 #ifdef cimg_strict_warnings 03850 throw CImgWarningException(message); 03851 #else 03852 std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s %s",cimg::t_red,cimg::t_normal,message); 03853 #endif 03854 } 03855 } 03856 03857 // Execute an external system command. 03858 /** 03859 \note This function is similar to <tt>std::system()</tt> 03860 and is here because using the <tt>std::</tt> version on 03861 Windows may open undesired consoles. 03862 **/ 03863 inline int system(const char *const command, const char *const module_name=0) { 03864 #if cimg_OS==2 03865 PROCESS_INFORMATION pi; 03866 STARTUPINFO si; 03867 std::memset(&pi,0,sizeof(PROCESS_INFORMATION)); 03868 std::memset(&si,0,sizeof(STARTUPINFO)); 03869 GetStartupInfo(&si); 03870 si.cb = sizeof(si); 03871 si.wShowWindow = SW_HIDE; 03872 si.dwFlags |= SW_HIDE; 03873 const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi); 03874 if (res) { 03875 WaitForSingleObject(pi.hProcess, INFINITE); 03876 CloseHandle(pi.hThread); 03877 CloseHandle(pi.hProcess); 03878 return 0; 03879 } else 03880 #endif 03881 return std::system(command); 03882 return module_name?0:1; 03883 } 03884 03885 //! Return a reference to a temporary variable of type T. 03886 template<typename T> 03887 inline T& temporary(const T&) { 03888 static T temp; 03889 return temp; 03890 } 03891 03892 //! Exchange values of variables \p a and \p b. 03893 template<typename T> 03894 inline void swap(T& a, T& b) { T t = a; a = b; b = t; } 03895 03896 //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2). 03897 template<typename T1, typename T2> 03898 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) { 03899 cimg::swap(a1,b1); cimg::swap(a2,b2); 03900 } 03901 03902 //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3). 03903 template<typename T1, typename T2, typename T3> 03904 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) { 03905 cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); 03906 } 03907 03908 //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4). 03909 template<typename T1, typename T2, typename T3, typename T4> 03910 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) { 03911 cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); 03912 } 03913 03914 //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5). 03915 template<typename T1, typename T2, typename T3, typename T4, typename T5> 03916 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) { 03917 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); 03918 } 03919 03920 //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6). 03921 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> 03922 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) { 03923 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6); 03924 } 03925 03926 //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7). 03927 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> 03928 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, 03929 T7& a7, T7& b7) { 03930 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7); 03931 } 03932 03933 //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8). 03934 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> 03935 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, 03936 T7& a7, T7& b7, T8& a8, T8& b8) { 03937 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8); 03938 } 03939 03940 //! Return the current endianness of the CPU. 03941 /** 03942 \return \c false for "Little Endian", \c true for "Big Endian". 03943 **/ 03944 inline bool endianness() { 03945 const int x = 1; 03946 return ((unsigned char*)&x)[0]?false:true; 03947 } 03948 03949 //! Invert endianness of a memory buffer. 03950 template<typename T> 03951 inline void invert_endianness(T* const buffer, const unsigned int size) { 03952 if (size) switch (sizeof(T)) { 03953 case 1 : break; 03954 case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) { 03955 const unsigned short val = *(--ptr); 03956 *ptr = (unsigned short)((val>>8)|((val<<8))); 03957 } 03958 } break; 03959 case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) { 03960 const unsigned int val = *(--ptr); 03961 *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24); 03962 } 03963 } break; 03964 default : { for (T* ptr = buffer+size; ptr>buffer; ) { 03965 unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T); 03966 for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe)); 03967 } 03968 } 03969 } 03970 } 03971 03972 //! Invert endianness of a single variable. 03973 template<typename T> 03974 inline T& invert_endianness(T& a) { 03975 invert_endianness(&a,1); 03976 return a; 03977 } 03978 03979 //! Get the value of a system timer with a millisecond precision. 03980 inline unsigned long time() { 03981 #if cimg_OS==1 03982 struct timeval st_time; 03983 gettimeofday(&st_time,0); 03984 return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000); 03985 #elif cimg_OS==2 03986 static SYSTEMTIME st_time; 03987 GetSystemTime(&st_time); 03988 return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour))); 03989 #else 03990 return 0; 03991 #endif 03992 } 03993 03994 //! Sleep for a certain numbers of milliseconds. 03995 /** 03996 This function frees the CPU ressources during the sleeping time. 03997 It may be used to temporize your program properly, without wasting CPU time. 03998 **/ 03999 inline void sleep(const unsigned int milliseconds) { 04000 #if cimg_OS==1 04001 struct timespec tv; 04002 tv.tv_sec = milliseconds/1000; 04003 tv.tv_nsec = (milliseconds%1000)*1000000; 04004 nanosleep(&tv,0); 04005 #elif cimg_OS==2 04006 Sleep(milliseconds); 04007 #endif 04008 } 04009 04010 inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) { 04011 if (!timer) timer = cimg::time(); 04012 const unsigned long current_time = cimg::time(); 04013 if (current_time>=timer+milliseconds) { timer = current_time; return 0; } 04014 const unsigned long time_diff = timer + milliseconds - current_time; 04015 timer = current_time + time_diff; 04016 cimg::sleep(time_diff); 04017 return (unsigned int)time_diff; 04018 } 04019 04020 //! Wait for a certain number of milliseconds since the last call. 04021 /** 04022 This function is equivalent to sleep() but the waiting time is computed with regard to the last call 04023 of wait(). It may be used to temporize your program properly. 04024 **/ 04025 inline unsigned int wait(const unsigned int milliseconds) { 04026 static unsigned long timer = 0; 04027 if (!timer) timer = cimg::time(); 04028 return _sleep(milliseconds,timer); 04029 } 04030 04031 // Use a specific srand initialization to avoid multi-threads to have to the 04032 // same series of random numbers (executed only once for a single program). 04033 inline void srand() { 04034 static bool first_time = true; 04035 if (first_time) { 04036 std::srand(cimg::time()); 04037 unsigned char *const rand_ptr = new unsigned char[1+std::rand()%2048]; 04038 std::srand((unsigned int)std::rand() + *(unsigned int*)(void*)rand_ptr); 04039 delete[] rand_ptr; 04040 first_time = false; 04041 } 04042 } 04043 04044 //! Return a left bitwise-rotated number. 04045 template<typename T> 04046 inline T rol(const T a, const unsigned int n=1) { 04047 return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a; 04048 } 04049 04050 inline float rol(const float a, const unsigned int n=1) { 04051 return (float)rol((int)a,n); 04052 } 04053 04054 inline double rol(const double a, const unsigned int n=1) { 04055 return (double)rol((long)a,n); 04056 } 04057 04058 //! Return a right bitwise-rotated number. 04059 template<typename T> 04060 inline T ror(const T a, const unsigned int n=1) { 04061 return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a; 04062 } 04063 04064 inline float ror(const float a, const unsigned int n=1) { 04065 return (float)ror((int)a,n); 04066 } 04067 04068 inline double ror(const double a, const unsigned int n=1) { 04069 return (double)ror((long)a,n); 04070 } 04071 04072 //! Return the absolute value of a number. 04073 /** 04074 \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt> 04075 because it is able to consider a variable of any type, without cast needed. 04076 **/ 04077 template<typename T> 04078 inline T abs(const T a) { 04079 return a>=0?a:-a; 04080 } 04081 inline bool abs(const bool a) { 04082 return a; 04083 } 04084 inline unsigned char abs(const unsigned char a) { 04085 return a; 04086 } 04087 inline unsigned short abs(const unsigned short a) { 04088 return a; 04089 } 04090 inline unsigned int abs(const unsigned int a) { 04091 return a; 04092 } 04093 inline unsigned long abs(const unsigned long a) { 04094 return a; 04095 } 04096 inline double abs(const double a) { 04097 return std::fabs(a); 04098 } 04099 inline float abs(const float a) { 04100 return (float)std::fabs((double)a); 04101 } 04102 inline int abs(const int a) { 04103 return std::abs(a); 04104 } 04105 04106 //! Return the square of a number. 04107 template<typename T> 04108 inline T sqr(const T val) { 04109 return val*val; 04110 } 04111 04112 //! Return 1 + log_10(x). 04113 inline int xln(const int x) { 04114 return x>0?(int)(1+std::log10((double)x)):1; 04115 } 04116 04117 //! Return the minimum value between two numbers. 04118 template<typename t1, typename t2> 04119 inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) { 04120 typedef typename cimg::superset<t1,t2>::type t1t2; 04121 return (t1t2)(a<=b?a:b); 04122 } 04123 04124 //! Return the minimum value between three numbers. 04125 template<typename t1, typename t2, typename t3> 04126 inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) { 04127 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3; 04128 return (t1t2t3)cimg::min(cimg::min(a,b),c); 04129 } 04130 04131 //! Return the minimum value between four numbers. 04132 template<typename t1, typename t2, typename t3, typename t4> 04133 inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) { 04134 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4; 04135 return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d); 04136 } 04137 04138 //! Return the maximum value between two numbers. 04139 template<typename t1, typename t2> 04140 inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) { 04141 typedef typename cimg::superset<t1,t2>::type t1t2; 04142 return (t1t2)(a>=b?a:b); 04143 } 04144 04145 //! Return the maximum value between three numbers. 04146 template<typename t1, typename t2, typename t3> 04147 inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) { 04148 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3; 04149 return (t1t2t3)cimg::max(cimg::max(a,b),c); 04150 } 04151 04152 //! Return the maximum value between four numbers. 04153 template<typename t1, typename t2, typename t3, typename t4> 04154 inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) { 04155 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4; 04156 return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d); 04157 } 04158 04159 //! Return the sign of a number. 04160 template<typename T> 04161 inline T sign(const T x) { 04162 return (x<0)?(T)(-1):(x==0?(T)0:(T)1); 04163 } 04164 04165 //! Return the nearest power of 2 higher than a given number. 04166 template<typename T> 04167 inline unsigned int nearest_pow2(const T x) { 04168 unsigned int i = 1; 04169 while (x>i) i<<=1; 04170 return i; 04171 } 04172 04173 //! Return the sinc() of a given number. 04174 inline double sinc(const double x) { 04175 return x?std::sin(x)/x:1; 04176 } 04177 04178 //! Return the modulo of a number. 04179 /** 04180 \note This modulo function accepts negative and floating-points modulo numbers, as well as 04181 variable of any type. 04182 **/ 04183 template<typename T> 04184 inline T mod(const T& x, const T& m) { 04185 const double dx = (double)x, dm = (double)m; 04186 if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); } 04187 return (T)(dx-dm*std::floor(dx/dm)); 04188 } 04189 inline int mod(const bool x, const bool m) { 04190 return m?(x?1:0):0; 04191 } 04192 inline int mod(const char x, const char m) { 04193 return x>=0?x%m:(x%m?m+x%m:0); 04194 } 04195 inline int mod(const short x, const short m) { 04196 return x>=0?x%m:(x%m?m+x%m:0); 04197 } 04198 inline int mod(const int x, const int m) { 04199 return x>=0?x%m:(x%m?m+x%m:0); 04200 } 04201 inline int mod(const long x, const long m) { 04202 return x>=0?x%m:(x%m?m+x%m:0); 04203 } 04204 inline int mod(const unsigned char x, const unsigned char m) { 04205 return x%m; 04206 } 04207 inline int mod(const unsigned short x, const unsigned short m) { 04208 return x%m; 04209 } 04210 inline int mod(const unsigned int x, const unsigned int m) { 04211 return x%m; 04212 } 04213 inline int mod(const unsigned long x, const unsigned long m) { 04214 return x%m; 04215 } 04216 04217 //! Return the minmod of two numbers. 04218 /** 04219 <i>minmod(\p a,\p b)</i> is defined to be : 04220 - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign. 04221 - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs. 04222 **/ 04223 template<typename T> 04224 inline T minmod(const T a, const T b) { 04225 return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a)); 04226 } 04227 04228 //! Return a random variable between [0,1] with respect to an uniform distribution. 04229 inline double rand() { 04230 static bool first_time = true; 04231 if (first_time) { cimg::srand(); first_time = false; } 04232 return (double)std::rand()/RAND_MAX; 04233 } 04234 04235 //! Return a random variable between [-1,1] with respect to an uniform distribution. 04236 inline double crand() { 04237 return 1-2*cimg::rand(); 04238 } 04239 04240 //! Return a random variable following a gaussian distribution and a standard deviation of 1. 04241 inline double grand() { 04242 double x1, w; 04243 do { 04244 const double x2 = 2*cimg::rand() - 1.0; 04245 x1 = 2*cimg::rand()-1.0; 04246 w = x1*x1 + x2*x2; 04247 } while (w<=0 || w>=1.0); 04248 return x1*std::sqrt((-2*std::log(w))/w); 04249 } 04250 04251 //! Return a random variable following a Poisson distribution of parameter z. 04252 inline unsigned int prand(const double z) { 04253 if (z<=1.0e-10) return 0; 04254 if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z); 04255 unsigned int k = 0; 04256 const double y = std::exp(-z); 04257 for (double s = 1.0; s>=y; ++k) s*=cimg::rand(); 04258 return k-1; 04259 } 04260 04261 //! Return a rounded number. 04262 /** 04263 \param x is the number to be rounded. 04264 \param y is the rounding precision. 04265 \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward). 04266 **/ 04267 inline double round(const double x, const double y, const int rounding_type=0) { 04268 if (y<=0) return x; 04269 const double delta = cimg::mod(x,y); 04270 if (delta==0.0) return x; 04271 const double 04272 backward = x - delta, 04273 forward = backward + y; 04274 return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward)); 04275 } 04276 04277 inline double _pythagore(double a, double b) { 04278 const double absa = cimg::abs(a), absb = cimg::abs(b); 04279 if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); } 04280 else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); } 04281 } 04282 04283 //! Remove the 'case' of an ASCII character. 04284 inline char uncase(const char x) { 04285 return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); 04286 } 04287 04288 //! Remove the 'case' of a C string. 04289 /** 04290 Acts in-place. 04291 **/ 04292 inline void uncase(char *const string) { 04293 if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr); 04294 } 04295 04296 //! Read a double number from a C-string. 04297 /** 04298 \note This function is quite similar to <tt>std::atof()</tt>, 04299 but that it allows the retrieval of fractions as in "1/2". 04300 **/ 04301 inline double atof(const char *const str) { 04302 double x = 0, y = 1; 04303 if (!str) return 0; else { std::sscanf(str,"%lf/%lf",&x,&y); return x/y; } 04304 } 04305 04306 //! Compare the first \p n characters of two C-strings, ignoring the case. 04307 /** 04308 \note This function is defined since it is not provided by all compilers 04309 (not an ANSI function). 04310 **/ 04311 inline int strncasecmp(const char *const s1, const char *const s2, const int l) { 04312 if (!l) return 0; 04313 if (!s1) return s2?-1:0; 04314 const char *ns1 = s1, *ns2 = s2; 04315 int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; } 04316 return k!=l?diff:0; 04317 } 04318 04319 //! Compare two C-strings, ignoring the case. 04320 /** 04321 \note This function is defined since it is not provided by all compilers 04322 (not an ANSI function). 04323 **/ 04324 inline int strcasecmp(const char *const s1, const char *const s2) { 04325 if (!s1) return s2?-1:0; 04326 const unsigned int l1 = std::strlen(s1), l2 = std::strlen(s2); 04327 return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2)); 04328 } 04329 04330 //! Remove useless delimiters on the borders of a C-string 04331 inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false, const bool is_iterative=false) { 04332 if (!s) return false; 04333 const int l = (int)std::strlen(s); 04334 int p, q; 04335 if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ) { --q; ++p; if (!is_iterative) break; } 04336 else { 04337 for (p = 0; p<l && s[p]==delimiter; ) { ++p; if (!is_iterative) break; } 04338 for (q = l-1; q>p && s[q]==delimiter; ) { --q; if (!is_iterative) break; } 04339 } 04340 const int n = q - p + 1; 04341 if (n!=l) { std::memmove(s,s+p,n); s[n] = 0; return true; } 04342 return false; 04343 } 04344 04345 //! Replace explicit escape sequences '\x' in C-strings. 04346 inline void strescape(char *const s) { 04347 #define cimg_strescape(ci,co) case ci: *nd = co; ++ns; break; 04348 static unsigned int val = 0; 04349 for (char *ns = s, *nd = s; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) { 04350 cimg_strescape('n','\n'); 04351 cimg_strescape('t','\t'); 04352 cimg_strescape('v','\v'); 04353 cimg_strescape('b','\b'); 04354 cimg_strescape('r','\r'); 04355 cimg_strescape('f','\f'); 04356 cimg_strescape('a','\a'); 04357 cimg_strescape('\\','\\'); 04358 cimg_strescape('\?','\?'); 04359 cimg_strescape('\'','\''); 04360 cimg_strescape('\"','\"'); 04361 case 0 : *nd = 0; break; 04362 case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : 04363 std::sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns; 04364 *nd = val; break; 04365 case 'x': 04366 std::sscanf(++ns,"%x",&val); while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; 04367 *nd = val; break; 04368 default : *nd = *(ns++); 04369 } else *nd = *(ns++); 04370 } 04371 04372 //! Compute the basename of a filename. 04373 inline const char* basename(const char *const s) { 04374 const char *p = 0; 04375 for (const char *np = s; np>=s && (p=np); np = std::strchr(np,cimg_file_separator)+1) {} 04376 return p; 04377 } 04378 04379 // Generate a random filename. 04380 inline const char* filenamerand() { 04381 static char randomid[9] = { 0,0,0,0,0,0,0,0,0 }; 04382 cimg::srand(); 04383 for (unsigned int k = 0; k<8; ++k) { 04384 const int v = (int)std::rand()%3; 04385 randomid[k] = (char)(v==0?('0'+(std::rand()%10)):(v==1?('a'+(std::rand()%26)):('A'+(std::rand()%26)))); 04386 } 04387 return randomid; 04388 } 04389 04390 // Convert filename into a Windows-style filename. 04391 inline void winformat_string(char *const s) { 04392 if (s && s[0]) { 04393 #if cimg_OS==2 04394 char *const ns = new char[MAX_PATH]; 04395 if (GetShortPathNameA(s,ns,MAX_PATH)) std::strcpy(s,ns); 04396 #endif 04397 } 04398 } 04399 04400 //! Return or set path to store temporary files. 04401 inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) { 04402 #define _cimg_test_temporary_path(p) \ 04403 if (!path_found) { \ 04404 std::sprintf(st_path,"%s",p); \ 04405 std::sprintf(tmp,"%s%c%s",st_path,cimg_file_separator,filetmp); \ 04406 if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } \ 04407 } 04408 static char *st_path = 0; 04409 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04410 if (user_path) { 04411 if (!st_path) st_path = new char[1024]; 04412 std::memset(st_path,0,1024); 04413 std::strncpy(st_path,user_path,1023); 04414 } else if (!st_path) { 04415 st_path = new char[1024]; 04416 std::memset(st_path,0,1024); 04417 bool path_found = false; 04418 char tmp[1024] = { 0 }, filetmp[512] = { 0 }; 04419 std::FILE *file = 0; 04420 std::sprintf(filetmp,"%s.tmp",cimg::filenamerand()); 04421 char *tmpPath = getenv("TMP"); 04422 if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); } 04423 if (tmpPath) _cimg_test_temporary_path(tmpPath); 04424 #if cimg_OS==2 04425 _cimg_test_temporary_path("C:\\WINNT\\Temp"); 04426 _cimg_test_temporary_path("C:\\WINDOWS\\Temp"); 04427 _cimg_test_temporary_path("C:\\Temp"); 04428 _cimg_test_temporary_path("C:"); 04429 _cimg_test_temporary_path("D:\\WINNT\\Temp"); 04430 _cimg_test_temporary_path("D:\\WINDOWS\\Temp"); 04431 _cimg_test_temporary_path("D:\\Temp"); 04432 _cimg_test_temporary_path("D:"); 04433 #else 04434 _cimg_test_temporary_path("/tmp"); 04435 _cimg_test_temporary_path("/var/tmp"); 04436 #endif 04437 if (!path_found) { 04438 st_path[0] = 0; 04439 std::strcpy(tmp,filetmp); 04440 if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } 04441 } 04442 if (!path_found) 04443 throw CImgIOException("cimg::temporary_path() : Failed to locate path for writing temporary files.\n"); 04444 } 04445 return st_path; 04446 } 04447 04448 // Return or set path to the "Program files/" directory (windows only). 04449 #if cimg_OS==2 04450 inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) { 04451 static char *st_path = 0; 04452 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04453 if (user_path) { 04454 if (!st_path) st_path = new char[1024]; 04455 std::memset(st_path,0,1024); 04456 std::strncpy(st_path,user_path,1023); 04457 } else if (!st_path) { 04458 st_path = new char[MAX_PATH]; 04459 std::memset(st_path,0,MAX_PATH); 04460 // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). 04461 #if !defined(__INTEL_COMPILER) 04462 if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) { 04463 const char *const pfPath = getenv("PROGRAMFILES"); 04464 if (pfPath) std::strncpy(st_path,pfPath,MAX_PATH-1); 04465 else std::strcpy(st_path,"C:\\PROGRA~1"); 04466 } 04467 #else 04468 std::strcpy(st_path,"C:\\PROGRA~1"); 04469 #endif 04470 } 04471 return st_path; 04472 } 04473 #endif 04474 04475 //! Return or set path to the ImageMagick's \c convert tool. 04476 inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) { 04477 static char *st_path = 0; 04478 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04479 if (user_path) { 04480 if (!st_path) st_path = new char[1024]; 04481 std::memset(st_path,0,1024); 04482 std::strncpy(st_path,user_path,1023); 04483 } else if (!st_path) { 04484 st_path = new char[1024]; 04485 std::memset(st_path,0,1024); 04486 bool path_found = false; 04487 std::FILE *file = 0; 04488 #if cimg_OS==2 04489 const char *const pf_path = programfiles_path(); 04490 if (!path_found) { 04491 std::sprintf(st_path,".\\convert.exe"); 04492 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04493 } 04494 for (int k = 32; k>=10 && !path_found; --k) { 04495 std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k); 04496 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04497 } 04498 for (int k = 9; k>=0 && !path_found; --k) { 04499 std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k); 04500 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04501 } 04502 for (int k = 32; k>=0 && !path_found; --k) { 04503 std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k); 04504 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04505 } 04506 for (int k = 32; k>=10 && !path_found; --k) { 04507 std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k); 04508 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04509 } 04510 for (int k = 9; k>=0 && !path_found; --k) { 04511 std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k); 04512 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04513 } 04514 for (int k = 32; k>=0 && !path_found; --k) { 04515 std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k); 04516 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04517 } 04518 for (int k = 32; k>=10 && !path_found; --k) { 04519 std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k); 04520 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04521 } 04522 for (int k = 9; k>=0 && !path_found; --k) { 04523 std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k); 04524 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04525 } 04526 for (int k = 32; k>=0 && !path_found; --k) { 04527 std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k); 04528 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04529 } 04530 for (int k = 32; k>=10 && !path_found; --k) { 04531 std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); 04532 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04533 } 04534 for (int k = 9; k>=0 && !path_found; --k) { 04535 std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); 04536 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04537 } 04538 for (int k = 32; k>=0 && !path_found; --k) { 04539 std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); 04540 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04541 } 04542 for (int k = 32; k>=10 && !path_found; --k) { 04543 std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k); 04544 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04545 } 04546 for (int k = 9; k>=0 && !path_found; --k) { 04547 std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k); 04548 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04549 } 04550 for (int k = 32; k>=0 && !path_found; --k) { 04551 std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k); 04552 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04553 } 04554 for (int k = 32; k>=10 && !path_found; --k) { 04555 std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k); 04556 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04557 } 04558 for (int k = 9; k>=0 && !path_found; --k) { 04559 std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k); 04560 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04561 } 04562 for (int k = 32; k>=0 && !path_found; --k) { 04563 std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k); 04564 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04565 } 04566 if (!path_found) std::strcpy(st_path,"convert.exe"); 04567 #else 04568 if (!path_found) { 04569 std::sprintf(st_path,"./convert"); 04570 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04571 } 04572 if (!path_found) std::strcpy(st_path,"convert"); 04573 #endif 04574 winformat_string(st_path); 04575 } 04576 return st_path; 04577 } 04578 04579 //! Return path of the GraphicsMagick's \c gm tool. 04580 inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) { 04581 static char *st_path = 0; 04582 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04583 if (user_path) { 04584 if (!st_path) st_path = new char[1024]; 04585 std::memset(st_path,0,1024); 04586 std::strncpy(st_path,user_path,1023); 04587 } else if (!st_path) { 04588 st_path = new char[1024]; 04589 std::memset(st_path,0,1024); 04590 bool path_found = false; 04591 std::FILE *file = 0; 04592 #if cimg_OS==2 04593 const char *const pf_path = programfiles_path(); 04594 if (!path_found) { 04595 std::sprintf(st_path,".\\gm.exe"); 04596 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04597 } 04598 for (int k = 32; k>=10 && !path_found; --k) { 04599 std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k); 04600 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04601 } 04602 for (int k = 9; k>=0 && !path_found; --k) { 04603 std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k); 04604 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04605 } 04606 for (int k = 32; k>=0 && !path_found; --k) { 04607 std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k); 04608 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04609 } 04610 for (int k = 32; k>=10 && !path_found; --k) { 04611 std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k); 04612 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04613 } 04614 for (int k = 9; k>=0 && !path_found; --k) { 04615 std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); 04616 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04617 } 04618 for (int k = 32; k>=0 && !path_found; --k) { 04619 std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k); 04620 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04621 } 04622 for (int k = 32; k>=10 && !path_found; --k) { 04623 std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k); 04624 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04625 } 04626 for (int k = 9; k>=0 && !path_found; --k) { 04627 std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k); 04628 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04629 } 04630 for (int k = 32; k>=0 && !path_found; --k) { 04631 std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k); 04632 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04633 } 04634 for (int k = 32; k>=10 && !path_found; --k) { 04635 std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); 04636 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04637 } 04638 for (int k = 9; k>=0 && !path_found; --k) { 04639 std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); 04640 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04641 } 04642 for (int k = 32; k>=0 && !path_found; --k) { 04643 std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); 04644 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04645 } 04646 for (int k = 32; k>=10 && !path_found; --k) { 04647 std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k); 04648 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04649 } 04650 for (int k = 9; k>=0 && !path_found; --k) { 04651 std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k); 04652 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04653 } 04654 for (int k = 32; k>=0 && !path_found; --k) { 04655 std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k); 04656 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04657 } 04658 for (int k = 32; k>=10 && !path_found; --k) { 04659 std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); 04660 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04661 } 04662 for (int k = 9; k>=0 && !path_found; --k) { 04663 std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); 04664 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04665 } 04666 for (int k = 32; k>=0 && !path_found; --k) { 04667 std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); 04668 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04669 } 04670 if (!path_found) std::strcpy(st_path,"gm.exe"); 04671 #else 04672 if (!path_found) { 04673 std::sprintf(st_path,"./gm"); 04674 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04675 } 04676 if (!path_found) std::strcpy(st_path,"gm"); 04677 #endif 04678 winformat_string(st_path); 04679 } 04680 return st_path; 04681 } 04682 04683 //! Return or set path of the \c XMedcon tool. 04684 inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) { 04685 static char *st_path = 0; 04686 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04687 if (user_path) { 04688 if (!st_path) st_path = new char[1024]; 04689 std::memset(st_path,0,1024); 04690 std::strncpy(st_path,user_path,1023); 04691 } else if (!st_path) { 04692 st_path = new char[1024]; 04693 std::memset(st_path,0,1024); 04694 bool path_found = false; 04695 std::FILE *file = 0; 04696 #if cimg_OS==2 04697 const char *const pf_path = programfiles_path(); 04698 if (!path_found) { 04699 std::sprintf(st_path,".\\medcon.bat"); 04700 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04701 } 04702 if (!path_found) { 04703 std::sprintf(st_path,".\\medcon.exe"); 04704 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04705 } 04706 if (!path_found) { 04707 std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path); 04708 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04709 } 04710 if (!path_found) { 04711 std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path); 04712 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04713 } 04714 if (!path_found) std::strcpy(st_path,"medcon.bat"); 04715 #else 04716 if (!path_found) { 04717 std::sprintf(st_path,"./medcon"); 04718 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04719 } 04720 if (!path_found) std::strcpy(st_path,"medcon"); 04721 #endif 04722 winformat_string(st_path); 04723 } 04724 return st_path; 04725 } 04726 04727 //! Return or set path to the 'ffmpeg' command. 04728 inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) { 04729 static char *st_path = 0; 04730 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04731 if (user_path) { 04732 if (!st_path) st_path = new char[1024]; 04733 std::memset(st_path,0,1024); 04734 std::strncpy(st_path,user_path,1023); 04735 } else if (!st_path) { 04736 st_path = new char[1024]; 04737 std::memset(st_path,0,1024); 04738 bool path_found = false; 04739 std::FILE *file = 0; 04740 #if cimg_OS==2 04741 if (!path_found) { 04742 std::sprintf(st_path,".\\ffmpeg.exe"); 04743 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04744 } 04745 if (!path_found) std::strcpy(st_path,"ffmpeg.exe"); 04746 #else 04747 if (!path_found) { 04748 std::sprintf(st_path,"./ffmpeg"); 04749 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04750 } 04751 if (!path_found) std::strcpy(st_path,"ffmpeg"); 04752 #endif 04753 winformat_string(st_path); 04754 } 04755 return st_path; 04756 } 04757 04758 //! Return or set path to the 'gzip' command. 04759 inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) { 04760 static char *st_path = 0; 04761 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04762 if (user_path) { 04763 if (!st_path) st_path = new char[1024]; 04764 std::memset(st_path,0,1024); 04765 std::strncpy(st_path,user_path,1023); 04766 } else if (!st_path) { 04767 st_path = new char[1024]; 04768 std::memset(st_path,0,1024); 04769 bool path_found = false; 04770 std::FILE *file = 0; 04771 #if cimg_OS==2 04772 if (!path_found) { 04773 std::sprintf(st_path,".\\gzip.exe"); 04774 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04775 } 04776 if (!path_found) std::strcpy(st_path,"gzip.exe"); 04777 #else 04778 if (!path_found) { 04779 std::sprintf(st_path,"./gzip"); 04780 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04781 } 04782 if (!path_found) std::strcpy(st_path,"gzip"); 04783 #endif 04784 winformat_string(st_path); 04785 } 04786 return st_path; 04787 } 04788 04789 //! Return or set path to the 'gunzip' command. 04790 inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) { 04791 static char *st_path = 0; 04792 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04793 if (user_path) { 04794 if (!st_path) st_path = new char[1024]; 04795 std::memset(st_path,0,1024); 04796 std::strncpy(st_path,user_path,1023); 04797 } else if (!st_path) { 04798 st_path = new char[1024]; 04799 std::memset(st_path,0,1024); 04800 bool path_found = false; 04801 std::FILE *file = 0; 04802 #if cimg_OS==2 04803 if (!path_found) { 04804 std::sprintf(st_path,".\\gunzip.exe"); 04805 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04806 } 04807 if (!path_found) std::strcpy(st_path,"gunzip.exe"); 04808 #else 04809 if (!path_found) { 04810 std::sprintf(st_path,"./gunzip"); 04811 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04812 } 04813 if (!path_found) std::strcpy(st_path,"gunzip"); 04814 #endif 04815 winformat_string(st_path); 04816 } 04817 return st_path; 04818 } 04819 04820 //! Return or set path to the 'dcraw' command. 04821 inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) { 04822 static char *st_path = 0; 04823 if (reinit_path && st_path) { delete[] st_path; st_path = 0; } 04824 if (user_path) { 04825 if (!st_path) st_path = new char[1024]; 04826 std::memset(st_path,0,1024); 04827 std::strncpy(st_path,user_path,1023); 04828 } else if (!st_path) { 04829 st_path = new char[1024]; 04830 std::memset(st_path,0,1024); 04831 bool path_found = false; 04832 std::FILE *file = 0; 04833 #if cimg_OS==2 04834 if (!path_found) { 04835 std::sprintf(st_path,".\\dcraw.exe"); 04836 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04837 } 04838 if (!path_found) std::strcpy(st_path,"dcraw.exe"); 04839 #else 04840 if (!path_found) { 04841 std::sprintf(st_path,"./dcraw"); 04842 if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; } 04843 } 04844 if (!path_found) std::strcpy(st_path,"dcraw"); 04845 #endif 04846 winformat_string(st_path); 04847 } 04848 return st_path; 04849 } 04850 04851 //! Split a filename into two strings 'body' and 'extension'. 04852 inline const char *split_filename(const char *const filename, char *const body=0) { 04853 if (!filename) { if (body) body[0] = 0; return 0; } 04854 const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.')+1) {} 04855 if (p==filename) { 04856 if (body) std::strcpy(body,filename); 04857 return filename + std::strlen(filename); 04858 } 04859 const unsigned int l = p - filename - 1; 04860 if (body) { std::memcpy(body,filename,l); body[l] = 0; } 04861 return p; 04862 } 04863 04864 //! Create a numbered version of a filename. 04865 inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) { 04866 if (!filename) { if (string) string[0] = 0; return 0; } 04867 char format[1024] = { 0 }, body[1024] = { 0 }; 04868 const char *const ext = cimg::split_filename(filename,body); 04869 if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext); 04870 else std::sprintf(format,"%s_%%d.%s",body,ext); 04871 std::sprintf(string,format,number); 04872 return string; 04873 } 04874 04875 //! Open a file, and check for possible errors. 04876 inline std::FILE *fopen(const char *const path, const char *const mode) { 04877 if (!path) 04878 throw CImgArgumentException("cimg::fopen() : Specified file path is (null)."); 04879 if (!mode) 04880 throw CImgArgumentException("cimg::fopen() : File '%s', specified mode is (null).", 04881 path); 04882 04883 if (path[0]=='-') return (*mode=='r')?stdin:stdout; 04884 std::FILE *res = std::fopen(path,mode); 04885 if (!res) 04886 throw CImgIOException("cimg::fopen() : Failed to open file '%s' with mode '%s'.", 04887 path,mode); 04888 return res; 04889 } 04890 04891 //! Close a file, and check for possible errors. 04892 inline int fclose(std::FILE *file) { 04893 if (!file) warn("cimg::fclose() : Specified file is (null)."); 04894 if (!file || file==stdin || file==stdout) return 0; 04895 const int errn = std::fclose(file); 04896 if (errn!=0) warn("cimg::fclose() : Error code %d returned during file closing.", 04897 errn); 04898 return errn; 04899 } 04900 04901 //! Try to guess the image format of a filename, using the magic numbers in its header. 04902 inline const char *file_type(std::FILE *const file, const char *const filename) { 04903 if (!file && !filename) 04904 throw CImgArgumentException("cimg::file_type() : Specified filename is (null)."); 04905 static const char 04906 *const _pnm = "pnm", 04907 *const _pfm = "pfm", 04908 *const _bmp = "bmp", 04909 *const _gif = "gif", 04910 *const _jpg = "jpg", 04911 *const _off = "off", 04912 *const _pan = "pan", 04913 *const _png = "png", 04914 *const _tif = "tif", 04915 *const _inr = "inr", 04916 *const _dcm = "dcm"; 04917 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 04918 const char *f_type = 0, *head; 04919 char header[2048] = { 0 }, item[1024] = { 0 }; 04920 const unsigned char *const uheader = (unsigned char*)header; 04921 int err; char cerr; 04922 const unsigned int siz = (unsigned int)std::fread(header,2048,1,nfile); // Read first 2048 bytes. 04923 if (!file) cimg::fclose(nfile); 04924 04925 if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // Check for OFF format. 04926 else if (!std::strncmp(header,"#INRIMAGE",9)) f_type = _inr; // Check for INRIMAGE format. 04927 else if (!std::strncmp(header,"PANDORE",7)) f_type = _pan; // Check for PANDORE format. 04928 else if (!std::strncmp(header+128,"DICM",4)) f_type = _dcm; // Check for DICOM format. 04929 else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg; // Check for JPEG format. 04930 else if (header[0]=='B' && header[1]=='M') f_type = _bmp; // Check for BMP format. 04931 else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // Check for GIF format. 04932 (header[4]=='7' || header[4]=='9')) f_type = _gif; 04933 else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 && // Check for PNG format. 04934 uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png; 04935 else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // Check for TIFF format. 04936 else { // Check for PNM or PFM format. 04937 head = header; 04938 while (head<header+siz && (err=std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) 04939 head+=1+(err?std::strlen(item):0); 04940 if (std::sscanf(item," P%d",&err)==1) f_type = _pnm; 04941 else if (std::sscanf(item," P%c",&cerr)==1 && (cerr=='f' || cerr=='F')) f_type = _pfm; 04942 } 04943 return f_type; 04944 } 04945 04946 //! Read file data, and check for possible errors. 04947 template<typename T> 04948 inline int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream) { 04949 if (!ptr || nmemb<=0 || !stream) 04950 throw CImgArgumentException("cimg::fread() : Invalid reading request of %u %s%s from file %p to buffer %p.", 04951 nmemb,cimg::type<T>::string(),nmemb>1?"s":"",stream,ptr); 04952 04953 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); 04954 unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0; 04955 do { 04956 ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit; 04957 lalread = (unsigned int)std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream); 04958 alread+=lalread; 04959 toread-=lalread; 04960 } while (ltoread==lalread && toread>0); 04961 if (toread>0) 04962 warn("cimg::fread() : Only %u/%u elements could be read from file.", 04963 alread,nmemb); 04964 return alread; 04965 } 04966 04967 //! Write data to a file, and check for possible errors. 04968 template<typename T> 04969 inline int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream) { 04970 if (!ptr || !stream) 04971 throw CImgArgumentException("cimg::fwrite() : Invalid writting request of %u %s%s from buffer %p to file %p.", 04972 nmemb,cimg::type<T>::string(),nmemb>1?"s":"",ptr,stream); 04973 if (nmemb<=0) return 0; 04974 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); 04975 unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0; 04976 do { 04977 ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit; 04978 lalwrite = (unsigned int)std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream); 04979 alwrite+=lalwrite; 04980 towrite-=lalwrite; 04981 } while (ltowrite==lalwrite && towrite>0); 04982 if (towrite>0) 04983 warn("cimg::fwrite() : Only %u/%u elements could be written in file.", 04984 alwrite,nmemb); 04985 return alwrite; 04986 } 04987 04988 inline const char* option(const char *const name, const int argc, const char *const *const argv, 04989 const char *const defaut, const char *const usage, const bool reset_static) { 04990 static bool first = true, visu = false; 04991 if (reset_static) { first = true; return 0; } 04992 const char *res = 0; 04993 if (first) { 04994 first = false; 04995 visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0; 04996 visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0; 04997 visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0; 04998 } 04999 if (!name && visu) { 05000 if (usage) { 05001 std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal); 05002 std::fprintf(cimg::output()," : %s",usage); 05003 std::fprintf(cimg::output()," (%s, %s)\n\n",__DATE__,__TIME__); 05004 } 05005 if (defaut) std::fprintf(cimg::output(),"%s\n",defaut); 05006 } 05007 if (name) { 05008 if (argc>0) { 05009 int k = 0; 05010 while (k<argc && std::strcmp(argv[k],name)) ++k; 05011 res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k])); 05012 } else res = defaut; 05013 if (visu && usage) std::fprintf(cimg::output()," %s%-16s%s %-24s %s%s%s\n", 05014 cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal); 05015 } 05016 return res; 05017 } 05018 05019 inline const char* option(const char *const name, const int argc, const char *const *const argv, 05020 const char *const defaut, const char *const usage=0) { 05021 return option(name,argc,argv,defaut,usage,false); 05022 } 05023 05024 inline bool option(const char *const name, const int argc, const char *const *const argv, 05025 const bool defaut, const char *const usage=0) { 05026 const char *const s = cimg::option(name,argc,argv,(char*)0); 05027 const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut; 05028 cimg::option(name,0,0,res?"true":"false",usage); 05029 return res; 05030 } 05031 05032 inline int option(const char *const name, const int argc, const char *const *const argv, 05033 const int defaut, const char *const usage=0) { 05034 const char *const s = cimg::option(name,argc,argv,(char*)0); 05035 const int res = s?std::atoi(s):defaut; 05036 char tmp[256] = { 0 }; 05037 std::sprintf(tmp,"%d",res); 05038 cimg::option(name,0,0,tmp,usage); 05039 return res; 05040 } 05041 05042 inline char option(const char *const name, const int argc, const char *const *const argv, 05043 const char defaut, const char *const usage=0) { 05044 const char *const s = cimg::option(name,argc,argv,(char*)0); 05045 const char res = s?s[0]:defaut; 05046 char tmp[8] = { 0 }; 05047 tmp[0] = res; 05048 cimg::option(name,0,0,tmp,usage); 05049 return res; 05050 } 05051 05052 inline float option(const char *const name, const int argc, const char *const *const argv, 05053 const float defaut, const char *const usage=0) { 05054 const char *const s = cimg::option(name,argc,argv,(char*)0); 05055 const float res = s?(float)cimg::atof(s):defaut; 05056 char tmp[256] = { 0 }; 05057 std::sprintf(tmp,"%g",res); 05058 cimg::option(name,0,0,tmp,usage); 05059 return res; 05060 } 05061 05062 inline double option(const char *const name, const int argc, const char *const *const argv, 05063 const double defaut, const char *const usage=0) { 05064 const char *const s = cimg::option(name,argc,argv,(char*)0); 05065 const double res = s?cimg::atof(s):defaut; 05066 char tmp[256] = { 0 }; 05067 std::sprintf(tmp,"%g",res); 05068 cimg::option(name,0,0,tmp,usage); 05069 return res; 05070 } 05071 05072 inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) { 05073 for (int k = 1, pos = 0; k<argc;) { 05074 const char *const item = argv[k]; 05075 bool option = (*item=='-'), single_option = false; 05076 if (option) { 05077 va_list ap; 05078 va_start(ap,nb_singles); 05079 for (unsigned int i = 0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; } 05080 va_end(ap); 05081 } 05082 if (option) { ++k; if (!single_option) ++k; } 05083 else { if (pos++==(int)nb) return item; else ++k; } 05084 } 05085 return 0; 05086 } 05087 05088 //! Print informations about %CImg environement variables. 05089 /** 05090 Printing is done on the standard error output. 05091 **/ 05092 inline void info() { 05093 char tmp[1024] = { 0 }; 05094 std::fprintf(cimg::output(),"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n", 05095 cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10, 05096 cimg::t_normal,__DATE__,__TIME__); 05097 05098 std::fprintf(cimg::output()," > Operating System : %s%-13s%s %s('cimg_OS'=%d)%s\n", 05099 cimg::t_bold, 05100 cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"), 05101 cimg::t_normal,cimg::t_green, 05102 cimg_OS, 05103 cimg::t_normal); 05104 05105 std::fprintf(cimg::output()," > CPU endianness : %s%s Endian%s\n", 05106 cimg::t_bold, 05107 cimg::endianness()?"Big":"Little", 05108 cimg::t_normal); 05109 05110 std::fprintf(cimg::output()," > Verbosity mode : %s%-13s%s %s('cimg_verbosity'=%d)%s\n", 05111 cimg::t_bold, 05112 cimg_verbosity==0?"Quiet":(cimg_verbosity==1?"Console":(cimg_verbosity==2?"Dialog":(cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings"))), 05113 cimg::t_normal,cimg::t_green, 05114 cimg_verbosity, 05115 cimg::t_normal); 05116 05117 std::fprintf(cimg::output()," > Stricts warnings : %s%-13s%s %s('cimg_strict_warnings' %s)%s\n", 05118 cimg::t_bold, 05119 #ifdef cimg_strict_warnings 05120 "Yes",cimg::t_normal,cimg::t_green,"defined", 05121 #else 05122 "No",cimg::t_normal,cimg::t_green,"undefined", 05123 #endif 05124 cimg::t_normal); 05125 05126 std::fprintf(cimg::output()," > Using VT100 messages : %s%-13s%s %s('cimg_use_vt100' %s)%s\n", 05127 cimg::t_bold, 05128 #ifdef cimg_use_vt100 05129 "Yes",cimg::t_normal,cimg::t_green,"defined", 05130 #else 05131 "No",cimg::t_normal,cimg::t_green,"undefined", 05132 #endif 05133 cimg::t_normal); 05134 05135 std::fprintf(cimg::output()," > Display type : %s%-13s%s %s('cimg_display'=%d)%s\n", 05136 cimg::t_bold, 05137 cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown", 05138 cimg::t_normal,cimg::t_green, 05139 cimg_display, 05140 cimg::t_normal); 05141 05142 #if cimg_display==1 05143 std::fprintf(cimg::output()," > Using XShm for X11 : %s%-13s%s %s('cimg_use_xshm' %s)%s\n", 05144 cimg::t_bold, 05145 #ifdef cimg_use_xshm 05146 "Yes",cimg::t_normal,cimg::t_green,"defined", 05147 #else 05148 "No",cimg::t_normal,cimg::t_green,"undefined", 05149 #endif 05150 cimg::t_normal); 05151 05152 std::fprintf(cimg::output()," > Using XRand for X11 : %s%-13s%s %s('cimg_use_xrandr' %s)%s\n", 05153 cimg::t_bold, 05154 #ifdef cimg_use_xrandr 05155 "Yes",cimg::t_normal,cimg::t_green,"defined", 05156 #else 05157 "No",cimg::t_normal,cimg::t_green,"undefined", 05158 #endif 05159 cimg::t_normal); 05160 #endif 05161 std::fprintf(cimg::output()," > Using OpenMP : %s%-13s%s %s('cimg_use_openmp' %s)%s\n", 05162 cimg::t_bold, 05163 #ifdef cimg_use_openmp 05164 "Yes",cimg::t_normal,cimg::t_green,"defined", 05165 #else 05166 "No",cimg::t_normal,cimg::t_green,"undefined", 05167 #endif 05168 cimg::t_normal); 05169 std::fprintf(cimg::output()," > Using PNG library : %s%-13s%s %s('cimg_use_png' %s)%s\n", 05170 cimg::t_bold, 05171 #ifdef cimg_use_png 05172 "Yes",cimg::t_normal,cimg::t_green,"defined", 05173 #else 05174 "No",cimg::t_normal,cimg::t_green,"undefined", 05175 #endif 05176 cimg::t_normal); 05177 std::fprintf(cimg::output()," > Using JPEG library : %s%-13s%s %s('cimg_use_jpeg' %s)%s\n", 05178 cimg::t_bold, 05179 #ifdef cimg_use_jpeg 05180 "Yes",cimg::t_normal,cimg::t_green,"defined", 05181 #else 05182 "No",cimg::t_normal,cimg::t_green,"undefined", 05183 #endif 05184 cimg::t_normal); 05185 05186 std::fprintf(cimg::output()," > Using TIFF library : %s%-13s%s %s('cimg_use_tiff' %s)%s\n", 05187 cimg::t_bold, 05188 #ifdef cimg_use_tiff 05189 "Yes",cimg::t_normal,cimg::t_green,"defined", 05190 #else 05191 "No",cimg::t_normal,cimg::t_green,"undefined", 05192 #endif 05193 cimg::t_normal); 05194 05195 std::fprintf(cimg::output()," > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n", 05196 cimg::t_bold, 05197 #ifdef cimg_use_magick 05198 "Yes",cimg::t_normal,cimg::t_green,"defined", 05199 #else 05200 "No",cimg::t_normal,cimg::t_green,"undefined", 05201 #endif 05202 cimg::t_normal); 05203 05204 std::fprintf(cimg::output()," > Using FFTW3 library : %s%-13s%s %s('cimg_use_fftw3' %s)%s\n", 05205 cimg::t_bold, 05206 #ifdef cimg_use_fftw3 05207 "Yes",cimg::t_normal,cimg::t_green,"defined", 05208 #else 05209 "No",cimg::t_normal,cimg::t_green,"undefined", 05210 #endif 05211 cimg::t_normal); 05212 05213 std::fprintf(cimg::output()," > Using LAPACK library : %s%-13s%s %s('cimg_use_lapack' %s)%s\n", 05214 cimg::t_bold, 05215 #ifdef cimg_use_lapack 05216 "Yes",cimg::t_normal,cimg::t_green,"defined", 05217 #else 05218 "No",cimg::t_normal,cimg::t_green,"undefined", 05219 #endif 05220 cimg::t_normal); 05221 05222 std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path()); 05223 std::fprintf(cimg::output()," > Path of ImageMagick : %s%-13s%s\n", 05224 cimg::t_bold, 05225 tmp, 05226 cimg::t_normal); 05227 05228 std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path()); 05229 std::fprintf(cimg::output()," > Path of GraphicsMagick : %s%-13s%s\n", 05230 cimg::t_bold, 05231 tmp, 05232 cimg::t_normal); 05233 05234 std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path()); 05235 std::fprintf(cimg::output()," > Path of 'medcon' : %s%-13s%s\n", 05236 cimg::t_bold, 05237 tmp, 05238 cimg::t_normal); 05239 05240 std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path()); 05241 std::fprintf(cimg::output()," > Temporary path : %s%-13s%s\n", 05242 cimg::t_bold, 05243 tmp, 05244 cimg::t_normal); 05245 05246 std::fprintf(cimg::output(),"\n"); 05247 } 05248 05249 // Declare LAPACK function signatures if necessary. 05250 #ifdef cimg_use_lapack 05251 template<typename T> 05252 inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) { 05253 dgetrf_(&N,&N,lapA,&N,IPIV,&INFO); 05254 } 05255 05256 inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) { 05257 sgetrf_(&N,&N,lapA,&N,IPIV,&INFO); 05258 } 05259 05260 template<typename T> 05261 inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) { 05262 dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); 05263 } 05264 05265 inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) { 05266 sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); 05267 } 05268 05269 template<typename T> 05270 inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN, 05271 T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) { 05272 dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); 05273 } 05274 05275 inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN, 05276 float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) { 05277 sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); 05278 } 05279 05280 template<typename T> 05281 inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) { 05282 int one = 1; 05283 dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); 05284 } 05285 05286 inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) { 05287 int one = 1; 05288 sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); 05289 } 05290 05291 template<typename T> 05292 inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) { 05293 dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); 05294 } 05295 05296 inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) { 05297 ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); 05298 } 05299 #endif 05300 05301 // End of the 'cimg' namespace 05302 } 05303 05304 /*------------------------------------------------ 05305 # 05306 # 05307 # Definition of mathematical operators and 05308 # external functions. 05309 # 05310 # 05311 -------------------------------------------------*/ 05312 05313 #define _cimg_create_ext_operators(typ) \ 05314 template<typename T> \ 05315 inline CImg<typename cimg::superset<T,typ>::type> operator+(const typ val, const CImg<T>& img) { \ 05316 return img + val; \ 05317 } \ 05318 template<typename T> \ 05319 inline CImg<typename cimg::superset<T,typ>::type> operator-(const typ val, const CImg<T>& img) { \ 05320 typedef typename cimg::superset<T,typ>::type Tt; \ 05321 return CImg<Tt>(img._width,img._height,img._depth,img._spectrum,val)-=img; \ 05322 } \ 05323 template<typename T> \ 05324 inline CImg<typename cimg::superset<T,typ>::type> operator*(const typ val, const CImg<T>& img) { \ 05325 return img*val; \ 05326 } \ 05327 template<typename T> \ 05328 inline CImg<typename cimg::superset<T,typ>::type> operator/(const typ val, const CImg<T>& img) { \ 05329 return val*img.get_invert(); \ 05330 } \ 05331 template<typename T> \ 05332 inline CImg<typename cimg::superset<T,typ>::type> operator&(const typ val, const CImg<T>& img) { \ 05333 return img & val; \ 05334 } \ 05335 template<typename T> \ 05336 inline CImg<typename cimg::superset<T,typ>::type> operator|(const typ val, const CImg<T>& img) { \ 05337 return img | val; \ 05338 } \ 05339 template<typename T> \ 05340 inline CImg<typename cimg::superset<T,typ>::type> operator^(const typ val, const CImg<T>& img) { \ 05341 return img ^ val; \ 05342 } \ 05343 05344 _cimg_create_ext_operators(bool) 05345 _cimg_create_ext_operators(unsigned char) 05346 _cimg_create_ext_operators(char) 05347 _cimg_create_ext_operators(signed char) 05348 _cimg_create_ext_operators(unsigned short) 05349 _cimg_create_ext_operators(short) 05350 _cimg_create_ext_operators(unsigned int) 05351 _cimg_create_ext_operators(int) 05352 _cimg_create_ext_operators(unsigned long) 05353 _cimg_create_ext_operators(long) 05354 _cimg_create_ext_operators(float) 05355 _cimg_create_ext_operators(double) 05356 05357 template<typename T> 05358 inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) { 05359 return img + expression; 05360 } 05361 05362 template<typename T> 05363 inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) { 05364 return (CImg<_cimg_Tfloat>(img._width,img._height,img._depth,img._spectrum)=expression)-=img; 05365 } 05366 05367 template<typename T> 05368 inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg<T>& img) { 05369 return img*expression; 05370 } 05371 05372 template<typename T> 05373 inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) { 05374 return expression*img.get_invert(); 05375 } 05376 05377 template<typename T> 05378 inline CImg<T> operator&(const char *const expression, const CImg<T>& img) { 05379 return img & expression; 05380 } 05381 05382 template<typename T> 05383 inline CImg<T> operator|(const char *const expression, const CImg<T>& img) { 05384 return img | expression; 05385 } 05386 05387 template<typename T> 05388 inline CImg<T> operator^(const char *const expression, const CImg<T>& img) { 05389 return img ^ expression; 05390 } 05391 05392 template<typename T> 05393 inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) { 05394 return instance.get_sqr(); 05395 } 05396 05397 template<typename T> 05398 inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) { 05399 return instance.get_sqrt(); 05400 } 05401 05402 template<typename T> 05403 inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) { 05404 return instance.get_exp(); 05405 } 05406 05407 template<typename T> 05408 inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) { 05409 return instance.get_log(); 05410 } 05411 05412 template<typename T> 05413 inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) { 05414 return instance.get_log10(); 05415 } 05416 05417 template<typename T> 05418 inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) { 05419 return instance.get_abs(); 05420 } 05421 05422 template<typename T> 05423 inline CImg<_cimg_Tfloat> sign(const CImg<T>& instance) { 05424 return instance.get_sign(); 05425 } 05426 05427 template<typename T> 05428 inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) { 05429 return instance.get_cos(); 05430 } 05431 05432 template<typename T> 05433 inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) { 05434 return instance.get_sin(); 05435 } 05436 05437 template<typename T> 05438 inline CImg<_cimg_Tfloat> sinc(const CImg<T>& instance) { 05439 return instance.get_sinc(); 05440 } 05441 05442 template<typename T> 05443 inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) { 05444 return instance.get_tan(); 05445 } 05446 05447 template<typename T> 05448 inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) { 05449 return instance.get_acos(); 05450 } 05451 05452 template<typename T> 05453 inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) { 05454 return instance.get_asin(); 05455 } 05456 05457 template<typename T> 05458 inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) { 05459 return instance.get_atan(); 05460 } 05461 05462 template<typename T> 05463 inline CImg<_cimg_Tfloat> cosh(const CImg<T>& instance) { 05464 return instance.get_cosh(); 05465 } 05466 05467 template<typename T> 05468 inline CImg<_cimg_Tfloat> sinh(const CImg<T>& instance) { 05469 return instance.get_sinh(); 05470 } 05471 05472 template<typename T> 05473 inline CImg<_cimg_Tfloat> tanh(const CImg<T>& instance) { 05474 return instance.get_tanh(); 05475 } 05476 05477 template<typename T> 05478 inline CImg<T> transpose(const CImg<T>& instance) { 05479 return instance.get_transpose(); 05480 } 05481 05482 template<typename T> 05483 inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) { 05484 return instance.get_invert(); 05485 } 05486 05487 template<typename T> 05488 inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) { 05489 return instance.get_pseudoinvert(); 05490 } 05491 05492 /*------------------------------------------- 05493 # 05494 # 05495 # 05496 # Definition of the CImgDisplay structure 05497 # 05498 # 05499 # 05500 --------------------------------------------*/ 05501 05502 //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events. 05503 /** 05504 Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image 05505 of a \c CImgList<T> image list inside. When a display is created, associated window events 05506 (such as mouse motion, keyboard and window size changes) are handled and can be easily 05507 detected by testing specific \c CImgDisplay data fields. 05508 See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class. 05509 **/ 05510 05511 struct CImgDisplay { 05512 05513 //! Width of the display. 05514 unsigned int _width; 05515 05516 //! Height of the display. 05517 unsigned int _height; 05518 05519 //! Width of the underlying window. 05520 volatile unsigned int _window_width; 05521 05522 //! Height of the underlying window. 05523 volatile unsigned int _window_height; 05524 05525 //! X-pos of the display on the screen. 05526 volatile int _window_x; 05527 05528 //! Y-pos of the display on the screen. 05529 volatile int _window_y; 05530 05531 //! X-coordinate of the mouse pointer on the display. 05532 volatile int _mouse_x; 05533 05534 //! Y-coordinate of the mouse pointer on the display. 05535 volatile int _mouse_y; 05536 05537 //! Normalization type used for the display. 05538 unsigned int _normalization; 05539 05540 //! Display title. 05541 char *_title; 05542 05543 //! Button state of the mouse. 05544 volatile unsigned int _button; 05545 05546 //! Wheel state of the mouse. 05547 volatile int _wheel; 05548 05549 //! Key value if pressed. 05550 volatile unsigned int _keys[128]; 05551 volatile unsigned int _released_keys[128]; 05552 05553 //! Closed state of the window. 05554 volatile bool _is_closed; 05555 05556 //! Resized state of the window. 05557 volatile bool _is_resized; 05558 05559 //! Moved state of the window. 05560 volatile bool _is_moved; 05561 05562 //! Event state of the window. 05563 volatile bool _is_event; 05564 05565 //! Current state of the corresponding key (exists for all referenced keys). 05566 volatile bool _is_keyESC; 05567 volatile bool _is_keyF1; 05568 volatile bool _is_keyF2; 05569 volatile bool _is_keyF3; 05570 volatile bool _is_keyF4; 05571 volatile bool _is_keyF5; 05572 volatile bool _is_keyF6; 05573 volatile bool _is_keyF7; 05574 volatile bool _is_keyF8; 05575 volatile bool _is_keyF9; 05576 volatile bool _is_keyF10; 05577 volatile bool _is_keyF11; 05578 volatile bool _is_keyF12; 05579 volatile bool _is_keyPAUSE; 05580 volatile bool _is_key1; 05581 volatile bool _is_key2; 05582 volatile bool _is_key3; 05583 volatile bool _is_key4; 05584 volatile bool _is_key5; 05585 volatile bool _is_key6; 05586 volatile bool _is_key7; 05587 volatile bool _is_key8; 05588 volatile bool _is_key9; 05589 volatile bool _is_key0; 05590 volatile bool _is_keyBACKSPACE; 05591 volatile bool _is_keyINSERT; 05592 volatile bool _is_keyHOME; 05593 volatile bool _is_keyPAGEUP; 05594 volatile bool _is_keyTAB; 05595 volatile bool _is_keyQ; 05596 volatile bool _is_keyW; 05597 volatile bool _is_keyE; 05598 volatile bool _is_keyR; 05599 volatile bool _is_keyT; 05600 volatile bool _is_keyY; 05601 volatile bool _is_keyU; 05602 volatile bool _is_keyI; 05603 volatile bool _is_keyO; 05604 volatile bool _is_keyP; 05605 volatile bool _is_keyDELETE; 05606 volatile bool _is_keyEND; 05607 volatile bool _is_keyPAGEDOWN; 05608 volatile bool _is_keyCAPSLOCK; 05609 volatile bool _is_keyA; 05610 volatile bool _is_keyS; 05611 volatile bool _is_keyD; 05612 volatile bool _is_keyF; 05613 volatile bool _is_keyG; 05614 volatile bool _is_keyH; 05615 volatile bool _is_keyJ; 05616 volatile bool _is_keyK; 05617 volatile bool _is_keyL; 05618 volatile bool _is_keyENTER; 05619 volatile bool _is_keySHIFTLEFT; 05620 volatile bool _is_keyZ; 05621 volatile bool _is_keyX; 05622 volatile bool _is_keyC; 05623 volatile bool _is_keyV; 05624 volatile bool _is_keyB; 05625 volatile bool _is_keyN; 05626 volatile bool _is_keyM; 05627 volatile bool _is_keySHIFTRIGHT; 05628 volatile bool _is_keyARROWUP; 05629 volatile bool _is_keyCTRLLEFT; 05630 volatile bool _is_keyAPPLEFT; 05631 volatile bool _is_keyALT; 05632 volatile bool _is_keySPACE; 05633 volatile bool _is_keyALTGR; 05634 volatile bool _is_keyAPPRIGHT; 05635 volatile bool _is_keyMENU; 05636 volatile bool _is_keyCTRLRIGHT; 05637 volatile bool _is_keyARROWLEFT; 05638 volatile bool _is_keyARROWDOWN; 05639 volatile bool _is_keyARROWRIGHT; 05640 volatile bool _is_keyPAD0; 05641 volatile bool _is_keyPAD1; 05642 volatile bool _is_keyPAD2; 05643 volatile bool _is_keyPAD3; 05644 volatile bool _is_keyPAD4; 05645 volatile bool _is_keyPAD5; 05646 volatile bool _is_keyPAD6; 05647 volatile bool _is_keyPAD7; 05648 volatile bool _is_keyPAD8; 05649 volatile bool _is_keyPAD9; 05650 volatile bool _is_keyPADADD; 05651 volatile bool _is_keyPADSUB; 05652 volatile bool _is_keyPADMUL; 05653 volatile bool _is_keyPADDIV; 05654 05655 //! Fullscreen state of the display. 05656 bool _is_fullscreen; 05657 05658 // Internal variables. 05659 float _fps_fps, _min, _max; 05660 unsigned long _timer, _fps_frames, _fps_timer; 05661 05662 //@} 05663 //--------------------------- 05664 // 05665 //! \name Plugins 05666 //@{ 05667 //--------------------------- 05668 05669 #ifdef cimgdisplay_plugin 05670 #include cimgdisplay_plugin 05671 #endif 05672 #ifdef cimgdisplay_plugin1 05673 #include cimgdisplay_plugin1 05674 #endif 05675 #ifdef cimgdisplay_plugin2 05676 #include cimgdisplay_plugin2 05677 #endif 05678 #ifdef cimgdisplay_plugin3 05679 #include cimgdisplay_plugin3 05680 #endif 05681 #ifdef cimgdisplay_plugin4 05682 #include cimgdisplay_plugin4 05683 #endif 05684 #ifdef cimgdisplay_plugin5 05685 #include cimgdisplay_plugin5 05686 #endif 05687 #ifdef cimgdisplay_plugin6 05688 #include cimgdisplay_plugin6 05689 #endif 05690 #ifdef cimgdisplay_plugin7 05691 #include cimgdisplay_plugin7 05692 #endif 05693 #ifdef cimgdisplay_plugin8 05694 #include cimgdisplay_plugin8 05695 #endif 05696 05697 //@} 05698 //-------------------------------------------------------- 05699 // 05700 //! \name Constructors / Destructor / Instance Management 05701 //@{ 05702 //-------------------------------------------------------- 05703 05704 //! Destructor. 05705 ~CImgDisplay() { 05706 assign(); 05707 } 05708 05709 //! Create an empty display window. 05710 CImgDisplay(): 05711 _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1), 05712 _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false), 05713 _is_fullscreen(false),_min(0),_max(0) { 05714 assign(); 05715 } 05716 05717 //! Create a display window with a specified size \p pwidth x \p height. 05718 /** \param width Width of the display window. 05719 \param height Height of the display window. 05720 \param title Title of the display window. 05721 \param normalization Normalization type of the display window (0=none, 1=always, 2=once). 05722 \param is_fullscreen : Fullscreen mode. 05723 \param is_closed : Initially visible mode. 05724 A black image will be initially displayed in the display window. 05725 **/ 05726 CImgDisplay(const unsigned int width, const unsigned int height, 05727 const char *const title=0, const unsigned int normalization=3, 05728 const bool is_fullscreen=false, const bool is_closed=false): 05729 _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1), 05730 _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false), 05731 _is_fullscreen(false),_min(0),_max(0) { 05732 assign(width,height,title,normalization,is_fullscreen,is_closed); 05733 } 05734 05735 //! Create a display window from an image. 05736 /** \param img : Image that will be used to create the display window. 05737 \param title : Title of the display window 05738 \param normalization : Normalization type of the display window. 05739 \param is_fullscreen : Fullscreen mode. 05740 \param is_closed : Initially visible mode. 05741 **/ 05742 template<typename T> 05743 explicit CImgDisplay(const CImg<T>& img, 05744 const char *const title=0, const unsigned int normalization=3, 05745 const bool is_fullscreen=false, const bool is_closed=false): 05746 _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1), 05747 _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false), 05748 _is_fullscreen(false),_min(0),_max(0) { 05749 assign(img,title,normalization,is_fullscreen,is_closed); 05750 } 05751 05752 //! Create a display window from an image list. 05753 /** \param list : The list of images to display. 05754 \param title : Title of the display window 05755 \param normalization : Normalization type of the display window. 05756 \param is_fullscreen : Fullscreen mode. 05757 \param is_closed : Initially visible mode. 05758 **/ 05759 template<typename T> 05760 explicit CImgDisplay(const CImgList<T>& list, 05761 const char *const title=0, const unsigned int normalization=3, 05762 const bool is_fullscreen=false, const bool is_closed=false): 05763 _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1), 05764 _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false), 05765 _is_fullscreen(false),_min(0),_max(0) { 05766 assign(list,title,normalization,is_fullscreen,is_closed); 05767 } 05768 05769 //! Create a display window by copying another one. 05770 /** 05771 \param disp : Display window to copy. 05772 **/ 05773 CImgDisplay(const CImgDisplay& disp): 05774 _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1), 05775 _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false), 05776 _is_fullscreen(false),_min(0),_max(0) { 05777 assign(disp); 05778 } 05779 05780 #if cimg_display==0 05781 05782 static void _no_display_exception() { 05783 throw CImgDisplayException("CImgDisplay() : No display available."); 05784 } 05785 05786 //! In-place version of the destructor. 05787 CImgDisplay& assign() { 05788 _no_display_exception(); 05789 return flush(); 05790 } 05791 05792 //! In-place version of the constructor. 05793 CImgDisplay& assign(const unsigned int width, const unsigned int height, 05794 const char *const title=0, const unsigned int normalization=3, 05795 const bool is_fullscreen=false, const bool is_closed=false) { 05796 cimg::unused(width,height,title,normalization,is_fullscreen,is_closed); 05797 return assign(); 05798 } 05799 05800 //! In-place version of the constructor. 05801 template<typename T> 05802 CImgDisplay& assign(const CImg<T>& img, 05803 const char *const title=0, const unsigned int normalization=3, 05804 const bool is_fullscreen=false, const bool is_closed=false) { 05805 return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed); 05806 } 05807 05808 //! In-place version of the constructor. 05809 template<typename T> 05810 CImgDisplay& assign(const CImgList<T>& list, 05811 const char *const title=0, const unsigned int normalization=3, 05812 const bool is_fullscreen=false, const bool is_closed=false) { 05813 return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed); 05814 } 05815 05816 //! In-place version of the constructor. 05817 CImgDisplay& assign(const CImgDisplay &disp) { 05818 return assign(disp._width,disp._height); 05819 } 05820 05821 #endif 05822 05823 //! Return a reference to an empty display. 05824 static CImgDisplay& empty() { 05825 static CImgDisplay _empty; 05826 return _empty.assign(); 05827 } 05828 05829 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true) 05830 static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, 05831 const int dmin=128, const int dmax=-85,const bool return_last=false) { 05832 unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0); 05833 const unsigned int 05834 sw = CImgDisplay::screen_width(), sh = CImgDisplay::screen_height(), 05835 mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin, 05836 mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin, 05837 Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax, 05838 Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax; 05839 if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0?1:0); nw = mw; } 05840 if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0?1:0); nh = mh; } 05841 if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0?1:0); nw = Mw; } 05842 if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0?1:0); nh = Mh; } 05843 if (nw<mw) nw = mw; 05844 if (nh<mh) nh = mh; 05845 if (return_last) return nh; 05846 return nw; 05847 } 05848 05849 //@} 05850 //------------------------------------------ 05851 // 05852 //! \name Overloaded Operators 05853 //@{ 05854 //------------------------------------------ 05855 05856 // Operator=(). 05857 template<typename t> 05858 CImgDisplay& operator=(const CImg<t>& img) { 05859 return display(img); 05860 } 05861 05862 // Operator=(). 05863 template<typename t> 05864 CImgDisplay& operator=(const CImgList<t>& list) { 05865 return display(list); 05866 } 05867 05868 //! Operator=(). 05869 CImgDisplay& operator=(const CImgDisplay& disp) { 05870 return assign(disp); 05871 } 05872 05873 //! Return true if display is not empty. 05874 operator bool() const { 05875 return !is_empty(); 05876 } 05877 05878 //@} 05879 //------------------------------------------ 05880 // 05881 //! \name Instance Checking 05882 //@{ 05883 //------------------------------------------ 05884 05885 //! Return true is display is empty. 05886 bool is_empty() const { 05887 return !(_width && _height); 05888 } 05889 05890 bool is_closed() const { 05891 return _is_closed; 05892 } 05893 05894 bool is_resized() const { 05895 return _is_resized; 05896 } 05897 05898 bool is_moved() const { 05899 return _is_moved; 05900 } 05901 05902 bool is_event() const { 05903 return _is_event; 05904 } 05905 05906 bool is_fullscreen() const { 05907 return _is_fullscreen; 05908 } 05909 05910 bool is_key() const { 05911 return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 || 05912 _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 || 05913 _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 || 05914 _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 || 05915 _is_key3 || _is_key4 || _is_key5 || _is_key6 || 05916 _is_key7 || _is_key8 || _is_key9 || _is_key0 || 05917 _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME || 05918 _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW || 05919 _is_keyE || _is_keyR || _is_keyT || _is_keyY || 05920 _is_keyU || _is_keyI || _is_keyO || _is_keyP || 05921 _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN || 05922 _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD || 05923 _is_keyF || _is_keyG || _is_keyH || _is_keyJ || 05924 _is_keyK || _is_keyL || _is_keyENTER || 05925 _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC || 05926 _is_keyV || _is_keyB || _is_keyN || _is_keyM || 05927 _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT || 05928 _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR || 05929 _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT || 05930 _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT || 05931 _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 || 05932 _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 || 05933 _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 || 05934 _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB || 05935 _is_keyPADMUL || _is_keyPADDIV; 05936 } 05937 05938 #define _cimg_iskey_def(k) \ 05939 bool is_key##k() const { \ 05940 return _is_key##k; \ 05941 } 05942 _cimg_iskey_def(ESC); _cimg_iskey_def(F1); _cimg_iskey_def(F2); _cimg_iskey_def(F3); 05943 _cimg_iskey_def(F4); _cimg_iskey_def(F5); _cimg_iskey_def(F6); _cimg_iskey_def(F7); 05944 _cimg_iskey_def(F8); _cimg_iskey_def(F9); _cimg_iskey_def(F10); _cimg_iskey_def(F11); 05945 _cimg_iskey_def(F12); _cimg_iskey_def(PAUSE); _cimg_iskey_def(1); _cimg_iskey_def(2); 05946 _cimg_iskey_def(3); _cimg_iskey_def(4); _cimg_iskey_def(5); _cimg_iskey_def(6); 05947 _cimg_iskey_def(7); _cimg_iskey_def(8); _cimg_iskey_def(9); _cimg_iskey_def(0); 05948 _cimg_iskey_def(BACKSPACE); _cimg_iskey_def(INSERT); _cimg_iskey_def(HOME); 05949 _cimg_iskey_def(PAGEUP); _cimg_iskey_def(TAB); _cimg_iskey_def(Q); _cimg_iskey_def(W); 05950 _cimg_iskey_def(E); _cimg_iskey_def(R); _cimg_iskey_def(T); _cimg_iskey_def(Y); 05951 _cimg_iskey_def(U); _cimg_iskey_def(I); _cimg_iskey_def(O); _cimg_iskey_def(P); 05952 _cimg_iskey_def(DELETE); _cimg_iskey_def(END); _cimg_iskey_def(PAGEDOWN); 05953 _cimg_iskey_def(CAPSLOCK); _cimg_iskey_def(A); _cimg_iskey_def(S); _cimg_iskey_def(D); 05954 _cimg_iskey_def(F); _cimg_iskey_def(G); _cimg_iskey_def(H); _cimg_iskey_def(J); 05955 _cimg_iskey_def(K); _cimg_iskey_def(L); _cimg_iskey_def(ENTER); 05956 _cimg_iskey_def(SHIFTLEFT); _cimg_iskey_def(Z); _cimg_iskey_def(X); _cimg_iskey_def(C); 05957 _cimg_iskey_def(V); _cimg_iskey_def(B); _cimg_iskey_def(N); _cimg_iskey_def(M); 05958 _cimg_iskey_def(SHIFTRIGHT); _cimg_iskey_def(ARROWUP); _cimg_iskey_def(CTRLLEFT); 05959 _cimg_iskey_def(APPLEFT); _cimg_iskey_def(ALT); _cimg_iskey_def(SPACE); _cimg_iskey_def(ALTGR); 05960 _cimg_iskey_def(APPRIGHT); _cimg_iskey_def(MENU); _cimg_iskey_def(CTRLRIGHT); 05961 _cimg_iskey_def(ARROWLEFT); _cimg_iskey_def(ARROWDOWN); _cimg_iskey_def(ARROWRIGHT); 05962 _cimg_iskey_def(PAD0); _cimg_iskey_def(PAD1); _cimg_iskey_def(PAD2); 05963 _cimg_iskey_def(PAD3); _cimg_iskey_def(PAD4); _cimg_iskey_def(PAD5); 05964 _cimg_iskey_def(PAD6); _cimg_iskey_def(PAD7); _cimg_iskey_def(PAD8); 05965 _cimg_iskey_def(PAD9); _cimg_iskey_def(PADADD); _cimg_iskey_def(PADSUB); 05966 _cimg_iskey_def(PADMUL); _cimg_iskey_def(PADDIV); 05967 05968 bool is_key(const unsigned int key) const { 05969 #define _cimg_iskey_test(k) if (key==cimg::key##k) return _is_key##k; 05970 _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3); 05971 _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7); 05972 _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11); 05973 _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2); 05974 _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6); 05975 _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0); 05976 _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME); 05977 _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W); 05978 _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y); 05979 _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P); 05980 _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN); 05981 _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D); 05982 _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J); 05983 _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER); 05984 _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C); 05985 _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M); 05986 _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT); 05987 _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR); 05988 _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT); 05989 _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT); 05990 _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2); 05991 _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5); 05992 _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8); 05993 _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB); 05994 _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV); 05995 return false; 05996 } 05997 05998 //! Get keycode corresponding to given input string. 05999 bool is_key(const char *const textcode) const { 06000 #define _cimg_iskey_test2(k) if (!cimg::strcasecmp(textcode,#k)) return _is_key##k; 06001 _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3); 06002 _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7); 06003 _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11); 06004 _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2); 06005 _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6); 06006 _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0); 06007 _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME); 06008 _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W); 06009 _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y); 06010 _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P); 06011 _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN); 06012 _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D); 06013 _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J); 06014 _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER); 06015 _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C); 06016 _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M); 06017 _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT); 06018 _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR); 06019 _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT); 06020 _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT); 06021 _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2); 06022 _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5); 06023 _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8); 06024 _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB); 06025 _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV); 06026 return false; 06027 } 06028 06029 //! Test if a key sequence has been typed. 06030 bool is_key_sequence(const unsigned int *const key_sequence, const unsigned int length, const bool remove_sequence=false) { 06031 if (key_sequence && length) { 06032 const unsigned int 06033 *const ps_end = key_sequence + length - 1, 06034 *const pk_end = (unsigned int*)_keys + 1 + sizeof(_keys)/sizeof(unsigned int) - length, 06035 k = *ps_end; 06036 for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) { 06037 if (*(pk++)==k) { 06038 bool res = true; 06039 const unsigned int *ps = ps_end, *pk2 = pk; 06040 for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++)); 06041 if (res) { 06042 if (remove_sequence) std::memset((void*)(pk-1),0,sizeof(unsigned int)*length); 06043 return true; 06044 } 06045 } 06046 } 06047 } 06048 return false; 06049 } 06050 06051 //@} 06052 //------------------------------------------ 06053 // 06054 //! \name Instance Characteristics 06055 //@{ 06056 //------------------------------------------ 06057 06058 //! Return display width. 06059 int width() const { 06060 return (int)_width; 06061 } 06062 06063 //! Return display height. 06064 int height() const { 06065 return (int)_height; 06066 } 06067 06068 //! Return X-coordinate of the mouse pointer. 06069 int mouse_x() const { 06070 return _mouse_x; 06071 } 06072 06073 //! Return Y-coordinate of the mouse pointer. 06074 int mouse_y() const { 06075 return _mouse_y; 06076 } 06077 06078 //! Return current or previous state of the mouse buttons. 06079 unsigned int button() const { 06080 return _button; 06081 } 06082 06083 //! Return current state of the mouse wheel. 06084 int wheel() const { 06085 return _wheel; 06086 } 06087 06088 //! Return current or previous state of the keyboard. 06089 unsigned int key(const unsigned int pos=0) const { 06090 return pos<(sizeof(_keys)/sizeof(unsigned int))?_keys[pos]:0; 06091 } 06092 06093 unsigned int released_key(const unsigned int pos=0) const { 06094 return pos<(sizeof(_released_keys)/sizeof(unsigned int))?_released_keys[pos]:0; 06095 } 06096 06097 //! Get keycode corresponding to given input string. 06098 static unsigned int keycode(const char *const textcode) { 06099 #define _cimg_keycode(k) if (!cimg::strcasecmp(textcode,#k)) return cimg::key##k; 06100 _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3); 06101 _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7); 06102 _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11); 06103 _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2); 06104 _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6); 06105 _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0); 06106 _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME); 06107 _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W); 06108 _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y); 06109 _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P); 06110 _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN); 06111 _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D); 06112 _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J); 06113 _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER); 06114 _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C); 06115 _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M); 06116 _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT); 06117 _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR); 06118 _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT); 06119 _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT); 06120 _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2); 06121 _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5); 06122 _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8); 06123 _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB); 06124 _cimg_keycode(PADMUL); _cimg_keycode(PADDIV); 06125 return 0; 06126 } 06127 06128 //! Return normalization type of the display. 06129 unsigned int normalization() const { 06130 return _normalization; 06131 } 06132 06133 //! Return title of the display. 06134 const char *title() const { 06135 return _title; 06136 } 06137 06138 //! Return display window width. 06139 int window_width() const { 06140 return (int)_window_width; 06141 } 06142 06143 //! Return display window height. 06144 int window_height() const { 06145 return (int)_window_height; 06146 } 06147 06148 //! Return X-coordinate of the window. 06149 int window_x() const { 06150 return _window_x; 06151 } 06152 06153 //! Return Y-coordinate of the window. 06154 int window_y() const { 06155 return _window_y; 06156 } 06157 06158 #if cimg_display==0 06159 06160 //! Return the width of the screen resolution. 06161 static int screen_width() { 06162 _no_display_exception(); 06163 return 0; 06164 } 06165 06166 //! Return the height of the screen resolution. 06167 static int screen_height() { 06168 _no_display_exception(); 06169 return 0; 06170 } 06171 06172 #endif 06173 06174 //! Return the frame per second rate. 06175 float frames_per_second() { 06176 if (!_fps_timer) _fps_timer = cimg::time(); 06177 const float delta = (cimg::time()-_fps_timer)/1000.0f; 06178 ++_fps_frames; 06179 if (delta>=1) { 06180 _fps_fps = _fps_frames/delta; 06181 _fps_frames = 0; 06182 _fps_timer = cimg::time(); 06183 } 06184 return _fps_fps; 06185 } 06186 06187 //@} 06188 //------------------------------------------ 06189 // 06190 //! \name Display Manipulation 06191 //@{ 06192 //------------------------------------------ 06193 06194 #if cimg_display==0 06195 06196 //! Display an image in a window. 06197 template<typename T> 06198 CImgDisplay& display(const CImg<T>& img) { 06199 return assign(img); 06200 } 06201 06202 #endif 06203 06204 //! Display an image list CImgList<T> into a display window. 06205 /** First, all images of the list are appended into a single image used for visualization, 06206 then this image is displayed in the current display window. 06207 \param list : The list of images to display. 06208 \param axis : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'c'. 06209 \param align : Defines the relative alignment of images when displaying images of different sizes. 06210 Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment). 06211 **/ 06212 template<typename T> 06213 CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') { 06214 return display(list.get_append(axis,align)); 06215 } 06216 06217 //! Resize a display window in its current size. 06218 CImgDisplay& resize(const bool redraw=true) { 06219 resize(_window_width,_window_height,redraw); 06220 return *this; 06221 } 06222 06223 //! Resize a display window with the size of an image. 06224 /** \param img : Input image. \p image.width and \p image.height give the new dimensions of the display window. 06225 \param redraw : If \p true (default), the current displayed image in the display window will 06226 be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window. 06227 **/ 06228 template<typename T> 06229 CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) { 06230 return resize(img._width,img._height,redraw); 06231 } 06232 06233 //! Resize a display window using the size of the given display \p disp. 06234 CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) { 06235 return resize(disp._width,disp._height,redraw); 06236 } 06237 06238 #if cimg_display==0 06239 06240 //! Resize window. 06241 CImgDisplay& resize(const int width, const int height, const bool redraw=true) { 06242 return assign(width,height,0,3,redraw); 06243 } 06244 06245 #endif 06246 06247 // Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs). 06248 template<typename t, typename T> 06249 static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, 06250 t *ptrd, const unsigned int wd, const unsigned int hd) { 06251 unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy; 06252 float s, curr, old; 06253 s = (float)ws/wd; 06254 poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) { old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old; } 06255 s = (float)hs/hd; 06256 poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) { old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old); } 06257 *poffy = 0; 06258 poffy = offy; 06259 for (unsigned int y = 0; y<hd; ) { 06260 const T *ptr = ptrs; 06261 poffx = offx; 06262 for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); } 06263 ++y; 06264 unsigned int dy = *(poffy++); 06265 for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poffy++)) {} 06266 ptrs+=dy; 06267 } 06268 delete[] offx; delete[] offy; 06269 } 06270 06271 //! Set fullscreen mode. 06272 CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool redraw=true) { 06273 if (is_empty() || _is_fullscreen==is_fullscreen) return *this; 06274 return toggle_fullscreen(redraw); 06275 } 06276 06277 #if cimg_display==0 06278 06279 //! Toggle fullscreen mode. 06280 CImgDisplay& toggle_fullscreen(const bool redraw=true) { 06281 return assign(_width,_height,0,3,redraw); 06282 } 06283 06284 //! Show a closed display. 06285 CImgDisplay& show() { 06286 return assign(); 06287 } 06288 06289 //! Close a visible display. 06290 CImgDisplay& close() { 06291 return assign(); 06292 } 06293 06294 //! Move window. 06295 CImgDisplay& move(const int pos_x, const int pos_y) { 06296 return assign(pos_x,pos_y); 06297 } 06298 06299 //! Show mouse pointer. 06300 CImgDisplay& show_mouse() { 06301 return assign(); 06302 } 06303 06304 //! Hide mouse pointer. 06305 CImgDisplay& hide_mouse() { 06306 return assign(); 06307 } 06308 06309 //! Move mouse pointer to a specific location. 06310 CImgDisplay& set_mouse(const int pos_x, const int pos_y) { 06311 return assign(pos_x,pos_y); 06312 } 06313 06314 //! Set the window title. 06315 CImgDisplay& set_title(const char *const format, ...) { 06316 return assign(0,0,format); 06317 } 06318 06319 //! Render image buffer into GDI native image format. 06320 template<typename T> 06321 CImgDisplay& render(const CImg<T>& img) { 06322 return assign(img); 06323 } 06324 06325 //! Re-paint image content in window. 06326 CImgDisplay& paint() { 06327 return assign(); 06328 } 06329 06330 //! Take a snapshot of the display in the specified image. 06331 template<typename T> 06332 const CImgDisplay& snapshot(CImg<T>& img) const { 06333 _no_display_exception(); 06334 return *this; 06335 } 06336 #endif 06337 06338 //! Simulate a mouse button event. 06339 CImgDisplay& set_button() { 06340 _button = 0; 06341 _is_event = true; 06342 return *this; 06343 } 06344 06345 CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) { 06346 const unsigned int buttoncode = button==1?1:button==2?2:button==3?4:0; 06347 if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode; 06348 _is_event = buttoncode?true:false; 06349 return *this; 06350 } 06351 06352 //! Simulate a mouse wheel event, or flush wheel events. 06353 CImgDisplay& set_wheel() { 06354 _wheel = 0; 06355 _is_event = true; 06356 return *this; 06357 } 06358 06359 CImgDisplay& set_wheel(const int amplitude) { 06360 _wheel+=amplitude; 06361 _is_event = amplitude?true:false; 06362 return *this; 06363 } 06364 06365 //! Simulate a keyboard press/release event, or flush all key events. 06366 CImgDisplay& set_key() { 06367 std::memset((void*)_keys,0,sizeof(_keys)); 06368 std::memset((void*)_released_keys,0,sizeof(_released_keys)); 06369 _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 = _is_keyF9 = 06370 _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 = _is_key5 = _is_key6 = 06371 _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT = _is_keyHOME = _is_keyPAGEUP = _is_keyTAB = 06372 _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY = _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE = 06373 _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK = _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ = 06374 _is_keyK = _is_keyL = _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN = 06375 _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE = _is_keyALTGR = _is_keyAPPRIGHT = 06376 _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN = _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 = 06377 _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 = _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB = 06378 _is_keyPADMUL = _is_keyPADDIV = false; 06379 _is_event = true; 06380 return *this; 06381 } 06382 06383 CImgDisplay& set_key(const unsigned int keycode, const bool pressed=true) { 06384 #define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = pressed; 06385 _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3); 06386 _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7); 06387 _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11); 06388 _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2); 06389 _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6); 06390 _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0); 06391 _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME); 06392 _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W); 06393 _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y); 06394 _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P); 06395 _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN); 06396 _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D); 06397 _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J); 06398 _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER); 06399 _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C); 06400 _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M); 06401 _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT); 06402 _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR); 06403 _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT); 06404 _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT); 06405 _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2); 06406 _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5); 06407 _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8); 06408 _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB); 06409 _cimg_set_key(PADMUL); _cimg_set_key(PADDIV); 06410 if (pressed) { 06411 if (*_keys) 06412 std::memmove((void*)(_keys+1),(void*)_keys,sizeof(_keys) - sizeof(unsigned int)); 06413 *_keys = keycode; 06414 if (*_released_keys) { 06415 std::memmove((void*)(_released_keys+1),(void*)_released_keys,sizeof(_released_keys) - sizeof(unsigned int)); 06416 *_released_keys = 0; 06417 } 06418 } else { 06419 if (*_keys) { 06420 std::memmove((void*)(_keys+1),(void*)_keys,sizeof(_keys) - sizeof(unsigned int)); 06421 *_keys = 0; 06422 } 06423 if (*_released_keys) 06424 std::memmove((void*)(_released_keys+1),(void*)_released_keys,sizeof(_released_keys) - sizeof(unsigned int)); 06425 *_released_keys = keycode; 06426 } 06427 _is_event = keycode?true:false; 06428 return *this; 06429 } 06430 06431 //! Flush all display events. 06432 CImgDisplay& flush() { 06433 set_key().set_button().set_wheel(); 06434 _is_resized = _is_moved = _is_event = false; 06435 _fps_timer = _fps_frames = _timer = 0; 06436 _fps_fps = 0; 06437 return *this; 06438 } 06439 06440 //! Synchronized waiting function. Same as cimg::wait(). 06441 CImgDisplay& wait(const unsigned int milliseconds) { 06442 cimg::_sleep(milliseconds,_timer); 06443 return *this; 06444 } 06445 06446 //! Wait for an event occuring on the current display. 06447 CImgDisplay& wait() { 06448 if (!is_empty()) wait(*this); 06449 return *this; 06450 } 06451 06452 //! Wait for any event occuring on the display \c disp1. 06453 static void wait(CImgDisplay& disp1) { 06454 disp1._is_event = 0; 06455 while (!disp1._is_event) wait_all(); 06456 } 06457 06458 //! Wait for any event occuring either on the display \c disp1 or \c disp2. 06459 static void wait(CImgDisplay& disp1, CImgDisplay& disp2) { 06460 disp1._is_event = disp2._is_event = 0; 06461 while (!disp1._is_event && !disp2._is_event) wait_all(); 06462 } 06463 06464 //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3. 06465 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) { 06466 disp1._is_event = disp2._is_event = disp3._is_event = 0; 06467 while (!disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all(); 06468 } 06469 06470 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4. 06471 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) { 06472 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = 0; 06473 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all(); 06474 } 06475 06476 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4 or \c disp5. 06477 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5) { 06478 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 0; 06479 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event) wait_all(); 06480 } 06481 06482 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp6. 06483 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, 06484 CImgDisplay& disp6) { 06485 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 06486 disp6._is_event = 0; 06487 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && 06488 !disp6._is_event) wait_all(); 06489 } 06490 06491 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp7. 06492 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, 06493 CImgDisplay& disp6, CImgDisplay& disp7) { 06494 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 06495 disp6._is_event = disp7._is_event = 0; 06496 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && 06497 !disp6._is_event && !disp7._is_event) wait_all(); 06498 } 06499 06500 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp8. 06501 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, 06502 CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) { 06503 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 06504 disp6._is_event = disp7._is_event = disp8._is_event = 0; 06505 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && 06506 !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all(); 06507 } 06508 06509 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp9. 06510 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, 06511 CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) { 06512 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 06513 disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = 0; 06514 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && 06515 !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all(); 06516 } 06517 06518 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp10. 06519 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, 06520 CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9, CImgDisplay& disp10) { 06521 disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 06522 disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = 0; 06523 while (!disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && 06524 !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event) wait_all(); 06525 } 06526 06527 #if cimg_display==0 06528 06529 //! Wait for a window event in any CImg window. 06530 static void wait_all() { 06531 return _no_display_exception(); 06532 } 06533 06534 #endif 06535 06536 // X11-based implementation 06537 //-------------------------- 06538 #if cimg_display==1 06539 06540 Atom _wm_window_atom, _wm_protocol_atom; 06541 Window _window, _background_window; 06542 Colormap _colormap; 06543 XImage *_image; 06544 void *_data; 06545 #ifdef cimg_use_xshm 06546 XShmSegmentInfo *_shminfo; 06547 #endif 06548 06549 static int screen_width() { 06550 int res = 0; 06551 if (!cimg::X11_attr().display) { 06552 Display *disp = XOpenDisplay((std::getenv("DISPLAY")?std::getenv("DISPLAY"):":0.0")); 06553 if (!disp) 06554 throw CImgDisplayException("CImgDisplay::screen_width() : Failed to open X11 display."); 06555 res = DisplayWidth(disp,DefaultScreen(disp)); 06556 XCloseDisplay(disp); 06557 } else { 06558 #ifdef cimg_use_xrandr 06559 if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) 06560 res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width; 06561 else 06562 #endif 06563 res = DisplayWidth(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)); 06564 } 06565 return res; 06566 } 06567 06568 static int screen_height() { 06569 int res = 0; 06570 if (!cimg::X11_attr().display) { 06571 Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); 06572 if (!disp) 06573 throw CImgDisplayException("CImgDisplay::screen_height() : Failed to open X11 display."); 06574 res = DisplayHeight(disp,DefaultScreen(disp)); 06575 XCloseDisplay(disp); 06576 } else { 06577 #ifdef cimg_use_xrandr 06578 if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) 06579 res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height; 06580 else 06581 #endif 06582 res = DisplayHeight(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)); 06583 } 06584 return res; 06585 } 06586 06587 static void wait_all() { 06588 if (cimg::X11_attr().display) { 06589 XLockDisplay(cimg::X11_attr().display); 06590 bool flag = true; 06591 XEvent event; 06592 while (flag) { 06593 XNextEvent(cimg::X11_attr().display, &event); 06594 for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i) 06595 if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) { 06596 cimg::X11_attr().wins[i]->_handle_events(&event); 06597 if (cimg::X11_attr().wins[i]->_is_event) flag = false; 06598 } 06599 } 06600 XUnlockDisplay(cimg::X11_attr().display); 06601 } 06602 } 06603 06604 void _handle_events(const XEvent *const pevent) { 06605 XEvent event = *pevent; 06606 switch (event.type) { 06607 case ClientMessage : { 06608 if ((int)event.xclient.message_type==(int)_wm_protocol_atom && 06609 (int)event.xclient.data.l[0]==(int)_wm_window_atom) { 06610 XUnmapWindow(cimg::X11_attr().display,_window); 06611 _is_closed = _is_event = true; 06612 } 06613 } break; 06614 case ConfigureNotify : { 06615 while (XCheckWindowEvent(cimg::X11_attr().display,_window,StructureNotifyMask,&event)) {} 06616 const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height; 06617 const int nx = event.xconfigure.x, ny = event.xconfigure.y; 06618 if (nw && nh && (nw!=_window_width || nh!=_window_height)) { 06619 _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1; 06620 XResizeWindow(cimg::X11_attr().display,_window,_window_width,_window_height); 06621 _is_resized = _is_event = true; 06622 } 06623 if (nx!=_window_x || ny!=_window_y) { _window_x = nx; _window_y = ny; _is_moved = _is_event = true; } 06624 } break; 06625 case Expose : { 06626 while (XCheckWindowEvent(cimg::X11_attr().display,_window,ExposureMask,&event)) {} 06627 _paint(false); 06628 if (_is_fullscreen) { 06629 XWindowAttributes attr; 06630 XGetWindowAttributes(cimg::X11_attr().display,_window,&attr); 06631 while (attr.map_state!=IsViewable) XSync(cimg::X11_attr().display,False); 06632 XSetInputFocus(cimg::X11_attr().display,_window,RevertToParent,CurrentTime); 06633 } 06634 } break; 06635 case ButtonPress : { 06636 do { 06637 _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; 06638 if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; 06639 switch (event.xbutton.button) { 06640 case 1 : set_button(1); break; 06641 case 3 : set_button(2); break; 06642 case 2 : set_button(3); break; 06643 } 06644 } while (XCheckWindowEvent(cimg::X11_attr().display,_window,ButtonPressMask,&event)); 06645 } break; 06646 case ButtonRelease : { 06647 do { 06648 _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; 06649 if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; 06650 switch (event.xbutton.button) { 06651 case 1 : set_button(1,false); break; 06652 case 3 : set_button(2,false); break; 06653 case 2 : set_button(3,false); break; 06654 case 4 : set_wheel(1); break; 06655 case 5 : set_wheel(-1); break; 06656 } 06657 } while (XCheckWindowEvent(cimg::X11_attr().display,_window,ButtonReleaseMask,&event)); 06658 } break; 06659 case KeyPress : { 06660 char tmp = 0; KeySym ksym; 06661 XLookupString(&event.xkey,&tmp,1,&ksym,0); 06662 set_key((unsigned int)ksym,true); 06663 } break; 06664 case KeyRelease : { 06665 char tmp = 0; KeySym ksym; 06666 XLookupString(&event.xkey,&tmp,1,&ksym,0); 06667 set_key((unsigned int)ksym,false); 06668 } break; 06669 case EnterNotify: { 06670 while (XCheckWindowEvent(cimg::X11_attr().display,_window,EnterWindowMask,&event)) {} 06671 _mouse_x = event.xmotion.x; 06672 _mouse_y = event.xmotion.y; 06673 if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; 06674 } break; 06675 case LeaveNotify : { 06676 while (XCheckWindowEvent(cimg::X11_attr().display,_window,LeaveWindowMask,&event)) {} 06677 _mouse_x = _mouse_y =-1; _is_event = true; 06678 } break; 06679 case MotionNotify : { 06680 while (XCheckWindowEvent(cimg::X11_attr().display,_window,PointerMotionMask,&event)) {} 06681 _mouse_x = event.xmotion.x; 06682 _mouse_y = event.xmotion.y; 06683 if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; 06684 _is_event = true; 06685 } break; 06686 } 06687 } 06688 06689 static void* _events_thread(void *arg) { 06690 arg = 0; 06691 XEvent event; 06692 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); 06693 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); 06694 for (;;) { 06695 XLockDisplay(cimg::X11_attr().display); 06696 bool event_flag = XCheckTypedEvent(cimg::X11_attr().display,ClientMessage,&event); 06697 if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11_attr().display, 06698 ExposureMask | StructureNotifyMask | ButtonPressMask| 06699 KeyPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask| 06700 ButtonReleaseMask | KeyReleaseMask,&event); 06701 if (event_flag) for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i) 06702 if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) 06703 cimg::X11_attr().wins[i]->_handle_events(&event); 06704 XUnlockDisplay(cimg::X11_attr().display); 06705 pthread_testcancel(); 06706 cimg::sleep(8); 06707 } 06708 return 0; 06709 } 06710 06711 void _set_colormap(Colormap& colormap, const unsigned int dim) { 06712 XColor palette[256]; 06713 switch (dim) { 06714 case 1 : { // palette for greyscale images 06715 for (unsigned int index = 0; index<256; ++index) { 06716 palette[index].pixel = index; 06717 palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8); 06718 palette[index].flags = DoRed | DoGreen | DoBlue; 06719 } 06720 } break; 06721 case 2 : { // palette for RG images 06722 for (unsigned int index = 0, r = 8; r<256; r+=16) 06723 for (unsigned int g = 8; g<256; g+=16) { 06724 palette[index].pixel = index; 06725 palette[index].red = palette[index].blue = (unsigned short)(r<<8); 06726 palette[index].green = (unsigned short)(g<<8); 06727 palette[index++].flags = DoRed | DoGreen | DoBlue; 06728 } 06729 } break; 06730 default : { // palette for RGB images 06731 for (unsigned int index = 0, r = 16; r<256; r+=32) 06732 for (unsigned int g = 16; g<256; g+=32) 06733 for (unsigned int b = 32; b<256; b+=64) { 06734 palette[index].pixel = index; 06735 palette[index].red = (unsigned short)(r<<8); 06736 palette[index].green = (unsigned short)(g<<8); 06737 palette[index].blue = (unsigned short)(b<<8); 06738 palette[index++].flags = DoRed | DoGreen | DoBlue; 06739 } 06740 } 06741 } 06742 XStoreColors(cimg::X11_attr().display,colormap,palette,256); 06743 } 06744 06745 void _map_window() { 06746 XWindowAttributes attr; 06747 XEvent event; 06748 bool exposed = false, mapped = false; 06749 XMapRaised(cimg::X11_attr().display,_window); 06750 XSync(cimg::X11_attr().display,False); 06751 do { 06752 XWindowEvent(cimg::X11_attr().display,_window,StructureNotifyMask | ExposureMask,&event); 06753 switch (event.type) { 06754 case MapNotify : mapped = true; break; 06755 case Expose : exposed = true; break; 06756 default : XSync(cimg::X11_attr().display, False); cimg::sleep(10); 06757 } 06758 } while (!(exposed && mapped)); 06759 do { 06760 XGetWindowAttributes(cimg::X11_attr().display, _window, &attr); 06761 if (attr.map_state!=IsViewable) { XSync(cimg::X11_attr().display,False); cimg::sleep(10); } 06762 } while (attr.map_state != IsViewable); 06763 _window_x = attr.x; 06764 _window_y = attr.y; 06765 } 06766 06767 void _paint(const bool wait_expose=true) { 06768 if (!_is_closed) { 06769 if (wait_expose) { 06770 static XEvent event; 06771 event.xexpose.type = Expose; 06772 event.xexpose.serial = 0; 06773 event.xexpose.send_event = True; 06774 event.xexpose.display = cimg::X11_attr().display; 06775 event.xexpose.window = _window; 06776 event.xexpose.x = 0; 06777 event.xexpose.y = 0; 06778 event.xexpose.width = width(); 06779 event.xexpose.height = height(); 06780 event.xexpose.count = 0; 06781 XSendEvent(cimg::X11_attr().display, _window, False, 0, &event); 06782 } else { 06783 #ifdef cimg_use_xshm 06784 if (_shminfo) XShmPutImage(cimg::X11_attr().display,_window,*cimg::X11_attr().gc,_image,0,0,0,0,_width,_height,False); 06785 else 06786 #endif 06787 XPutImage(cimg::X11_attr().display,_window,*cimg::X11_attr().gc,_image,0,0,0,0,_width,_height); 06788 XSync(cimg::X11_attr().display, False); 06789 } 06790 } 06791 } 06792 06793 template<typename T> 06794 void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) { 06795 foo = 0; 06796 #ifdef cimg_use_xshm 06797 if (_shminfo) { 06798 XShmSegmentInfo *const nshminfo = new XShmSegmentInfo; 06799 XImage *const nimage = XShmCreateImage(cimg::X11_attr().display,DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 06800 cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy); 06801 if (!nimage) { delete nshminfo; return; } 06802 else { 06803 nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777); 06804 if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; } 06805 else { 06806 nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0); 06807 if (nshminfo->shmaddr==(char*)-1) { shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; } 06808 else { 06809 nshminfo->readOnly = False; 06810 cimg::X11_attr().shm_enabled = true; 06811 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); 06812 XShmAttach(cimg::X11_attr().display, nshminfo); 06813 XSync(cimg::X11_attr().display, False); 06814 XSetErrorHandler(oldXErrorHandler); 06815 if (!cimg::X11_attr().shm_enabled) { 06816 shmdt(nshminfo->shmaddr); 06817 shmctl(nshminfo->shmid,IPC_RMID,0); 06818 XDestroyImage(nimage); 06819 delete nshminfo; 06820 return; 06821 } else { 06822 T *const ndata = (T*)nimage->data; 06823 if (redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); 06824 else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); 06825 XShmDetach(cimg::X11_attr().display, _shminfo); 06826 XDestroyImage(_image); 06827 shmdt(_shminfo->shmaddr); 06828 shmctl(_shminfo->shmid,IPC_RMID,0); 06829 delete _shminfo; 06830 _shminfo = nshminfo; 06831 _image = nimage; 06832 _data = (void*)ndata; 06833 } 06834 } 06835 } 06836 } 06837 } else 06838 #endif 06839 { 06840 T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T)); 06841 if (redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); 06842 else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); 06843 _data = (void*)ndata; 06844 XDestroyImage(_image); 06845 _image = XCreateImage(cimg::X11_attr().display,DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 06846 cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0); 06847 } 06848 } 06849 06850 void _init_fullscreen() { 06851 _background_window = 0; 06852 if (_is_fullscreen && !_is_closed) { 06853 #ifdef cimg_use_xrandr 06854 int foo; 06855 if (XRRQueryExtension(cimg::X11_attr().display,&foo,&foo)) { 06856 XRRRotations(cimg::X11_attr().display, DefaultScreen(cimg::X11_attr().display), &cimg::X11_attr().curr_rotation); 06857 if (!cimg::X11_attr().resolutions) { 06858 cimg::X11_attr().resolutions = XRRSizes(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display),&foo); 06859 cimg::X11_attr().nb_resolutions = (unsigned int)foo; 06860 } 06861 if (cimg::X11_attr().resolutions) { 06862 cimg::X11_attr().curr_resolution = 0; 06863 for (unsigned int i = 0; i<cimg::X11_attr().nb_resolutions; ++i) { 06864 const unsigned int 06865 nw = (unsigned int)(cimg::X11_attr().resolutions[i].width), 06866 nh = (unsigned int)(cimg::X11_attr().resolutions[i].height); 06867 if (nw>=_width && nh>=_height && 06868 nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) && 06869 nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height)) 06870 cimg::X11_attr().curr_resolution = i; 06871 } 06872 if (cimg::X11_attr().curr_resolution>0) { 06873 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11_attr().display, DefaultRootWindow(cimg::X11_attr().display)); 06874 XRRSetScreenConfig(cimg::X11_attr().display, config, DefaultRootWindow(cimg::X11_attr().display), 06875 cimg::X11_attr().curr_resolution, cimg::X11_attr().curr_rotation, CurrentTime); 06876 XRRFreeScreenConfigInfo(config); 06877 XSync(cimg::X11_attr().display, False); 06878 } 06879 } 06880 } 06881 if (!cimg::X11_attr().resolutions) 06882 cimg::warn(_cimgdisplay_instance 06883 "_create_window() : Xrandr extension is not supported by the X server.", 06884 cimgdisplay_instance); 06885 #endif 06886 const unsigned int sx = screen_width(), sy = screen_height(); 06887 XSetWindowAttributes winattr; 06888 winattr.override_redirect = True; 06889 if (sx!=_width || sy!=_height) { 06890 _background_window = XCreateWindow(cimg::X11_attr().display, 06891 RootWindow(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)),0,0, 06892 sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); 06893 const unsigned int bufsize = sx*sy*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4)); 06894 void *background_data = std::malloc(bufsize); 06895 std::memset(background_data,0,bufsize); 06896 XImage *background_image = XCreateImage(cimg::X11_attr().display,DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 06897 cimg::X11_attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0); 06898 XEvent event; 06899 XSelectInput(cimg::X11_attr().display,_background_window,StructureNotifyMask); 06900 XMapRaised(cimg::X11_attr().display,_background_window); 06901 do XWindowEvent(cimg::X11_attr().display,_background_window,StructureNotifyMask,&event); 06902 while (event.type!=MapNotify); 06903 #ifdef cimg_use_xshm 06904 if (_shminfo) XShmPutImage(cimg::X11_attr().display,_background_window,*cimg::X11_attr().gc,background_image,0,0,0,0,sx,sy,False); 06905 else 06906 #endif 06907 XPutImage(cimg::X11_attr().display,_background_window,*cimg::X11_attr().gc,background_image,0,0,0,0,sx,sy); 06908 XWindowAttributes attr; 06909 XGetWindowAttributes(cimg::X11_attr().display, _background_window, &attr); 06910 while (attr.map_state != IsViewable) XSync(cimg::X11_attr().display, False); 06911 XDestroyImage(background_image); 06912 } 06913 } 06914 } 06915 06916 void _desinit_fullscreen() { 06917 if (_is_fullscreen) { 06918 XUngrabKeyboard(cimg::X11_attr().display,CurrentTime); 06919 #ifdef cimg_use_xrandr 06920 if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) { 06921 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11_attr().display, DefaultRootWindow(cimg::X11_attr().display)); 06922 XRRSetScreenConfig(cimg::X11_attr().display, config, DefaultRootWindow(cimg::X11_attr().display), 06923 0, cimg::X11_attr().curr_rotation, CurrentTime); 06924 XRRFreeScreenConfigInfo(config); 06925 XSync(cimg::X11_attr().display, False); 06926 cimg::X11_attr().curr_resolution = 0; 06927 } 06928 #endif 06929 if (_background_window) XDestroyWindow(cimg::X11_attr().display,_background_window); 06930 _background_window = 0; 06931 _is_fullscreen = false; 06932 } 06933 } 06934 06935 static int _assign_xshm(Display *dpy, XErrorEvent *error) { 06936 dpy = 0; error = 0; 06937 cimg::X11_attr().shm_enabled = false; 06938 return 0; 06939 } 06940 06941 void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, 06942 const unsigned int normalization_type=3, 06943 const bool fullscreen_flag=false, const bool closed_flag=false) { 06944 06945 // Allocate space for window title 06946 const char *const nptitle = ptitle?ptitle:""; 06947 const unsigned int s = std::strlen(nptitle) + 1; 06948 char *const tmp_title = s?new char[s]:0; 06949 if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); 06950 06951 // Destroy previous display window if existing 06952 if (!is_empty()) assign(); 06953 06954 // Open X11 display if necessary. 06955 if (!cimg::X11_attr().display) { 06956 static bool xinit_threads = false; 06957 if (!xinit_threads) { XInitThreads(); xinit_threads = true; } 06958 cimg::X11_attr().nb_wins = 0; 06959 cimg::X11_attr().display = XOpenDisplay((std::getenv("DISPLAY")?std::getenv("DISPLAY"):":0.0")); 06960 if (!cimg::X11_attr().display) 06961 throw CImgDisplayException(_cimgdisplay_instance 06962 "assign() : Failed to open X11 display.", 06963 cimgdisplay_instance); 06964 06965 cimg::X11_attr().nb_bits = DefaultDepth(cimg::X11_attr().display, DefaultScreen(cimg::X11_attr().display)); 06966 if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 && cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32) 06967 throw CImgDisplayException(_cimgdisplay_instance 06968 "assign() : Invalid %u bits screen mode detected " 06969 "(only 8, 16, 24 and 32 bits modes are managed).", 06970 cimgdisplay_instance, 06971 cimg::X11_attr().nb_bits); 06972 06973 cimg::X11_attr().gc = new GC; 06974 *cimg::X11_attr().gc = DefaultGC(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)); 06975 Visual *visual = DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)); 06976 XVisualInfo vtemplate; 06977 vtemplate.visualid = XVisualIDFromVisual(visual); 06978 int nb_visuals; 06979 XVisualInfo *vinfo = XGetVisualInfo(cimg::X11_attr().display,VisualIDMask,&vtemplate,&nb_visuals); 06980 if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_attr().blue_first = true; 06981 cimg::X11_attr().byte_order = ImageByteOrder(cimg::X11_attr().display); 06982 XFree(vinfo); 06983 XLockDisplay(cimg::X11_attr().display); 06984 cimg::X11_attr().event_thread = new pthread_t; 06985 pthread_create(cimg::X11_attr().event_thread,0,_events_thread,0); 06986 } else XLockDisplay(cimg::X11_attr().display); 06987 06988 // Set display variables 06989 _width = cimg::min(dimw,(unsigned int)screen_width()); 06990 _height = cimg::min(dimh,(unsigned int)screen_height()); 06991 _normalization = normalization_type<4?normalization_type:3; 06992 _is_fullscreen = fullscreen_flag; 06993 _window_x = _window_y = 0; 06994 _is_closed = closed_flag; 06995 _title = tmp_title; 06996 flush(); 06997 06998 // Create X11 window (and LUT, if 8bits display) 06999 if (_is_fullscreen) { 07000 if (!_is_closed) _init_fullscreen(); 07001 const unsigned int sx = screen_width(), sy = screen_height(); 07002 XSetWindowAttributes winattr; 07003 winattr.override_redirect = True; 07004 _window = XCreateWindow(cimg::X11_attr().display, 07005 RootWindow(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 07006 (sx-_width)/2,(sy-_height)/2, 07007 _width,_height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); 07008 } else 07009 _window = XCreateSimpleWindow(cimg::X11_attr().display, 07010 RootWindow(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 07011 0,2,_width,_height,0,0,0x0L); 07012 XStoreName(cimg::X11_attr().display,_window,_title?_title:" "); 07013 if (cimg::X11_attr().nb_bits==8) { 07014 _colormap = XCreateColormap(cimg::X11_attr().display,_window,DefaultVisual(cimg::X11_attr().display, 07015 DefaultScreen(cimg::X11_attr().display)),AllocAll); 07016 _set_colormap(_colormap,3); 07017 XSetWindowColormap(cimg::X11_attr().display,_window,_colormap); 07018 } 07019 _window_width = _width; 07020 _window_height = _height; 07021 07022 // Create XImage 07023 const unsigned int bufsize = _width*_height*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4)); 07024 #ifdef cimg_use_xshm 07025 _shminfo = 0; 07026 if (XShmQueryExtension(cimg::X11_attr().display)) { 07027 _shminfo = new XShmSegmentInfo; 07028 _image = XShmCreateImage(cimg::X11_attr().display,DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 07029 cimg::X11_attr().nb_bits,ZPixmap,0,_shminfo,_width,_height); 07030 if (!_image) { 07031 delete _shminfo; 07032 _shminfo = 0; 07033 } else { 07034 _shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777); 07035 if (_shminfo->shmid==-1) { 07036 XDestroyImage(_image); 07037 delete _shminfo; 07038 _shminfo = 0; 07039 } else { 07040 _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0)); 07041 if (_shminfo->shmaddr==(char*)-1) { 07042 shmctl(_shminfo->shmid,IPC_RMID,0); 07043 XDestroyImage(_image); 07044 delete _shminfo; 07045 _shminfo = 0; 07046 } else { 07047 _shminfo->readOnly = False; 07048 cimg::X11_attr().shm_enabled = true; 07049 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); 07050 XShmAttach(cimg::X11_attr().display, _shminfo); 07051 XSync(cimg::X11_attr().display, False); 07052 XSetErrorHandler(oldXErrorHandler); 07053 if (!cimg::X11_attr().shm_enabled) { 07054 shmdt(_shminfo->shmaddr); 07055 shmctl(_shminfo->shmid,IPC_RMID,0); 07056 XDestroyImage(_image); 07057 delete _shminfo; 07058 _shminfo = 0; 07059 } 07060 } 07061 } 07062 } 07063 } 07064 if (!_shminfo) 07065 #endif 07066 { 07067 _data = std::malloc(bufsize); 07068 _image = XCreateImage(cimg::X11_attr().display,DefaultVisual(cimg::X11_attr().display,DefaultScreen(cimg::X11_attr().display)), 07069 cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,_width,_height,8,0); 07070 } 07071 07072 _wm_window_atom = XInternAtom(cimg::X11_attr().display,"WM_DELETE_WINDOW",False); 07073 _wm_protocol_atom = XInternAtom(cimg::X11_attr().display,"WM_PROTOCOLS",False); 07074 XSetWMProtocols(cimg::X11_attr().display,_window,&_wm_window_atom,1); 07075 XSelectInput(cimg::X11_attr().display,_window, 07076 ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | 07077 EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask); 07078 if (_is_fullscreen) XGrabKeyboard(cimg::X11_attr().display, _window, True, GrabModeAsync, GrabModeAsync, CurrentTime); 07079 cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this; 07080 if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type<int>::min(); } 07081 XUnlockDisplay(cimg::X11_attr().display); 07082 } 07083 07084 CImgDisplay& assign() { 07085 if (is_empty()) return *this; 07086 XLockDisplay(cimg::X11_attr().display); 07087 07088 // Remove display window from event thread list. 07089 unsigned int i; 07090 for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {} 07091 for (; i<cimg::X11_attr().nb_wins-1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i+1]; 07092 --cimg::X11_attr().nb_wins; 07093 07094 // Destroy window, image, colormap and title. 07095 if (_is_fullscreen && !_is_closed) _desinit_fullscreen(); 07096 XDestroyWindow(cimg::X11_attr().display,_window); 07097 _window = 0; 07098 #ifdef cimg_use_xshm 07099 if (_shminfo) { 07100 XShmDetach(cimg::X11_attr().display, _shminfo); 07101 XDestroyImage(_image); 07102 shmdt(_shminfo->shmaddr); 07103 shmctl(_shminfo->shmid,IPC_RMID,0); 07104 delete _shminfo; 07105 _shminfo = 0; 07106 } else 07107 #endif 07108 XDestroyImage(_image); 07109 _data = 0; _image = 0; 07110 if (cimg::X11_attr().nb_bits==8) XFreeColormap(cimg::X11_attr().display,_colormap); 07111 _colormap = 0; 07112 XSync(cimg::X11_attr().display, False); 07113 07114 // Reset display variables 07115 if (_title) delete[] _title; 07116 _width = _height = _normalization = _window_width = _window_height = 0; 07117 _window_x = _window_y = 0; 07118 _is_fullscreen = false; 07119 _is_closed = true; 07120 _min = _max = 0; 07121 _title = 0; 07122 flush(); 07123 07124 // End event thread and close display if necessary 07125 XUnlockDisplay(cimg::X11_attr().display); 07126 if (!cimg::X11_attr().nb_wins) { 07127 // Kill event thread 07128 //pthread_cancel(*cimg::X11_attr().event_thread); 07129 //XUnlockDisplay(cimg::X11_attr().display); 07130 //pthread_join(*cimg::X11_attr().event_thread,0); 07131 //delete cimg::X11_attr().event_thread; 07132 //cimg::X11_attr().event_thread = 0; 07133 // XUnlockDisplay(cimg::X11_attr().display); // <- This call make the library hang sometimes (fix required). 07134 // XCloseDisplay(cimg::X11_attr().display); // <- This call make the library hang sometimes (fix required). 07135 //cimg::X11_attr().display = 0; 07136 //delete cimg::X11_attr().gc; 07137 //cimg::X11_attr().gc = 0; 07138 } 07139 return *this; 07140 } 07141 07142 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, 07143 const unsigned int normalization_type=3, 07144 const bool fullscreen_flag=false, const bool closed_flag=false) { 07145 if (!dimw || !dimh) return assign(); 07146 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); 07147 _min = _max = 0; 07148 std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): 07149 (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*_width*_height); 07150 return paint(); 07151 } 07152 07153 template<typename T> 07154 CImgDisplay& assign(const CImg<T>& img, const char *const title=0, 07155 const unsigned int normalization_type=3, 07156 const bool fullscreen_flag=false, const bool closed_flag=false) { 07157 if (!img) return assign(); 07158 CImg<T> tmp; 07159 const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 07160 _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); 07161 if (_normalization==2) _min = (float)nimg.min_max(_max); 07162 return render(nimg).paint(); 07163 } 07164 07165 template<typename T> 07166 CImgDisplay& assign(const CImgList<T>& list, const char *const title=0, 07167 const unsigned int normalization_type=3, 07168 const bool fullscreen_flag=false, const bool closed_flag=false) { 07169 if (!list) return assign(); 07170 CImg<T> tmp; 07171 const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 07172 _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); 07173 if (_normalization==2) _min = (float)nimg.min_max(_max); 07174 return render(nimg).paint(); 07175 } 07176 07177 CImgDisplay& assign(const CImgDisplay& disp) { 07178 if (!disp) return assign(); 07179 _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); 07180 std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): 07181 cimg::X11_attr().nb_bits==16?sizeof(unsigned short): 07182 sizeof(unsigned int))*_width*_height); 07183 return paint(); 07184 } 07185 07186 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { 07187 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); 07188 if (is_empty()) return assign(nwidth,nheight); 07189 const unsigned int 07190 tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100), 07191 tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), 07192 dimx = tmpdimx?tmpdimx:1, 07193 dimy = tmpdimy?tmpdimy:1; 07194 XLockDisplay(cimg::X11_attr().display); 07195 if (_window_width!=dimx || _window_height!=dimy) XResizeWindow(cimg::X11_attr().display,_window,dimx,dimy); 07196 if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) { 07197 case 8 : { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break; 07198 case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break; 07199 default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); } 07200 } 07201 _window_width = _width = dimx; _window_height = _height = dimy; 07202 _is_resized = false; 07203 XUnlockDisplay(cimg::X11_attr().display); 07204 if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2); 07205 if (redraw) return paint(); 07206 return *this; 07207 } 07208 07209 CImgDisplay& toggle_fullscreen(const bool redraw=true) { 07210 if (is_empty()) return *this; 07211 if (redraw) { 07212 const unsigned int bufsize = _width*_height*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4)); 07213 void *odata = std::malloc(bufsize); 07214 std::memcpy(odata,_data,bufsize); 07215 assign(_width,_height,_title,_normalization,!_is_fullscreen,false); 07216 std::memcpy(_data,odata,bufsize); 07217 std::free(odata); 07218 return paint(false); 07219 } 07220 return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); 07221 } 07222 07223 CImgDisplay& show() { 07224 if (!is_empty() && _is_closed) { 07225 XLockDisplay(cimg::X11_attr().display); 07226 if (_is_fullscreen) _init_fullscreen(); 07227 _map_window(); 07228 _is_closed = false; 07229 XUnlockDisplay(cimg::X11_attr().display); 07230 return paint(); 07231 } 07232 return *this; 07233 } 07234 07235 CImgDisplay& close() { 07236 if (!is_empty() && !_is_closed) { 07237 XLockDisplay(cimg::X11_attr().display); 07238 if (_is_fullscreen) _desinit_fullscreen(); 07239 XUnmapWindow(cimg::X11_attr().display,_window); 07240 _window_x = _window_y = -1; 07241 _is_closed = true; 07242 XUnlockDisplay(cimg::X11_attr().display); 07243 } 07244 return *this; 07245 } 07246 07247 CImgDisplay& move(const int posx, const int posy) { 07248 if (is_empty()) return *this; 07249 show(); 07250 XLockDisplay(cimg::X11_attr().display); 07251 XMoveWindow(cimg::X11_attr().display,_window,posx,posy); 07252 _window_x = posx; _window_y = posy; 07253 _is_moved = false; 07254 XUnlockDisplay(cimg::X11_attr().display); 07255 return paint(); 07256 } 07257 07258 CImgDisplay& show_mouse() { 07259 if (is_empty()) return *this; 07260 XLockDisplay(cimg::X11_attr().display); 07261 XUndefineCursor(cimg::X11_attr().display,_window); 07262 XUnlockDisplay(cimg::X11_attr().display); 07263 return *this; 07264 } 07265 07266 CImgDisplay& hide_mouse() { 07267 if (is_empty()) return *this; 07268 XLockDisplay(cimg::X11_attr().display); 07269 const char pix_data[8] = { 0 }; 07270 XColor col; 07271 col.red = col.green = col.blue = 0; 07272 Pixmap pix = XCreateBitmapFromData(cimg::X11_attr().display,_window,pix_data,8,8); 07273 Cursor cur = XCreatePixmapCursor(cimg::X11_attr().display,pix,pix,&col,&col,0,0); 07274 XFreePixmap(cimg::X11_attr().display,pix); 07275 XDefineCursor(cimg::X11_attr().display,_window,cur); 07276 XUnlockDisplay(cimg::X11_attr().display); 07277 return *this; 07278 } 07279 07280 CImgDisplay& set_mouse(const int posx, const int posy) { 07281 if (is_empty() || _is_closed) return *this; 07282 XLockDisplay(cimg::X11_attr().display); 07283 XWarpPointer(cimg::X11_attr().display,0L,_window,0,0,0,0,posx,posy); 07284 _mouse_x = posx; _mouse_y = posy; 07285 _is_moved = false; 07286 XSync(cimg::X11_attr().display, False); 07287 XUnlockDisplay(cimg::X11_attr().display); 07288 return *this; 07289 } 07290 07291 CImgDisplay& set_title(const char *const format, ...) { 07292 if (is_empty()) return *this; 07293 char tmp[1024] = { 0 }; 07294 va_list ap; 07295 va_start(ap, format); 07296 std::vsprintf(tmp,format,ap); 07297 va_end(ap); 07298 if (std::strcmp(_title,tmp)) { 07299 if (_title) delete[] _title; 07300 const unsigned int s = std::strlen(tmp) + 1; 07301 _title = new char[s]; 07302 std::memcpy(_title,tmp,s*sizeof(char)); 07303 XLockDisplay(cimg::X11_attr().display); 07304 XStoreName(cimg::X11_attr().display,_window,tmp); 07305 XUnlockDisplay(cimg::X11_attr().display); 07306 } 07307 return *this; 07308 } 07309 07310 template<typename T> 07311 CImgDisplay& display(const CImg<T>& img) { 07312 if (!img) 07313 throw CImgArgumentException(_cimgdisplay_instance 07314 "display() : Empty specified image.", 07315 cimgdisplay_instance); 07316 07317 if (is_empty()) assign(img._width,img._height); 07318 return render(img).paint(false); 07319 } 07320 07321 CImgDisplay& paint(const bool wait_expose=true) { 07322 if (is_empty()) return *this; 07323 XLockDisplay(cimg::X11_attr().display); 07324 _paint(wait_expose); 07325 XUnlockDisplay(cimg::X11_attr().display); 07326 return *this; 07327 } 07328 07329 template<typename T> 07330 CImgDisplay& render(const CImg<T>& img, const bool flag8=false) { 07331 if (!img) 07332 throw CImgArgumentException(_cimgdisplay_instance 07333 "render() : Empty specified image.", 07334 cimgdisplay_instance); 07335 07336 if (is_empty()) return *this; 07337 if (img._depth!=1) return render(img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 07338 if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height)) return render(img.get_resize(_width,_height,1,-100,1)); 07339 if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) { 07340 static const CImg<typename CImg<T>::ucharT> default_palette = CImg<typename CImg<T>::ucharT>::default_LUT256(); 07341 return render(img.get_index(default_palette,true,false)); 07342 } 07343 07344 const T 07345 *data1 = img._data, 07346 *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1, 07347 *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1; 07348 07349 if (cimg::X11_attr().blue_first) cimg::swap(data1,data3); 07350 XLockDisplay(cimg::X11_attr().display); 07351 07352 if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) { 07353 _min = _max = 0; 07354 switch (cimg::X11_attr().nb_bits) { 07355 case 8 : { // 256 color palette, no normalization 07356 _set_colormap(_colormap,img._spectrum); 07357 unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[img._width*img._height]; 07358 unsigned char *ptrd = (unsigned char*)ndata; 07359 switch (img._spectrum) { 07360 case 1 : for (unsigned int xy = img._width*img._height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++); 07361 break; 07362 case 2 : for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07363 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); 07364 (*ptrd++) = (R&0xf0) | (G>>4); 07365 } break; 07366 default : for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07367 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++); 07368 (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); 07369 } 07370 } 07371 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } 07372 } break; 07373 case 16 : { // 16 bits colors, no normalization 07374 unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[img._width*img._height]; 07375 unsigned char *ptrd = (unsigned char*)ndata; 07376 const unsigned int M = 248; 07377 switch (img._spectrum) { 07378 case 1 : 07379 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07380 const unsigned char val = (unsigned char)*(data1++), G = val>>2; 07381 *(ptrd++) = (val&M) | (G>>3); 07382 *(ptrd++) = (G<<5) | (G>>1); 07383 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07384 const unsigned char val = (unsigned char)*(data1++), G = val>>2; 07385 *(ptrd++) = (G<<5) | (G>>1); 07386 *(ptrd++) = (val&M) | (G>>3); 07387 } 07388 break; 07389 case 2 : 07390 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07391 const unsigned char G = (unsigned char)*(data2++)>>2; 07392 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); 07393 *(ptrd++) = (G<<5); 07394 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07395 const unsigned char G = (unsigned char)*(data2++)>>2; 07396 *(ptrd++) = (G<<5); 07397 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); 07398 } 07399 break; 07400 default : 07401 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07402 const unsigned char G = (unsigned char)*(data2++)>>2; 07403 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); 07404 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); 07405 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07406 const unsigned char G = (unsigned char)*(data2++)>>2; 07407 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); 07408 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3); 07409 } 07410 } 07411 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } 07412 } break; 07413 default : { // 24 bits colors, no normalization 07414 unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[img._width*img._height]; 07415 if (sizeof(int)==4) { // 32 bits int uses optimized version 07416 unsigned int *ptrd = ndata; 07417 switch (img._spectrum) { 07418 case 1 : 07419 if (cimg::X11_attr().byte_order==cimg::endianness()) 07420 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07421 const unsigned char val = (unsigned char)*(data1++); 07422 *(ptrd++) = (val<<16) | (val<<8) | val; 07423 } 07424 else 07425 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07426 const unsigned char val = (unsigned char)*(data1++)<<8; 07427 *(ptrd++) = (val<<16) | (val<<8) | val; 07428 } 07429 break; 07430 case 2 : 07431 if (cimg::X11_attr().byte_order==cimg::endianness()) 07432 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07433 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8); 07434 else 07435 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07436 *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); 07437 break; 07438 default : 07439 if (cimg::X11_attr().byte_order==cimg::endianness()) 07440 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07441 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); 07442 else 07443 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07444 *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); 07445 } 07446 } else { 07447 unsigned char *ptrd = (unsigned char*)ndata; 07448 switch (img._spectrum) { 07449 case 1 : 07450 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07451 *(ptrd++) = 0; 07452 *(ptrd++) = (unsigned char)*(data1++); 07453 *(ptrd++) = 0; 07454 *(ptrd++) = 0; 07455 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07456 *(ptrd++) = 0; 07457 *(ptrd++) = 0; 07458 *(ptrd++) = (unsigned char)*(data1++); 07459 *(ptrd++) = 0; 07460 } 07461 break; 07462 case 2 : 07463 if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); 07464 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07465 *(ptrd++) = 0; 07466 *(ptrd++) = (unsigned char)*(data2++); 07467 *(ptrd++) = (unsigned char)*(data1++); 07468 *(ptrd++) = 0; 07469 } 07470 break; 07471 default : 07472 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07473 *(ptrd++) = 0; 07474 *(ptrd++) = (unsigned char)*(data1++); 07475 *(ptrd++) = (unsigned char)*(data2++); 07476 *(ptrd++) = (unsigned char)*(data3++); 07477 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07478 *(ptrd++) = (unsigned char)*(data3++); 07479 *(ptrd++) = (unsigned char)*(data2++); 07480 *(ptrd++) = (unsigned char)*(data1++); 07481 *(ptrd++) = 0; 07482 } 07483 } 07484 } 07485 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; } 07486 } 07487 } 07488 } else { 07489 if (_normalization==3) { 07490 if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max); 07491 else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); } 07492 } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); 07493 const float delta = _max-_min, mm = delta?delta:1.0f; 07494 switch (cimg::X11_attr().nb_bits) { 07495 case 8 : { // 256 color palette, with normalization 07496 _set_colormap(_colormap,img._spectrum); 07497 unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[img._width*img._height]; 07498 unsigned char *ptrd = (unsigned char*)ndata; 07499 switch (img._spectrum) { 07500 case 1 : for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07501 const unsigned char R = (unsigned char)(255*(*(data1++)-_min)/mm); 07502 *(ptrd++) = R; 07503 } break; 07504 case 2 : for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07505 const unsigned char 07506 R = (unsigned char)(255*(*(data1++)-_min)/mm), 07507 G = (unsigned char)(255*(*(data2++)-_min)/mm); 07508 (*ptrd++) = (R&0xf0) | (G>>4); 07509 } break; 07510 default : 07511 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07512 const unsigned char 07513 R = (unsigned char)(255*(*(data1++)-_min)/mm), 07514 G = (unsigned char)(255*(*(data2++)-_min)/mm), 07515 B = (unsigned char)(255*(*(data3++)-_min)/mm); 07516 *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); 07517 } 07518 } 07519 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; } 07520 } break; 07521 case 16 : { // 16 bits colors, with normalization 07522 unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[img._width*img._height]; 07523 unsigned char *ptrd = (unsigned char*)ndata; 07524 const unsigned int M = 248; 07525 switch (img._spectrum) { 07526 case 1 : 07527 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07528 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm), G = val>>2; 07529 *(ptrd++) = (val&M) | (G>>3); 07530 *(ptrd++) = (G<<5) | (val>>3); 07531 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07532 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm), G = val>>2; 07533 *(ptrd++) = (G<<5) | (val>>3); 07534 *(ptrd++) = (val&M) | (G>>3); 07535 } 07536 break; 07537 case 2 : 07538 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07539 const unsigned char G = (unsigned char)(255*(*(data2++)-_min)/mm)>>2; 07540 *(ptrd++) = ((unsigned char)(255*(*(data1++)-_min)/mm)&M) | (G>>3); 07541 *(ptrd++) = (G<<5); 07542 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07543 const unsigned char G = (unsigned char)(255*(*(data2++)-_min)/mm)>>2; 07544 *(ptrd++) = (G<<5); 07545 *(ptrd++) = ((unsigned char)(255*(*(data1++)-_min)/mm)&M) | (G>>3); 07546 } 07547 break; 07548 default : 07549 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07550 const unsigned char G = (unsigned char)(255*(*(data2++)-_min)/mm)>>2; 07551 *(ptrd++) = ((unsigned char)(255*(*(data1++)-_min)/mm)&M) | (G>>3); 07552 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-_min)/mm)>>3); 07553 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07554 const unsigned char G = (unsigned char)(255*(*(data2++)-_min)/mm)>>2; 07555 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-_min)/mm)>>3); 07556 *(ptrd++) = ((unsigned char)(255*(*(data1++)-_min)/mm)&M) | (G>>3); 07557 } 07558 } 07559 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; } 07560 } break; 07561 default : { // 24 bits colors, with normalization 07562 unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[img._width*img._height]; 07563 if (sizeof(int)==4) { // 32 bits int uses optimized version 07564 unsigned int *ptrd = ndata; 07565 switch (img._spectrum) { 07566 case 1 : 07567 if (cimg::X11_attr().byte_order==cimg::endianness()) 07568 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07569 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm); 07570 *(ptrd++) = (val<<16) | (val<<8) | val; 07571 } 07572 else 07573 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07574 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm); 07575 *(ptrd++) = (val<<24) | (val<<16) | (val<<8); 07576 } 07577 break; 07578 case 2 : 07579 if (cimg::X11_attr().byte_order==cimg::endianness()) 07580 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07581 *(ptrd++) = 07582 ((unsigned char)(255*(*(data1++)-_min)/mm)<<16) | 07583 ((unsigned char)(255*(*(data2++)-_min)/mm)<<8); 07584 else 07585 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07586 *(ptrd++) = 07587 ((unsigned char)(255*(*(data2++)-_min)/mm)<<16) | 07588 ((unsigned char)(255*(*(data1++)-_min)/mm)<<8); 07589 break; 07590 default : 07591 if (cimg::X11_attr().byte_order==cimg::endianness()) 07592 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07593 *(ptrd++) = 07594 ((unsigned char)(255*(*(data1++)-_min)/mm)<<16) | 07595 ((unsigned char)(255*(*(data2++)-_min)/mm)<<8) | 07596 (unsigned char)(255*(*(data3++)-_min)/mm); 07597 else 07598 for (unsigned int xy = img._width*img._height; xy>0; --xy) 07599 *(ptrd++) = 07600 ((unsigned char)(255*(*(data3++)-_min)/mm)<<24) | 07601 ((unsigned char)(255*(*(data2++)-_min)/mm)<<16) | 07602 ((unsigned char)(255*(*(data1++)-_min)/mm)<<8); 07603 } 07604 } else { 07605 unsigned char *ptrd = (unsigned char*)ndata; 07606 switch (img._spectrum) { 07607 case 1 : 07608 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07609 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm); 07610 (*ptrd++) = 0; 07611 (*ptrd++) = val; 07612 (*ptrd++) = val; 07613 (*ptrd++) = val; 07614 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07615 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm); 07616 (*ptrd++) = val; 07617 (*ptrd++) = val; 07618 (*ptrd++) = val; 07619 (*ptrd++) = 0; 07620 } 07621 break; 07622 case 2 : 07623 if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); 07624 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07625 (*ptrd++) = 0; 07626 (*ptrd++) = (unsigned char)(255*(*(data2++)-_min)/mm); 07627 (*ptrd++) = (unsigned char)(255*(*(data1++)-_min)/mm); 07628 (*ptrd++) = 0; 07629 } 07630 break; 07631 default : 07632 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07633 (*ptrd++) = 0; 07634 (*ptrd++) = (unsigned char)(255*(*(data1++)-_min)/mm); 07635 (*ptrd++) = (unsigned char)(255*(*(data2++)-_min)/mm); 07636 (*ptrd++) = (unsigned char)(255*(*(data3++)-_min)/mm); 07637 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07638 (*ptrd++) = (unsigned char)(255*(*(data3++)-_min)/mm); 07639 (*ptrd++) = (unsigned char)(255*(*(data2++)-_min)/mm); 07640 (*ptrd++) = (unsigned char)(255*(*(data1++)-_min)/mm); 07641 (*ptrd++) = 0; 07642 } 07643 } 07644 } 07645 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; } 07646 } 07647 } 07648 } 07649 XUnlockDisplay(cimg::X11_attr().display); 07650 return *this; 07651 } 07652 07653 template<typename T> 07654 const CImgDisplay& snapshot(CImg<T>& img) const { 07655 if (is_empty()) { img.assign(); return *this; } 07656 const unsigned char *ptrs = (unsigned char*)_data; 07657 img.assign(_width,_height,1,3); 07658 T 07659 *data1 = img.data(0,0,0,0), 07660 *data2 = img.data(0,0,0,1), 07661 *data3 = img.data(0,0,0,2); 07662 if (cimg::X11_attr().blue_first) cimg::swap(data1,data3); 07663 switch (cimg::X11_attr().nb_bits) { 07664 case 8 : { 07665 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07666 const unsigned char val = *(ptrs++); 07667 *(data1++) = val&0xe0; 07668 *(data2++) = (val&0x1c)<<3; 07669 *(data3++) = val<<6; 07670 } 07671 } break; 07672 case 16 : { 07673 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07674 const unsigned char val0 = *(ptrs++), val1 = *(ptrs++); 07675 *(data1++) = val0&0xf8; 07676 *(data2++) = (val0<<5) | ((val1&0xe0)>>5); 07677 *(data3++) = val1<<3; 07678 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07679 const unsigned short val0 = *(ptrs++), val1 = *(ptrs++); 07680 *(data1++) = val1&0xf8; 07681 *(data2++) = (val1<<5) | ((val0&0xe0)>>5); 07682 *(data3++) = val0<<3; 07683 } 07684 } break; 07685 default : { 07686 if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07687 ++ptrs; 07688 *(data1++) = *(ptrs++); 07689 *(data2++) = *(ptrs++); 07690 *(data3++) = *(ptrs++); 07691 } else for (unsigned int xy = img._width*img._height; xy>0; --xy) { 07692 *(data3++) = *(ptrs++); 07693 *(data2++) = *(ptrs++); 07694 *(data1++) = *(ptrs++); 07695 ++ptrs; 07696 } 07697 } 07698 } 07699 return *this; 07700 } 07701 07702 // Windows-based implementation. 07703 //------------------------------- 07704 #elif cimg_display==2 07705 07706 CLIENTCREATESTRUCT _ccs; 07707 BITMAPINFO _bmi; 07708 unsigned int *_data; 07709 DEVMODE _curr_mode; 07710 HWND _window; 07711 HWND _background_window; 07712 HDC _hdc; 07713 HANDLE _thread; 07714 HANDLE _is_created; 07715 HANDLE _mutex; 07716 bool _is_mouse_tracked; 07717 bool _is_cursor_visible; 07718 07719 static int screen_width() { 07720 DEVMODE mode; 07721 mode.dmSize = sizeof(DEVMODE); 07722 mode.dmDriverExtra = 0; 07723 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); 07724 return mode.dmPelsWidth; 07725 } 07726 07727 static int screen_height() { 07728 DEVMODE mode; 07729 mode.dmSize = sizeof(DEVMODE); 07730 mode.dmDriverExtra = 0; 07731 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); 07732 return mode.dmPelsHeight; 07733 } 07734 07735 static void wait_all() { 07736 WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE); 07737 } 07738 07739 static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) { 07740 #ifdef _WIN64 07741 CImgDisplay *disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA); 07742 #else 07743 CImgDisplay *disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA); 07744 #endif 07745 MSG st_msg; 07746 switch (msg) { 07747 case WM_CLOSE : 07748 disp->_mouse_x = disp->_mouse_y = -1; 07749 disp->_window_x = disp->_window_y = 0; 07750 disp->set_button().set_key(0).set_key(0,false)._is_closed = true; 07751 ReleaseMutex(disp->_mutex); 07752 ShowWindow(disp->_window,SW_HIDE); 07753 disp->_is_event = true; 07754 SetEvent(cimg::Win32_attr().wait_event); 07755 return 0; 07756 case WM_SIZE : { 07757 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} 07758 WaitForSingleObject(disp->_mutex,INFINITE); 07759 const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam); 07760 if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) { 07761 disp->_window_width = nw; 07762 disp->_window_height = nh; 07763 disp->_mouse_x = disp->_mouse_y = -1; 07764 disp->_is_resized = disp->_is_event = true; 07765 SetEvent(cimg::Win32_attr().wait_event); 07766 } 07767 ReleaseMutex(disp->_mutex); 07768 } break; 07769 case WM_MOVE : { 07770 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} 07771 WaitForSingleObject(disp->_mutex,INFINITE); 07772 const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam)); 07773 if (nx!=disp->_window_x || ny!=disp->_window_y) { 07774 disp->_window_x = nx; 07775 disp->_window_y = ny; 07776 disp->_is_moved = disp->_is_event = true; 07777 SetEvent(cimg::Win32_attr().wait_event); 07778 } 07779 ReleaseMutex(disp->_mutex); 07780 } break; 07781 case WM_PAINT : 07782 disp->paint(); 07783 break; 07784 case WM_KEYDOWN : 07785 disp->set_key((unsigned int)wParam); 07786 SetEvent(cimg::Win32_attr().wait_event); 07787 break; 07788 case WM_KEYUP : 07789 disp->set_key((unsigned int)wParam,false); 07790 SetEvent(cimg::Win32_attr().wait_event); 07791 break; 07792 case WM_MOUSEMOVE : { 07793 while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {} 07794 disp->_mouse_x = LOWORD(lParam); 07795 disp->_mouse_y = HIWORD(lParam); 07796 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT) 07797 if (!disp->_is_mouse_tracked) { 07798 TRACKMOUSEEVENT tme; 07799 tme.cbSize = sizeof(TRACKMOUSEEVENT); 07800 tme.dwFlags = TME_LEAVE; 07801 tme.hwndTrack = disp->_window; 07802 if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true; 07803 } 07804 #endif 07805 if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height()) 07806 disp->_mouse_x = disp->_mouse_y = -1; 07807 disp->_is_event = true; 07808 SetEvent(cimg::Win32_attr().wait_event); 07809 } break; 07810 case WM_MOUSELEAVE : { 07811 disp->_mouse_x = disp->_mouse_y = -1; 07812 disp->_is_mouse_tracked = false; 07813 } break; 07814 case WM_LBUTTONDOWN : 07815 disp->set_button(1); 07816 SetEvent(cimg::Win32_attr().wait_event); 07817 break; 07818 case WM_RBUTTONDOWN : 07819 disp->set_button(2); 07820 SetEvent(cimg::Win32_attr().wait_event); 07821 break; 07822 case WM_MBUTTONDOWN : 07823 disp->set_button(3); 07824 SetEvent(cimg::Win32_attr().wait_event); 07825 break; 07826 case WM_LBUTTONUP : 07827 disp->set_button(1,false); 07828 SetEvent(cimg::Win32_attr().wait_event); 07829 break; 07830 case WM_RBUTTONUP : 07831 disp->set_button(2,false); 07832 SetEvent(cimg::Win32_attr().wait_event); 07833 break; 07834 case WM_MBUTTONUP : 07835 disp->set_button(3,false); 07836 SetEvent(cimg::Win32_attr().wait_event); 07837 break; 07838 case 0x020A : // WM_MOUSEWHEEL: 07839 disp->set_wheel((int)((short)HIWORD(wParam))/120); 07840 SetEvent(cimg::Win32_attr().wait_event); 07841 case WM_SETCURSOR : 07842 if (disp->_is_cursor_visible) ShowCursor(TRUE); 07843 else ShowCursor(FALSE); 07844 break; 07845 } 07846 return DefWindowProc(window,msg,wParam,lParam); 07847 } 07848 07849 static DWORD WINAPI _events_thread(void* arg) { 07850 CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]); 07851 const char *const title = (const char*)(((void**)arg)[1]); 07852 MSG msg; 07853 delete[] (void**)arg; 07854 disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 07855 disp->_bmi.bmiHeader.biWidth = disp->width(); 07856 disp->_bmi.bmiHeader.biHeight = -disp->height(); 07857 disp->_bmi.bmiHeader.biPlanes = 1; 07858 disp->_bmi.bmiHeader.biBitCount = 32; 07859 disp->_bmi.bmiHeader.biCompression = BI_RGB; 07860 disp->_bmi.bmiHeader.biSizeImage = 0; 07861 disp->_bmi.bmiHeader.biXPelsPerMeter = 1; 07862 disp->_bmi.bmiHeader.biYPelsPerMeter = 1; 07863 disp->_bmi.bmiHeader.biClrUsed = 0; 07864 disp->_bmi.bmiHeader.biClrImportant = 0; 07865 disp->_data = new unsigned int[disp->_width*disp->_height]; 07866 if (!disp->_is_fullscreen) { // Normal window 07867 RECT rect; 07868 rect.left = rect.top = 0; rect.right = disp->_width-1; rect.bottom = disp->_height-1; 07869 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); 07870 const int 07871 border1 = (rect.right - rect.left + 1 - disp->_width)/2, 07872 border2 = rect.bottom - rect.top + 1 - disp->_height - border1; 07873 disp->_window = CreateWindowA("MDICLIENT",title?title:" ", 07874 WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT, 07875 disp->_width + 2*border1, disp->_height + border1 + border2, 07876 0,0,0,&(disp->_ccs)); 07877 if (!disp->_is_closed) { 07878 GetWindowRect(disp->_window,&rect); 07879 disp->_window_x = rect.left + border1; 07880 disp->_window_y = rect.top + border2; 07881 } else disp->_window_x = disp->_window_y = 0; 07882 } else { // Fullscreen window 07883 const unsigned int sx = screen_width(), sy = screen_height(); 07884 disp->_window = CreateWindowA("MDICLIENT",title?title:" ", 07885 WS_POPUP | (disp->_is_closed?0:WS_VISIBLE), (sx-disp->_width)/2, (sy-disp->_height)/2, 07886 disp->_width,disp->_height,0,0,0,&(disp->_ccs)); 07887 disp->_window_x = disp->_window_y = 0; 07888 } 07889 SetForegroundWindow(disp->_window); 07890 disp->_hdc = GetDC(disp->_window); 07891 disp->_window_width = disp->_width; 07892 disp->_window_height = disp->_height; 07893 disp->flush(); 07894 #ifdef _WIN64 07895 SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp); 07896 SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events); 07897 #else 07898 SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp); 07899 SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events); 07900 #endif 07901 SetEvent(disp->_is_created); 07902 while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg); 07903 return 0; 07904 } 07905 07906 CImgDisplay& _update_window_pos() { 07907 if (!_is_closed) { 07908 RECT rect; 07909 rect.left = rect.top = 0; rect.right = _width-1; rect.bottom = _height-1; 07910 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); 07911 const int 07912 border1 = (rect.right - rect.left + 1 - _width)/2, 07913 border2 = rect.bottom - rect.top + 1 - _height - border1; 07914 GetWindowRect(_window,&rect); 07915 _window_x = rect.left + border1; 07916 _window_y = rect.top + border2; 07917 } else _window_x = _window_y = -1; 07918 return *this; 07919 } 07920 07921 void _init_fullscreen() { 07922 _background_window = 0; 07923 if (_is_fullscreen && !_is_closed) { 07924 DEVMODE mode; 07925 unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U; 07926 for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) { 07927 const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight; 07928 if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) { 07929 bestbpp = mode.dmBitsPerPel; 07930 ibest = imode; 07931 bw = nw; bh = nh; 07932 } 07933 } 07934 if (bestbpp) { 07935 _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0; 07936 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode); 07937 EnumDisplaySettings(0,ibest,&mode); 07938 ChangeDisplaySettings(&mode,0); 07939 } else _curr_mode.dmSize = 0; 07940 07941 const unsigned int sx = screen_width(), sy = screen_height(); 07942 if (sx!=_width || sy!=_height) { 07943 CLIENTCREATESTRUCT background_ccs; 07944 _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs); 07945 SetForegroundWindow(_background_window); 07946 } 07947 } else _curr_mode.dmSize = 0; 07948 } 07949 07950 void _desinit_fullscreen() { 07951 if (_is_fullscreen) { 07952 if (_background_window) DestroyWindow(_background_window); 07953 _background_window = 0; 07954 if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0); 07955 _is_fullscreen = false; 07956 } 07957 } 07958 07959 CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, 07960 const unsigned int normalization_type=3, 07961 const bool fullscreen_flag=false, const bool closed_flag=false) { 07962 07963 // Allocate space for window title 07964 const char *const nptitle = ptitle?ptitle:""; 07965 const unsigned int s = std::strlen(nptitle) + 1; 07966 char *const tmp_title = s?new char[s]:0; 07967 if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); 07968 07969 // Destroy previous window if existing 07970 if (!is_empty()) assign(); 07971 07972 // Set display variables 07973 _width = cimg::min(dimw,(unsigned int)screen_width()); 07974 _height = cimg::min(dimh,(unsigned int)screen_height()); 07975 _normalization = normalization_type<4?normalization_type:3; 07976 _is_fullscreen = fullscreen_flag; 07977 _window_x = _window_y = 0; 07978 _is_closed = closed_flag; 07979 _is_cursor_visible = true; 07980 _is_mouse_tracked = false; 07981 _title = tmp_title; 07982 flush(); 07983 if (_is_fullscreen) _init_fullscreen(); 07984 07985 // Create event thread 07986 void *const arg = (void*)(new void*[2]); 07987 ((void**)arg)[0] = (void*)this; 07988 ((void**)arg)[1] = (void*)_title; 07989 unsigned long ThreadID = 0; 07990 _mutex = CreateMutex(0,FALSE,0); 07991 _is_created = CreateEvent(0,FALSE,FALSE,0); 07992 _thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID); 07993 WaitForSingleObject(_is_created,INFINITE); 07994 return *this; 07995 } 07996 07997 CImgDisplay& assign() { 07998 if (is_empty()) return *this; 07999 DestroyWindow(_window); 08000 TerminateThread(_thread,0); 08001 if (_data) delete[] _data; 08002 if (_title) delete[] _title; 08003 if (_is_fullscreen) _desinit_fullscreen(); 08004 _width = _height = _normalization = _window_width = _window_height = 0; 08005 _window_x = _window_y = 0; 08006 _is_fullscreen = false; 08007 _is_closed = true; 08008 _min = _max = 0; 08009 _title = 0; 08010 flush(); 08011 return *this; 08012 } 08013 08014 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, 08015 const unsigned int normalization_type=3, 08016 const bool fullscreen_flag=false, const bool closed_flag=false) { 08017 if (!dimw || !dimh) return assign(); 08018 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); 08019 _min = _max = 0; 08020 std::memset(_data,0,sizeof(unsigned int)*_width*_height); 08021 return paint(); 08022 } 08023 08024 template<typename T> 08025 CImgDisplay& assign(const CImg<T>& img, const char *const title=0, 08026 const unsigned int normalization_type=3, 08027 const bool fullscreen_flag=false, const bool closed_flag=false) { 08028 if (!img) return assign(); 08029 CImg<T> tmp; 08030 const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 08031 _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); 08032 if (_normalization==2) _min = (float)nimg.min_max(_max); 08033 return display(nimg); 08034 } 08035 08036 template<typename T> 08037 CImgDisplay& assign(const CImgList<T>& list, const char *const title=0, 08038 const unsigned int normalization_type=3, 08039 const bool fullscreen_flag=false, const bool closed_flag=false) { 08040 if (!list) return assign(); 08041 CImg<T> tmp; 08042 const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 08043 _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); 08044 if (_normalization==2) _min = (float)nimg.min_max(_max); 08045 return display(nimg); 08046 } 08047 08048 CImgDisplay& assign(const CImgDisplay& disp) { 08049 if (!disp) return assign(); 08050 _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); 08051 std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height); 08052 return paint(); 08053 } 08054 08055 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { 08056 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); 08057 if (is_empty()) return assign(nwidth,nheight); 08058 const unsigned int 08059 tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100), 08060 tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), 08061 dimx = tmpdimx?tmpdimx:1, 08062 dimy = tmpdimy?tmpdimy:1; 08063 if (_window_width!=dimx || _window_height!=dimy) { 08064 RECT rect; rect.left = rect.top = 0; rect.right = dimx - 1; rect.bottom = dimy - 1; 08065 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); 08066 const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; 08067 SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); 08068 } 08069 if (_width!=dimx || _height!=dimy) { 08070 unsigned int *const ndata = new unsigned int[dimx*dimy]; 08071 if (redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy); 08072 else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); 08073 delete[] _data; 08074 _data = ndata; 08075 _bmi.bmiHeader.biWidth = dimx; 08076 _bmi.bmiHeader.biHeight = -(int)dimy; 08077 _width = dimx; 08078 _height = dimy; 08079 } 08080 _window_width = dimx; _window_height = dimy; 08081 _is_resized = false; 08082 if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2); 08083 if (redraw) return paint(); 08084 return *this; 08085 } 08086 08087 CImgDisplay& toggle_fullscreen(const bool redraw=true) { 08088 if (is_empty()) return *this; 08089 if (redraw) { 08090 const unsigned int bufsize = _width*_height*4; 08091 void *odata = std::malloc(bufsize); 08092 std::memcpy(odata,_data,bufsize); 08093 assign(_width,_height,_title,_normalization,!_is_fullscreen,false); 08094 std::memcpy(_data,odata,bufsize); 08095 std::free(odata); 08096 return paint(); 08097 } 08098 return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); 08099 } 08100 08101 CImgDisplay& show() { 08102 if (is_empty()) return *this; 08103 if (_is_closed) { 08104 _is_closed = false; 08105 if (_is_fullscreen) _init_fullscreen(); 08106 ShowWindow(_window,SW_SHOW); 08107 _update_window_pos(); 08108 } 08109 return paint(); 08110 } 08111 08112 CImgDisplay& close() { 08113 if (is_empty()) return *this; 08114 if (!_is_closed && !_is_fullscreen) { 08115 if (_is_fullscreen) _desinit_fullscreen(); 08116 ShowWindow(_window,SW_HIDE); 08117 _is_closed = true; 08118 _window_x = _window_y = 0; 08119 } 08120 return *this; 08121 } 08122 08123 CImgDisplay& move(const int posx, const int posy) { 08124 if (is_empty()) return *this; 08125 if (!_is_fullscreen) { 08126 RECT rect; rect.left = rect.top = 0; rect.right = _window_width-1; rect.bottom = _window_height-1; 08127 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); 08128 const int border1 = (rect.right-rect.left+1-_width)/2, border2 = rect.bottom-rect.top+1-_height-border1; 08129 SetWindowPos(_window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER); 08130 } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); 08131 _window_x = posx; 08132 _window_y = posy; 08133 _is_moved = false; 08134 return show(); 08135 } 08136 08137 CImgDisplay& show_mouse() { 08138 if (is_empty()) return *this; 08139 _is_cursor_visible = true; 08140 ShowCursor(TRUE); 08141 SendMessage(_window,WM_SETCURSOR,0,0); 08142 return *this; 08143 } 08144 08145 CImgDisplay& hide_mouse() { 08146 if (is_empty()) return *this; 08147 _is_cursor_visible = false; 08148 ShowCursor(FALSE); 08149 SendMessage(_window,WM_SETCURSOR,0,0); 08150 return *this; 08151 } 08152 08153 CImgDisplay& set_mouse(const int posx, const int posy) { 08154 if (!_is_closed && posx>=0 && posy>=0) { 08155 _update_window_pos(); 08156 const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy); 08157 if (res) { _mouse_x = posx; _mouse_y = posy; } 08158 } 08159 return *this; 08160 } 08161 08162 CImgDisplay& set_title(const char *const format, ...) { 08163 if (is_empty()) return *this; 08164 char tmp[1024] = { 0 }; 08165 va_list ap; 08166 va_start(ap, format); 08167 std::vsprintf(tmp,format,ap); 08168 va_end(ap); 08169 if (std::strcmp(_title,tmp)) { 08170 if (_title) delete[] _title; 08171 const unsigned int s = std::strlen(tmp) + 1; 08172 _title = new char[s]; 08173 std::memcpy(_title,tmp,s*sizeof(char)); 08174 SetWindowTextA(_window, tmp); 08175 } 08176 return *this; 08177 } 08178 08179 template<typename T> 08180 CImgDisplay& display(const CImg<T>& img) { 08181 if (!img) 08182 throw CImgArgumentException(_cimgdisplay_instance 08183 "display() : Empty specified image.", 08184 cimgdisplay_instance); 08185 08186 if (is_empty()) assign(img._width,img._height); 08187 return render(img).paint(); 08188 } 08189 08190 CImgDisplay& paint() { 08191 if (!_is_closed) { 08192 WaitForSingleObject(_mutex,INFINITE); 08193 SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS); 08194 ReleaseMutex(_mutex); 08195 } 08196 return *this; 08197 } 08198 08199 template<typename T> 08200 CImgDisplay& render(const CImg<T>& img) { 08201 if (!img) 08202 throw CImgArgumentException(_cimgdisplay_instance 08203 "render() : Empty specified image.", 08204 cimgdisplay_instance); 08205 08206 if (is_empty()) return *this; 08207 if (img._depth!=1) return render(img.get_projections2d(img._width/2,img._height/2,img._depth/2)); 08208 08209 const T 08210 *data1 = img._data, 08211 *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1, 08212 *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1; 08213 08214 WaitForSingleObject(_mutex,INFINITE); 08215 unsigned int 08216 *const ndata = (img._width==_width && img._height==_height)?_data:new unsigned int[img._width*img._height], 08217 *ptrd = ndata; 08218 08219 if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) { 08220 _min = _max = 0; 08221 switch (img._spectrum) { 08222 case 1 : { 08223 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 08224 const unsigned char val = (unsigned char)*(data1++); 08225 *(ptrd++) = (val<<16) | (val<<8) | val; 08226 } 08227 } break; 08228 case 2 : { 08229 for (unsigned int xy = img._width*img._height; xy>0; --xy) 08230 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8); 08231 } break; 08232 default : { 08233 for (unsigned int xy = img._width*img._height; xy>0; --xy) 08234 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); 08235 } 08236 } 08237 } else { 08238 if (_normalization==3) { 08239 if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max); 08240 else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); } 08241 } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); 08242 const float delta = _max-_min, mm = delta?delta:1.0f; 08243 switch (img._spectrum) { 08244 case 1 : { 08245 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 08246 const unsigned char val = (unsigned char)(255*(*(data1++)-_min)/mm); 08247 *(ptrd++) = (val<<16) | (val<<8) | val; 08248 } 08249 } break; 08250 case 2 : { 08251 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 08252 const unsigned char 08253 R = (unsigned char)(255*(*(data1++)-_min)/mm), 08254 G = (unsigned char)(255*(*(data2++)-_min)/mm); 08255 *(ptrd++) = (R<<16) | (G<<8); 08256 } 08257 } break; 08258 default : { 08259 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 08260 const unsigned char 08261 R = (unsigned char)(255*(*(data1++)-_min)/mm), 08262 G = (unsigned char)(255*(*(data2++)-_min)/mm), 08263 B = (unsigned char)(255*(*(data3++)-_min)/mm); 08264 *(ptrd++) = (R<<16) | (G<<8) | B; 08265 } 08266 } 08267 } 08268 } 08269 if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; } 08270 ReleaseMutex(_mutex); 08271 return *this; 08272 } 08273 08274 template<typename T> 08275 const CImgDisplay& snapshot(CImg<T>& img) const { 08276 if (is_empty()) { img.assign(); return *this; } 08277 const unsigned int *ptrs = _data; 08278 img.assign(_width,_height,1,3); 08279 T 08280 *data1 = img.data(0,0,0,0), 08281 *data2 = img.data(0,0,0,1), 08282 *data3 = img.data(0,0,0,2); 08283 for (unsigned int xy = img._width*img._height; xy>0; --xy) { 08284 const unsigned int val = *(ptrs++); 08285 *(data1++) = (unsigned char)(val>>16); 08286 *(data2++) = (unsigned char)((val>>8)&0xFF); 08287 *(data3++) = (unsigned char)(val&0xFF); 08288 } 08289 return *this; 08290 } 08291 #endif 08292 08293 //@} 08294 }; 08295 08296 /* 08297 #-------------------------------------- 08298 # 08299 # 08300 # 08301 # Definition of the CImg<T> structure 08302 # 08303 # 08304 # 08305 #-------------------------------------- 08306 */ 08307 08308 //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T. 08309 /** 08310 This is the main class of the %CImg Library. It declares and constructs 08311 an image, allows access to its pixel values, and is able to perform various image operations. 08312 08313 \par Image representation 08314 08315 A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels, 08316 each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth 08317 and number of channels. 08318 Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels 08319 is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance). 08320 If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>. 08321 08322 Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels, 08323 as well as images with less dimensions (1d scalar signal, 2d color images, ...). 08324 Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions. 08325 08326 Concerning the pixel value type \c T : 08327 fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int, 08328 unsigned long, long, float, double, ... </tt>. 08329 Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images, 08330 while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt> 08331 images that have floating-point pixel values. The default value for the template T is \c float. 08332 Using your own template types may be possible. However, you will certainly have to define the complete set 08333 of arithmetic and logical operators for your class. 08334 08335 \par Image structure 08336 08337 The \ref CImg<\c T> structure contains \a six fields : 08338 - \ref width defines the number of \a columns of the image (size along the X-axis). 08339 - \ref height defines the number of \a rows of the image (size along the Y-axis). 08340 - \ref depth defines the number of \a slices of the image (size along the Z-axis). 08341 - \ref spectrum defines the number of \a channels of the image (size along the C-axis). 08342 - \ref data defines a \a pointer to the \a pixel \a data (of type \c T). 08343 - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with 08344 another image. 08345 08346 You can access these fields publicly although it is recommended to use the dedicated functions 08347 width(), height(), depth(), spectrum() and ptr() to do so. 08348 Image dimensions are not limited to a specific range (as long as you got enough available memory). 08349 A value of \e 1 usually means that the corresponding dimension is \a flat. 08350 If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty. 08351 Empty images should not contain any pixel data and thus, will not be processed by CImg member functions 08352 (a CImgInstanceException will be thrown instead). 08353 Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage). 08354 08355 \par Image declaration and construction 08356 08357 Declaring an image can be done by using one of the several available constructors. 08358 Here is a list of the most used : 08359 08360 - Construct images from arbitrary dimensions : 08361 - <tt>CImg<char> img;</tt> declares an empty image. 08362 - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with 08363 \c unsigned \c char pixel values. 08364 - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients. 08365 - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image 08366 (colors are stored as an image with three channels). 08367 - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image 08368 (with \c double pixel values). 08369 - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image 08370 (with \c float pixels, which is the default value of the template parameter \c T). 08371 - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to 08372 do it, or use the specific constructor taking 5 parameters like this : 08373 <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0. 08374 08375 - Construct images from filenames : 08376 - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg". 08377 - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr". 08378 - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a> 08379 to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io). 08380 08381 - Construct images from C-style arrays : 08382 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer 08383 \c data_buffer (of size 256x256=65536). 08384 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image 08385 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). 08386 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image 08387 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed). 08388 08389 The complete list of constructors can be found <a href="#constructors">here</a>. 08390 08391 \par Most useful functions 08392 08393 The \ref CImg<\c T> class contains a lot of functions that operates on images. 08394 Some of the most useful are : 08395 08396 - operator()() : allows to access or write pixel values. 08397 - display() : displays the image in a new window. 08398 **/ 08399 template<typename T> 08400 struct CImg { 08401 08402 //! Variable representing the width of the instance image (i.e. dimensions along the X-axis). 08403 /** 08404 \remark 08405 - Prefer using the function CImg<T>::width() to get information about the width of an image. 08406 - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably 08407 result in a library crash. 08408 - Empty images have \c width defined to \c 0. 08409 **/ 08410 unsigned int _width; 08411 08412 //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis). 08413 /** 08414 \remark 08415 - Prefer using the function CImg<T>::height() to get information about the height of an image. 08416 - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably 08417 result in a library crash. 08418 - 1d signals have \c height defined to \c 1. 08419 - Empty images have \c height defined to \c 0. 08420 **/ 08421 unsigned int _height; 08422 08423 //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis). 08424 /** 08425 \remark 08426 - Prefer using the function CImg<T>::depth() to get information about the depth of an image. 08427 - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably 08428 result in a library crash. 08429 - Classical 2d images have \c depth defined to \c 1. 08430 - Empty images have \c depth defined to \c 0. 08431 **/ 08432 unsigned int _depth; 08433 08434 //! Variable representing the number of channels of the instance image (i.e. dimensions along the C-axis). 08435 /** 08436 \remark 08437 - Prefer using the function CImg<T>::spectrum() to get information about the depth of an image. 08438 - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c spectrum would probably 08439 result in a library crash. 08440 - Scalar-valued images (one value per pixel) have \c spectrum defined to \c 1. 08441 - Empty images have \c depth defined to \c 0. 08442 **/ 08443 unsigned int _spectrum; 08444 08445 //! Variable telling if pixel buffer of the instance image is shared with another one. 08446 bool _is_shared; 08447 08448 //! Pointer to the first pixel of the pixel buffer. 08449 T *_data; 08450 08451 //! Iterator type for CImg<T>. 08452 /** 08453 \remark 08454 - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer). 08455 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL. 08456 **/ 08457 typedef T* iterator; 08458 08459 //! Const iterator type for CImg<T>. 08460 /** 08461 \remark 08462 - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer). 08463 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL. 08464 **/ 08465 typedef const T* const_iterator; 08466 08467 //! Value type. 08468 typedef T value_type; 08469 08470 // Define common T-dependant types. 08471 typedef typename cimg::superset<T,bool>::type Tbool; 08472 typedef typename cimg::superset<T,unsigned char>::type Tuchar; 08473 typedef typename cimg::superset<T,char>::type Tchar; 08474 typedef typename cimg::superset<T,unsigned short>::type Tushort; 08475 typedef typename cimg::superset<T,short>::type Tshort; 08476 typedef typename cimg::superset<T,unsigned int>::type Tuint; 08477 typedef typename cimg::superset<T,int>::type Tint; 08478 typedef typename cimg::superset<T,unsigned long>::type Tulong; 08479 typedef typename cimg::superset<T,long>::type Tlong; 08480 typedef typename cimg::superset<T,float>::type Tfloat; 08481 typedef typename cimg::superset<T,double>::type Tdouble; 08482 typedef typename cimg::last<T,bool>::type boolT; 08483 typedef typename cimg::last<T,unsigned char>::type ucharT; 08484 typedef typename cimg::last<T,char>::type charT; 08485 typedef typename cimg::last<T,unsigned short>::type ushortT; 08486 typedef typename cimg::last<T,short>::type shortT; 08487 typedef typename cimg::last<T,unsigned int>::type uintT; 08488 typedef typename cimg::last<T,int>::type intT; 08489 typedef typename cimg::last<T,unsigned long>::type ulongT; 08490 typedef typename cimg::last<T,long>::type longT; 08491 typedef typename cimg::last<T,float>::type floatT; 08492 typedef typename cimg::last<T,double>::type doubleT; 08493 08494 //@} 08495 //--------------------------- 08496 // 08497 //! \name Plugins 08498 //@{ 08499 //--------------------------- 08500 #ifdef cimg_plugin 08501 #include cimg_plugin 08502 #endif 08503 #ifdef cimg_plugin1 08504 #include cimg_plugin1 08505 #endif 08506 #ifdef cimg_plugin2 08507 #include cimg_plugin2 08508 #endif 08509 #ifdef cimg_plugin3 08510 #include cimg_plugin3 08511 #endif 08512 #ifdef cimg_plugin4 08513 #include cimg_plugin4 08514 #endif 08515 #ifdef cimg_plugin5 08516 #include cimg_plugin5 08517 #endif 08518 #ifdef cimg_plugin6 08519 #include cimg_plugin6 08520 #endif 08521 #ifdef cimg_plugin7 08522 #include cimg_plugin7 08523 #endif 08524 #ifdef cimg_plugin8 08525 #include cimg_plugin8 08526 #endif 08527 08528 //@} 08529 //--------------------------------------------------------- 08530 // 08531 //! \name Constructors / Destructor / Instance Management 08532 //@{ 08533 //--------------------------------------------------------- 08534 08535 //! Destructor. 08536 /** 08537 The destructor destroys the instance image. 08538 \remark 08539 - Destructing an empty or shared image does nothing. 08540 - Otherwise, all memory used to store the pixel data of the instance image is freed. 08541 - When destroying a non-shared image, be sure that every shared instances of the same image are 08542 also destroyed to avoid further access to desallocated memory buffers. 08543 **/ 08544 ~CImg() { 08545 if (_data && !_is_shared) delete[] _data; 08546 } 08547 08548 //! Default constructor. 08549 /** 08550 The default constructor creates an empty instance image. 08551 \remark 08552 - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref spectrum 08553 set to 0 as well as its pointer to the pixel buffer \ref data. 08554 - An empty image is non-shared. 08555 **/ 08556 CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {} 08557 08558 //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dc). 08559 /** 08560 This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dc) with pixels of type \p T. 08561 \param dx Desired size along the X-axis, i.e. the \ref width of the image. 08562 \param dy Desired size along the Y-axis, i.e. the \ref height of the image. 08563 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. 08564 \param dc Desired size along the C-axis, i.e. the number of image channels \ref spectrum. 08565 \remark 08566 - If one of the input dimension \p dx,\p dy,\p dz or \p dc is set to 0, the created image is empty 08567 and all has its dimensions set to 0. No memory for pixel data is then allocated. 08568 - This constructor creates only non-shared images. 08569 - Image pixels allocated by this constructor are \b not \b initialized. 08570 Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T) 08571 to get an image of desired size with pixels set to a particular value. 08572 **/ 08573 explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1): 08574 _is_shared(false) { 08575 const unsigned int siz = dx*dy*dz*dc; 08576 if (siz) { 08577 _width = dx; _height = dy; _depth = dz; _spectrum = dc; 08578 try { _data = new T[siz]; } catch (...) { 08579 _width = _height = _depth = _spectrum = 0; _data = 0; 08580 throw CImgInstanceException(_cimg_instance 08581 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08582 cimg_instance, 08583 dx,dy,dz,dc); 08584 } 08585 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08586 } 08587 08588 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dc) and with pixel having a default value \p val. 08589 /** 08590 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dc) with pixels of type \p T and sets all pixel 08591 values of the created instance image to \p val. 08592 \param dx Desired size along the X-axis, i.e. the \ref width of the image. 08593 \param dy Desired size along the Y-axis, i.e. the \ref height of the image. 08594 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. 08595 \param dc Desired size along the C-axis, i.e. the number of image channels \p spectrum. 08596 \param val Default value for image pixels. 08597 \remark 08598 - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int). 08599 **/ 08600 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, const T val): 08601 _is_shared(false) { 08602 const unsigned int siz = dx*dy*dz*dc; 08603 if (siz) { 08604 _width = dx; _height = dy; _depth = dz; _spectrum = dc; 08605 try { _data = new T[siz]; } catch (...) { 08606 _width = _height = _depth = _spectrum = 0; _data = 0; 08607 throw CImgInstanceException(_cimg_instance 08608 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08609 cimg_instance, 08610 dx,dy,dz,dc); 08611 } 08612 fill(val); 08613 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08614 } 08615 08616 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dc) and with specified pixel values (int version). 08617 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08618 const int val0, const int val1, ...):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08619 #define _CImg_stdarg(img,a0,a1,N,t) { \ 08620 unsigned int _siz = (unsigned int)N; \ 08621 if (_siz--) { \ 08622 va_list ap; \ 08623 va_start(ap,a1); \ 08624 T *ptrd = (img)._data; \ 08625 *(ptrd++) = (T)a0; \ 08626 if (_siz--) { \ 08627 *(ptrd++) = (T)a1; \ 08628 for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ 08629 } \ 08630 va_end(ap); \ 08631 } \ 08632 } 08633 assign(dx,dy,dz,dc); 08634 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dc,int); 08635 } 08636 08637 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dc) and with specified pixel values (double version). 08638 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08639 const double val0, const double val1, ...):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08640 assign(dx,dy,dz,dc); 08641 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dc,double); 08642 } 08643 08644 //! Construct an image with given size and with specified values given in a string. 08645 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08646 const char *const values, const bool repeat_values):_is_shared(false) { 08647 const unsigned int siz = dx*dy*dz*dc; 08648 if (siz) { 08649 _width = dx; _height = dy; _depth = dz; _spectrum = dc; 08650 try { _data = new T[siz]; } catch (...) { 08651 _width = _height = _depth = _spectrum = 0; _data = 0; 08652 throw CImgInstanceException(_cimg_instance 08653 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08654 cimg_instance, 08655 dx,dy,dz,dc); 08656 } 08657 fill(values,repeat_values); 08658 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08659 } 08660 08661 //! Construct an image from a raw memory buffer. 08662 /** 08663 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dc) and fill its pixel buffer by 08664 copying data values from the input raw pixel buffer \p data_buffer. 08665 **/ 08666 template<typename t> 08667 CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, 08668 const unsigned int dz=1, const unsigned int dc=1, const bool shared=false):_is_shared(false) { 08669 if (shared) { 08670 _width = _height = _depth = _spectrum = 0; _data = 0; 08671 throw CImgArgumentException(_cimg_instance 08672 "CImg() : Invalid construction request of a (%u,%u,%u,%u) shared instance from a (%s*) buffer " 08673 "(pixel types are different).", 08674 cimg_instance, 08675 dx,dy,dz,dc,CImg<t>::pixel_type()); 08676 } 08677 const unsigned int siz = dx*dy*dz*dc; 08678 if (data_buffer && siz) { 08679 _width = dx; _height = dy; _depth = dz; _spectrum = dc; 08680 try { _data = new T[siz]; } catch (...) { 08681 _width = _height = _depth = _spectrum = 0; _data = 0; 08682 throw CImgInstanceException(_cimg_instance 08683 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08684 cimg_instance, 08685 dx,dy,dz,dc); 08686 08687 } 08688 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); 08689 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08690 } 08691 08692 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, 08693 const unsigned int dz=1, const unsigned int dc=1, const bool shared=false) { 08694 const unsigned int siz = dx*dy*dz*dc; 08695 if (data_buffer && siz) { 08696 _width = dx; _height = dy; _depth = dz; _spectrum = dc; _is_shared = shared; 08697 if (_is_shared) _data = const_cast<T*>(data_buffer); 08698 else { 08699 try { _data = new T[siz]; } catch (...) { 08700 _width = _height = _depth = _spectrum = 0; _data = 0; 08701 throw CImgInstanceException(_cimg_instance 08702 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08703 cimg_instance, 08704 dx,dy,dz,dc); 08705 } 08706 std::memcpy(_data,data_buffer,siz*sizeof(T)); } 08707 } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } 08708 } 08709 08710 //! Construct an image from an image file. 08711 /** 08712 This constructor creates an instance image by reading it from a file. 08713 \param filename Filename of the image file. 08714 \remark 08715 - The image format is deduced from the filename only by looking for the filename extension i.e. without 08716 analyzing the file itself. 08717 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with. 08718 More informations on this topic can be found in cimg_files_io. 08719 - If the filename is not found, a CImgIOException is thrown by this constructor. 08720 **/ 08721 explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08722 assign(filename); 08723 } 08724 08725 //! Default copy constructor. 08726 /** 08727 The default copy constructor creates a new instance image having same dimensions 08728 (\ref width, \ref height, \ref depth, \ref _spectrum) and same pixel values as the input image \p img. 08729 \param img The input image to copy. 08730 \remark 08731 - If the input image \p img is non-shared or have a different template type \p t != \p T, 08732 the default copy constructor allocates a new pixel buffer and copy the pixel data 08733 of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different 08734 and the resulting instance image is non-shared. 08735 - If the input image \p img is shared and has the same template type \p t == \p T, 08736 the default copy constructor does not allocate a new pixel buffer and the resulting instance image 08737 shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies 08738 the created instance image. 08739 - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from 08740 type \p t to type \p T. 08741 - Copying an image having the same template type \p t == \p T is significantly faster. 08742 **/ 08743 template<typename t> 08744 CImg(const CImg<t>& img):_is_shared(false) { 08745 const unsigned int siz = img.size(); 08746 if (img._data && siz) { 08747 _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; 08748 try { _data = new T[siz]; } catch (...) { 08749 _width = _height = _depth = _spectrum = 0; _data = 0; 08750 throw CImgInstanceException(_cimg_instance 08751 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08752 cimg_instance, 08753 img._width,img._height,img._depth,img._spectrum); 08754 } 08755 const t *ptrs = img._data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); 08756 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08757 } 08758 08759 CImg(const CImg<T>& img) { 08760 const unsigned int siz = img.size(); 08761 if (img._data && siz) { 08762 _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = img._is_shared; 08763 if (_is_shared) _data = const_cast<T*>(img._data); 08764 else { 08765 try { _data = new T[siz]; } catch (...) { 08766 _width = _height = _depth = _spectrum = 0; _data = 0; 08767 throw CImgInstanceException(_cimg_instance 08768 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08769 cimg_instance, 08770 img._width,img._height,img._depth,img._spectrum); 08771 08772 } 08773 std::memcpy(_data,img._data,siz*sizeof(T)); 08774 } 08775 } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } 08776 } 08777 08778 //! Advanced copy constructor. 08779 /** 08780 The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions 08781 \ref width, \ref height, \ref depth, \ref spectrum and same pixel values as the input image \p img. 08782 But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter 08783 \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false). 08784 \param img The input image to copy. 08785 \param shared Boolean flag that decides if the copy is shared on non-shared. 08786 \remark 08787 - It is not possible to create a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T. 08788 - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data. 08789 - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance 08790 image is the same as the one used by the input image \p img. 08791 **/ 08792 template<typename t> 08793 CImg(const CImg<t>& img, const bool shared):_is_shared(false) { 08794 if (shared) { 08795 _width = _height = _depth = _spectrum = 0; _data = 0; 08796 throw CImgArgumentException(_cimg_instance 08797 "CImg() : Invalid construction request of a shared instance from a " 08798 "CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).", 08799 cimg_instance, 08800 CImg<t>::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data); 08801 } 08802 08803 const unsigned int siz = img.size(); 08804 if (img._data && siz) { 08805 _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; 08806 try { _data = new T[siz]; } catch (...) { 08807 _width = _height = _depth = _spectrum = 0; _data = 0; 08808 throw CImgInstanceException(_cimg_instance 08809 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08810 cimg_instance, 08811 img._width,img._height,img._depth,img._spectrum); 08812 } 08813 const t *ptrs = img._data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); 08814 } else { _width = _height = _depth = _spectrum = 0; _data = 0; } 08815 } 08816 08817 CImg(const CImg<T>& img, const bool shared) { 08818 const unsigned int siz = img.size(); 08819 if (img._data && siz) { 08820 _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = shared; 08821 if (_is_shared) _data = const_cast<T*>(img._data); 08822 else { 08823 try { _data = new T[siz]; } catch (...) { 08824 _width = _height = _depth = _spectrum = 0; _data = 0; 08825 throw CImgInstanceException(_cimg_instance 08826 "CImg() : Failed to allocate memory for image (%u,%u,%u,%u).", 08827 cimg_instance, 08828 img._width,img._height,img._depth,img._spectrum); 08829 } 08830 std::memcpy(_data,img._data,siz*sizeof(T)); 08831 } 08832 } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } 08833 } 08834 08835 //! Construct an image using dimensions of another image 08836 template<typename t> 08837 CImg(const CImg<t>& img, const char *const dimensions):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08838 assign(img,dimensions); 08839 } 08840 08841 //! Construct an image using dimensions of another image, and fill it with given values. 08842 template<typename t> 08843 CImg(const CImg<t>& img, const char *const dimensions, const T val): 08844 _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08845 assign(img,dimensions).fill(val); 08846 } 08847 08848 //! Construct an image using dimensions of another image, and fill it with given values. 08849 template<typename t> 08850 CImg(const CImg<t>& img, const char *const dimensions, const char *const values, const bool repeat_values): 08851 _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08852 assign(img,dimensions).fill(values,repeat_values); 08853 } 08854 08855 //! Construct an image from the content of a CImgDisplay instance. 08856 explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 08857 disp.snapshot(*this); 08858 } 08859 08860 //! Return a shared version of the instance image. 08861 CImg<T> get_shared() { 08862 return CImg<T>(_data,_width,_height,_depth,_spectrum,true); 08863 } 08864 08865 const CImg<T> get_shared() const { 08866 return CImg<T>(_data,_width,_height,_depth,_spectrum,true); 08867 } 08868 08869 //! In-place version of the default constructor (STL-compliant name). 08870 /** 08871 This function is strictly equivalent to \ref assign() and has been 08872 introduced for having a STL-compatible function name. 08873 **/ 08874 CImg<T>& clear() { 08875 return assign(); 08876 } 08877 08878 //! In-place version of the default constructor/destructor. 08879 /** 08880 This function replaces the instance image by an empty image. 08881 \remark 08882 - Memory used by the previous content of the instance image is freed if necessary. 08883 - If the instance image was initially shared, it is replaced by a (non-shared) empty image. 08884 - This function is useful to free memory used by an image that is not of use, but which 08885 has been created in the current code scope (i.e. not destroyed yet). 08886 **/ 08887 CImg<T>& assign() { 08888 if (_data && !_is_shared) delete[] _data; 08889 _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; 08890 return *this; 08891 } 08892 08893 //! In-place version of the previous constructor. 08894 /** 08895 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dc) with pixels of type \p T. 08896 \param dx Desired size along the X-axis, i.e. the \ref width of the image. 08897 \param dy Desired size along the Y-axis, i.e. the \ref height of the image. 08898 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. 08899 \param dc Desired size along the C-axis, i.e. the number of image channels \p _spectrum. 08900 - If one of the input dimension \p dx,\p dy,\p dz or \p dc is set to 0, the instance image becomes empty 08901 and all has its dimensions set to 0. No memory for pixel data is then allocated. 08902 - Memory buffer used to store previous pixel values is freed if necessary. 08903 - If the instance image is shared, this constructor actually does nothing more than verifying 08904 that new and old image dimensions fit. 08905 - Image pixels allocated by this function are \b not \b initialized. 08906 Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T) 08907 to assign an image of desired size with pixels set to a particular value. 08908 **/ 08909 CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dc=1) { 08910 const unsigned int siz = dx*dy*dz*dc; 08911 if (!siz) return assign(); 08912 const unsigned int curr_siz = size(); 08913 if (siz!=curr_siz) { 08914 if (_is_shared) 08915 throw CImgArgumentException(_cimg_instance 08916 "assign() : Invalid assignement request of shared instance from specified image (%u,%u,%u,%u).", 08917 cimg_instance, 08918 dx,dy,dz,dc); 08919 else { 08920 if (_data) delete[] _data; 08921 try { _data = new T[siz]; } catch (...) { 08922 _width = _height = _depth = _spectrum = 0; _data = 0; 08923 throw CImgInstanceException(_cimg_instance 08924 "assign() : Failed to allocate memory for image (%u,%u,%u,%u).", 08925 cimg_instance, 08926 dx,dy,dz,dc); 08927 } 08928 } 08929 } 08930 _width = dx; _height = dy; _depth = dz; _spectrum = dc; 08931 return *this; 08932 } 08933 08934 //! In-place version of the previous constructor. 08935 /** 08936 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dc) with pixels of type \p T 08937 and sets all pixel values of the instance image to \p val. 08938 \param dx Desired size along the X-axis, i.e. the \ref width of the image. 08939 \param dy Desired size along the Y-axis, i.e. the \ref height of the image. 08940 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. 08941 \param dc Desired size along the C-axis, i.e. the number of image channels \p _spectrum. 08942 \param val Default value for image pixels. 08943 \remark 08944 - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int). 08945 **/ 08946 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, const T val) { 08947 return assign(dx,dy,dz,dc).fill(val); 08948 } 08949 08950 //! In-place version of the previous constructor. 08951 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08952 const int val0, const int val1, ...) { 08953 assign(dx,dy,dz,dc); 08954 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dc,int); 08955 return *this; 08956 } 08957 08958 //! In-place version of the previous constructor. 08959 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08960 const double val0, const double val1, ...) { 08961 assign(dx,dy,dz,dc); 08962 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dc,double); 08963 return *this; 08964 } 08965 08966 //! In-place version of the corresponding constructor. 08967 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc, 08968 const char *const values, const bool repeat_values) { 08969 return assign(dx,dy,dz,dc).fill(values,repeat_values); 08970 } 08971 08972 //! In-place version of the previous constructor. 08973 template<typename t> 08974 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, 08975 const unsigned int dz=1, const unsigned int dc=1) { 08976 const unsigned int siz = dx*dy*dz*dc; 08977 if (!data_buffer || !siz) return assign(); 08978 assign(dx,dy,dz,dc); 08979 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); 08980 return *this; 08981 } 08982 08983 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, 08984 const unsigned int dz=1, const unsigned int dc=1) { 08985 const unsigned int siz = dx*dy*dz*dc; 08986 if (!data_buffer || !siz) return assign(); 08987 const unsigned int curr_siz = size(); 08988 if (data_buffer==_data && siz==curr_siz) return assign(dx,dy,dz,dc); 08989 if (_is_shared || data_buffer+siz<_data || data_buffer>=_data+size()) { 08990 assign(dx,dy,dz,dc); 08991 if (_is_shared) std::memmove(_data,data_buffer,siz*sizeof(T)); 08992 else std::memcpy(_data,data_buffer,siz*sizeof(T)); 08993 } else { 08994 T *new_data = 0; 08995 try { new_data = new T[siz]; } catch (...) { 08996 _width = _height = _depth = _spectrum = 0; _data = 0; 08997 throw CImgInstanceException(_cimg_instance 08998 "assign() : Failed to allocate memory for image (%u,%u,%u,%u).", 08999 cimg_instance, 09000 dx,dy,dz,dc); 09001 } 09002 std::memcpy(new_data,data_buffer,siz*sizeof(T)); 09003 delete[] _data; _data = new_data; _width = dx; _height = dy; _depth = dz; _spectrum = dc; 09004 } 09005 return *this; 09006 } 09007 09008 //! In-place version of the previous constructor, allowing to force the shared state of the instance image. 09009 template<typename t> 09010 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy, 09011 const unsigned int dz, const unsigned int dc, const bool shared) { 09012 if (shared) 09013 throw CImgArgumentException(_cimg_instance 09014 "assign() : Invalid assignment request of shared instance from (%s*) buffer" 09015 "(pixel types are different).", 09016 cimg_instance, 09017 CImg<t>::pixel_type()); 09018 09019 return assign(data_buffer,dx,dy,dz,dc); 09020 } 09021 09022 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy, 09023 const unsigned int dz, const unsigned int dc, const bool shared) { 09024 const unsigned int siz = dx*dy*dz*dc; 09025 if (!data_buffer || !siz) { 09026 if (shared) throw CImgArgumentException(_cimg_instance 09027 "assign() : Invalid assignment request of shared instance from (null) or empty buffer.", 09028 cimg_instance); 09029 else return assign(); 09030 } 09031 if (!shared) { if (_is_shared) assign(); assign(data_buffer,dx,dy,dz,dc); } 09032 else { 09033 if (!_is_shared) { 09034 if (data_buffer+siz<_data || data_buffer>=_data+size()) assign(); 09035 else cimg::warn(_cimg_instance 09036 "assign() : Shared instance image has overlapping memory.", 09037 cimg_instance); 09038 } 09039 _width = dx; _height = dy; _depth = dz; _spectrum = dc; _is_shared = true; 09040 _data = const_cast<T*>(data_buffer); 09041 } 09042 return *this; 09043 } 09044 09045 //! In-place version of the previous constructor. 09046 /** 09047 This function replaces the instance image by the one that have been read from the given file. 09048 \param filename Filename of the image file. 09049 - The image format is deduced from the filename only by looking for the filename extension i.e. without 09050 analyzing the file itself. 09051 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with. 09052 More informations on this topic can be found in cimg_files_io. 09053 - If the filename is not found, a CImgIOException is thrown by this constructor. 09054 **/ 09055 CImg<T>& assign(const char *const filename) { 09056 return load(filename); 09057 } 09058 09059 //! In-place version of the default copy constructor. 09060 /** 09061 This function assigns a copy of the input image \p img to the current instance image. 09062 \param img The input image to copy. 09063 \remark 09064 - If the instance image is non-shared, the content of the input image \p img is copied into a new buffer 09065 becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary. 09066 - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer 09067 of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared. 09068 **/ 09069 template<typename t> 09070 CImg<T>& assign(const CImg<t>& img) { 09071 return assign(img._data,img._width,img._height,img._depth,img._spectrum); 09072 } 09073 09074 //! In-place version of the advanced constructor. 09075 /** 09076 This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the 09077 current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true) 09078 or non-shared (if the input parameter \p shared is set to \c false). 09079 \param img The input image to copy. 09080 \param shared Boolean flag that decides if the copy is shared or non-shared. 09081 \remark 09082 - It is not possible to assign a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T. 09083 - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data. 09084 - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance 09085 image is the same as the one used by the input image \p img. 09086 **/ 09087 template<typename t> 09088 CImg<T>& assign(const CImg<t>& img, const bool shared) { 09089 return assign(img._data,img._width,img._height,img._depth,img._spectrum,shared); 09090 } 09091 09092 //! In-place version of the previous constructor. 09093 template<typename t> 09094 CImg<T>& assign(const CImg<t>& img, const char *const dimensions) { 09095 if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum); 09096 unsigned int siz[4] = { 0,1,1,1 }, k = 0; 09097 for (const char *s = dimensions; *s && k<4; ++k) { 09098 char item[256] = { 0 }; 09099 if (std::sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item)>0) s+=std::strlen(item); 09100 if (*s) { 09101 unsigned int val = 0; char sep = 0; 09102 if (std::sscanf(s,"%u%c",&val,&sep)>0) { 09103 if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100; 09104 else siz[k] = val; 09105 while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s; 09106 } else switch (cimg::uncase(*s)) { 09107 case 'x' : case 'w' : siz[k] = img._width; ++s; break; 09108 case 'y' : case 'h' : siz[k] = img._height; ++s; break; 09109 case 'z' : case 'd' : siz[k] = img._depth; ++s; break; 09110 case 'v' : case 'c' : siz[k] = img._spectrum; ++s; break; 09111 default : 09112 throw CImgArgumentException(_cimg_instance 09113 "assign() : Invalid character '%c' detected in specified dimension string '%s'.", 09114 cimg_instance, 09115 *s,dimensions); 09116 } 09117 } 09118 } 09119 return assign(siz[0],siz[1],siz[2],siz[3]); 09120 } 09121 09122 //! In-place version of the previous constructor. 09123 template<typename t> 09124 CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) { 09125 return assign(img,dimensions).fill(val); 09126 } 09127 09128 //! In-place version of the previous constructor. 09129 template<typename t> 09130 CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const char *const values, const bool repeat_values) { 09131 return assign(img,dimensions).fill(values,repeat_values); 09132 } 09133 09134 //! In-place version of the previous constructor. 09135 CImg<T>& assign(const CImgDisplay &disp) { 09136 disp.snapshot(*this); 09137 return *this; 09138 } 09139 09140 //! Move the content of the instance image into another one in a way that memory copies are avoided if possible. 09141 /** 09142 The instance image is always empty after a call to this function. 09143 **/ 09144 template<typename t> 09145 CImg<t>& move_to(CImg<t>& img) { 09146 img.assign(*this); 09147 assign(); 09148 return img; 09149 } 09150 09151 CImg<T>& move_to(CImg<T>& img) { 09152 if (_is_shared || img._is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); } 09153 return img; 09154 } 09155 09156 template<typename t> 09157 CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos=~0U) { 09158 const unsigned int npos = pos>list._width?list._width:pos; 09159 move_to(list.insert(1,npos)[npos]); 09160 return list; 09161 } 09162 09163 //! Return a reference to an empty image. 09164 static CImg<T>& empty() { 09165 static CImg<T> _empty; 09166 return _empty.assign(); 09167 } 09168 09169 //! Swap all fields of two images. Use with care ! 09170 CImg<T>& swap(CImg<T>& img) { 09171 cimg::swap(_width,img._width); 09172 cimg::swap(_height,img._height); 09173 cimg::swap(_depth,img._depth); 09174 cimg::swap(_spectrum,img._spectrum); 09175 cimg::swap(_data,img._data); 09176 cimg::swap(_is_shared,img._is_shared); 09177 return img; 09178 } 09179 09180 //@} 09181 //------------------------------------------ 09182 // 09183 //! \name Overloaded Operators 09184 //@{ 09185 //------------------------------------------ 09186 09187 //! Fast access to pixel value for reading or writing. 09188 /** 09189 \param x X-coordinate of the pixel. 09190 \param y Y-coordinate of the pixel. 09191 \param z Z-coordinate of the pixel. 09192 \param v C-coordinate of the pixel. 09193 09194 - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below). 09195 - If the macro \c 'cimg_verbosity'>=3, boundary checking is performed and warning messages may appear 09196 (but function performances decrease). 09197 09198 \par example: 09199 \code 09200 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. 09201 const float valR = img(10,10,0,0); // Read the red component at coordinates (10,10). 09202 const float valG = img(10,10,0,1); // Read the green component at coordinates (10,10) 09203 const float valB = img(10,10,2); // Read the blue component at coordinates (10,10) (Z-coordinate omitted here). 09204 const float avg = (valR + valG + valB)/3; // Compute average pixel value. 09205 img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the pixel (10,10) by the average grey value. 09206 \endcode 09207 **/ 09208 #if cimg_verbosity>=3 09209 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { 09210 const unsigned int off = (unsigned int)offset(x,y,z,c); 09211 if (!_data || off>=size()) { 09212 cimg::warn(_cimg_instance 09213 "operator() : Invalid pixel request, at coordinates (%u,%u,%u,%u) [offset=%u].", 09214 cimg_instance, 09215 x,y,z,c,off); 09216 return *_data; 09217 } 09218 else return _data[off]; 09219 } 09220 09221 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { 09222 return const_cast<CImg<T>*>(this)->operator()(x,y,z,c); 09223 } 09224 09225 #else 09226 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { 09227 return _data[x + y*_width + z*_width*_height + c*_width*_height*_depth]; 09228 } 09229 09230 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { 09231 return _data[x + y*_width + z*_width*_height + c*_width*_height*_depth]; 09232 } 09233 #endif 09234 09235 //! Return address of the pixel buffer. 09236 operator const T*() const { 09237 return _data; 09238 } 09239 09240 operator T*() { 09241 return _data; 09242 } 09243 09244 //! Operator=(). 09245 /** 09246 Assignment operator. Fill all pixels of the instance image with the same value. 09247 The image size is not modified. 09248 **/ 09249 CImg<T>& operator=(const T val) { 09250 return fill(val); 09251 } 09252 09253 //! Operator=(). 09254 /** 09255 Assignment operator. 09256 If \p expression is a formula or a list of values, the image pixels are filled 09257 according to the expression and the image size is not modified. 09258 If \p expression is a filename, the image is replaced by the input file data 09259 (so image size is modified). 09260 **/ 09261 CImg<T>& operator=(const char *const expression) { 09262 const unsigned int omode = cimg::exception_mode(); 09263 cimg::exception_mode() = 0; 09264 try { 09265 fill(expression,true); 09266 } catch (CImgException&) { 09267 cimg::exception_mode() = omode; 09268 load(expression); 09269 } 09270 cimg::exception_mode() = omode; 09271 return *this; 09272 } 09273 09274 //! Operator=(). 09275 /** 09276 Assignement operator. 09277 If instance image is non-shared, replace the instance image by a copy of the argument image. 09278 If instance image is shared, replace the image content by the content of the argument image. 09279 **/ 09280 template<typename t> 09281 CImg<T>& operator=(const CImg<t>& img) { 09282 return assign(img); 09283 } 09284 09285 CImg<T>& operator=(const CImg<T>& img) { 09286 return assign(img); 09287 } 09288 09289 //! Operator=(). 09290 CImg<T>& operator=(const CImgDisplay& disp) { 09291 disp.snapshot(*this); 09292 return *this; 09293 } 09294 09295 //! Operator+=(). 09296 template<typename t> 09297 CImg<T>& operator+=(const t val) { 09298 cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd + val); 09299 return *this; 09300 } 09301 09302 //! Operator+=(). 09303 CImg<T>& operator+=(const char *const expression) { 09304 const unsigned int omode = cimg::exception_mode(); 09305 cimg::exception_mode() = 0; 09306 try { 09307 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09308 _cimg_math_parser mp(base,expression,"operator+="); 09309 T *ptrd = _data; 09310 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp.eval(x,y,z,c)); ++ptrd; } 09311 } catch (CImgException&) { 09312 cimg::exception_mode() = omode; 09313 CImg<T> values(_width,_height,_depth,_spectrum); 09314 values = expression; 09315 *this+=values; 09316 } 09317 cimg::exception_mode() = omode; 09318 return *this; 09319 } 09320 09321 //! Operator+=(). 09322 template<typename t> 09323 CImg<T>& operator+=(const CImg<t>& img) { 09324 const unsigned int siz = size(), isiz = img.size(); 09325 if (siz && isiz) { 09326 if (is_overlapped(img)) return *this+=+img; 09327 T *ptrd = _data, *const ptre = _data + siz; 09328 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09329 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++)); 09330 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++)); 09331 } 09332 return *this; 09333 } 09334 09335 //! Operator++() (prefix). 09336 CImg<T>& operator++() { 09337 cimg_for(*this,ptrd,T) ++*ptrd; 09338 return *this; 09339 } 09340 09341 //! Operator++() (postfix). 09342 CImg<T> operator++(int) { 09343 const CImg<T> copy(*this,false); 09344 ++*this; 09345 return copy; 09346 } 09347 09348 //! Operator+() (unary). 09349 /** 09350 \remark 09351 - This operator always returns a non-shared copy of an image. 09352 **/ 09353 CImg<T> operator+() const { 09354 return CImg<T>(*this,false); 09355 } 09356 09357 //! Operator+(). 09358 template<typename t> 09359 CImg<_cimg_Tt> operator+(const t val) const { 09360 return CImg<_cimg_Tt>(*this,false)+=val; 09361 } 09362 09363 //! Operator+(). 09364 CImg<Tfloat> operator+(const char *const expression) const { 09365 return CImg<Tfloat>(*this,false)+=expression; 09366 } 09367 09368 //! Operator+(). 09369 template<typename t> 09370 CImg<_cimg_Tt> operator+(const CImg<t>& img) const { 09371 return CImg<_cimg_Tt>(*this,false)+=img; 09372 } 09373 09374 //! Operator-=(). 09375 template<typename t> 09376 CImg<T>& operator-=(const t val) { 09377 cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd - val); 09378 return *this; 09379 } 09380 09381 //! Operator-=(). 09382 CImg<T>& operator-=(const char *const expression) { 09383 const unsigned int omode = cimg::exception_mode(); 09384 cimg::exception_mode() = 0; 09385 try { 09386 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09387 _cimg_math_parser mp(base,expression,"operator-="); 09388 T *ptrd = _data; 09389 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp.eval(x,y,z,c)); ++ptrd; } 09390 } catch (CImgException&) { 09391 cimg::exception_mode() = omode; 09392 CImg<T> values(_width,_height,_depth,_spectrum); 09393 values = expression; 09394 *this-=values; 09395 } 09396 cimg::exception_mode() = omode; 09397 return *this; 09398 } 09399 09400 //! Operator-=(). 09401 template<typename t> 09402 CImg<T>& operator-=(const CImg<t>& img) { 09403 const unsigned int siz = size(), isiz = img.size(); 09404 if (siz && isiz) { 09405 if (is_overlapped(img)) return *this-=+img; 09406 T *ptrd = _data, *const ptre = _data + siz; 09407 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09408 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++)); 09409 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++)); 09410 } 09411 return *this; 09412 } 09413 09414 //! Operator--() (prefix). 09415 CImg<T>& operator--() { 09416 cimg_for(*this,ptrd,T) *ptrd = *ptrd-(T)1; 09417 return *this; 09418 } 09419 09420 //! Operator--() (postfix). 09421 CImg<T> operator--(int) { 09422 const CImg<T> copy(*this,false); 09423 --*this; 09424 return copy; 09425 } 09426 09427 //! Operator-() (unary). 09428 CImg<T> operator-() const { 09429 return CImg<T>(_width,_height,_depth,_spectrum,(T)0)-=*this; 09430 } 09431 09432 //! Operator-(). 09433 template<typename t> 09434 CImg<_cimg_Tt> operator-(const t val) const { 09435 return CImg<_cimg_Tt>(*this,false)-=val; 09436 } 09437 09438 //! Operator-(). 09439 CImg<Tfloat> operator-(const char *const expression) const { 09440 return CImg<Tfloat>(*this,false)-=expression; 09441 } 09442 09443 //! Operator-(). 09444 template<typename t> 09445 CImg<_cimg_Tt> operator-(const CImg<t>& img) const { 09446 return CImg<_cimg_Tt>(*this,false)-=img; 09447 } 09448 09449 //! Operator*=(). 09450 template<typename t> 09451 CImg<T>& operator*=(const t val) { 09452 cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd * val); 09453 return *this; 09454 } 09455 09456 //! Operator*=(). 09457 CImg<T>& operator*=(const char *const expression) { 09458 const unsigned int omode = cimg::exception_mode(); 09459 cimg::exception_mode() = 0; 09460 try { 09461 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09462 _cimg_math_parser mp(base,expression,"operator*="); 09463 T *ptrd = _data; 09464 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp.eval(x,y,z,c)); ++ptrd; } 09465 } catch (CImgException&) { 09466 cimg::exception_mode() = omode; 09467 CImg<Tfloat> values(_width,_height,_depth,_spectrum); 09468 values = expression; 09469 *this*=values; 09470 } 09471 cimg::exception_mode() = omode; 09472 return *this; 09473 } 09474 09475 //! Operator*=(). 09476 template<typename t> 09477 CImg<T>& operator*=(const CImg<t>& img) { 09478 return ((*this)*img).move_to(*this); 09479 } 09480 09481 //! Operator*(). 09482 template<typename t> 09483 CImg<_cimg_Tt> operator*(const t val) const { 09484 return CImg<_cimg_Tt>(*this,false)*=val; 09485 } 09486 09487 //! Operator*(). 09488 CImg<Tfloat> operator*(const char *const expression) const { 09489 return CImg<Tfloat>(*this,false)*=expression; 09490 } 09491 09492 //! Operator*(). 09493 template<typename t> 09494 CImg<_cimg_Tt> operator*(const CImg<t>& img) const { 09495 if (_width!=img._height || _depth!=1 || _spectrum!=1) 09496 throw CImgArgumentException(_cimg_instance 09497 "operator*() : Invalid multiplication of instance by specified matrix (%u,%u,%u,%u,%p)", 09498 cimg_instance, 09499 img._width,img._height,img._depth,img._spectrum,img._data); 09500 09501 CImg<_cimg_Tt> res(img._width,_height); 09502 _cimg_Tt val, *ptrd = res._data; 09503 #ifdef cimg_use_openmp 09504 #pragma omp parallel for if (size()>=1000 && img.size()>=1000) private(val) 09505 #endif 09506 cimg_forXY(res,i,j) { val = 0; cimg_forX(*this,k) val+=(*this)(k,j)*img(i,k); *(ptrd++) = val; } 09507 return res; 09508 } 09509 09510 //! Operator/=(). 09511 template<typename t> 09512 CImg<T>& operator/=(const t val) { 09513 cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd / val); 09514 return *this; 09515 } 09516 09517 //! Operator/=(). 09518 CImg<T>& operator/=(const char *const expression) { 09519 const unsigned int omode = cimg::exception_mode(); 09520 cimg::exception_mode() = 0; 09521 try { 09522 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09523 _cimg_math_parser mp(base,expression,"operator/="); 09524 T *ptrd = _data; 09525 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp.eval(x,y,z,c)); ++ptrd; } 09526 } catch (CImgException&) { 09527 cimg::exception_mode() = omode; 09528 CImg<Tfloat> values(_width,_height,_depth,_spectrum); 09529 values = expression; 09530 *this/=values; 09531 } 09532 cimg::exception_mode() = omode; 09533 return *this; 09534 } 09535 09536 //! Operator/=(). 09537 template<typename t> 09538 CImg<T>& operator/=(const CImg<t>& img) { 09539 return (*this*img.get_invert()).move_to(*this); 09540 } 09541 09542 //! Operator/(). 09543 template<typename t> 09544 CImg<_cimg_Tt> operator/(const t val) const { 09545 return CImg<_cimg_Tt>(*this,false)/=val; 09546 } 09547 09548 //! Operator/(). 09549 CImg<Tfloat> operator/(const char *const expression) const { 09550 return CImg<Tfloat>(*this,false)/=expression; 09551 } 09552 09553 //! Operator/(). 09554 template<typename t> 09555 CImg<_cimg_Tt> operator/(const CImg<t>& img) const { 09556 return (*this)*img.get_invert(); 09557 } 09558 09559 //! Operator%=(). 09560 template<typename t> 09561 CImg<T>& operator%=(const t val) { 09562 cimg_for(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)val); 09563 return *this; 09564 } 09565 09566 //! Operator%=(). 09567 CImg<T>& operator%=(const char *const expression) { 09568 const unsigned int omode = cimg::exception_mode(); 09569 cimg::exception_mode() = 0; 09570 try { 09571 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09572 _cimg_math_parser mp(base,expression,"operator%="); 09573 T *ptrd = _data; 09574 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; } 09575 } catch (CImgException&) { 09576 cimg::exception_mode() = omode; 09577 CImg<T> values(_width,_height,_depth,_spectrum); 09578 values = expression; 09579 *this%=values; 09580 } 09581 cimg::exception_mode() = omode; 09582 return *this; 09583 } 09584 09585 //! Operator%=(). 09586 template<typename t> 09587 CImg<T>& operator%=(const CImg<t>& img) { 09588 const unsigned int siz = size(), isiz = img.size(); 09589 if (siz && isiz) { 09590 if (is_overlapped(img)) return *this%=+img; 09591 T *ptrd = _data, *const ptre = _data + siz; 09592 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09593 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++)); 09594 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++)); 09595 } 09596 return *this; 09597 } 09598 09599 //! Operator%(). 09600 template<typename t> 09601 CImg<_cimg_Tt> operator%(const t val) const { 09602 return CImg<_cimg_Tt>(*this,false)%=val; 09603 } 09604 09605 //! Operator%(). 09606 CImg<Tfloat> operator%(const char *const expression) const { 09607 return CImg<Tfloat>(*this,false)%=expression; 09608 } 09609 09610 //! Operator%(). 09611 template<typename t> 09612 CImg<_cimg_Tt> operator%(const CImg<t>& img) const { 09613 return CImg<_cimg_Tt>(*this,false)%=img; 09614 } 09615 09616 //! Operator&=(). 09617 template<typename t> 09618 CImg<T>& operator&=(const t val) { 09619 cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)val); 09620 return *this; 09621 } 09622 09623 //! Operator&=(). 09624 CImg<T>& operator&=(const char *const expression) { 09625 const unsigned int omode = cimg::exception_mode(); 09626 cimg::exception_mode() = 0; 09627 try { 09628 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09629 _cimg_math_parser mp(base,expression,"operator&="); 09630 T *ptrd = _data; 09631 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp.eval(x,y,z,c)); ++ptrd; } 09632 } catch (CImgException&) { 09633 cimg::exception_mode() = omode; 09634 CImg<T> values(_width,_height,_depth,_spectrum); 09635 values = expression; 09636 *this&=values; 09637 } 09638 cimg::exception_mode() = omode; 09639 return *this; 09640 } 09641 09642 //! Operator&=(). 09643 template<typename t> 09644 CImg<T>& operator&=(const CImg<t>& img) { 09645 const unsigned int siz = size(), isiz = img.size(); 09646 if (siz && isiz) { 09647 if (is_overlapped(img)) return *this&=+img; 09648 T *ptrd = _data, *const ptre = _data + siz; 09649 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09650 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++)); 09651 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++)); 09652 } 09653 return *this; 09654 } 09655 09656 //! Operator&(). 09657 template<typename t> 09658 CImg<T> operator&(const t val) const { 09659 return (+*this)&=val; 09660 } 09661 09662 //! Operator|=(). 09663 template<typename t> 09664 CImg<T>& operator|=(const t val) { 09665 cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)val); 09666 return *this; 09667 } 09668 09669 //! Operator|=(). 09670 CImg<T>& operator|=(const char *const expression) { 09671 const unsigned int omode = cimg::exception_mode(); 09672 cimg::exception_mode() = 0; 09673 try { 09674 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09675 _cimg_math_parser mp(base,expression,"operator|="); 09676 T *ptrd = _data; 09677 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp.eval(x,y,z,c)); ++ptrd; } 09678 } catch (CImgException&) { 09679 cimg::exception_mode() = omode; 09680 CImg<T> values(_width,_height,_depth,_spectrum); 09681 values = expression; 09682 *this|=values; 09683 } 09684 cimg::exception_mode() = omode; 09685 return *this; 09686 } 09687 09688 //! Operator|=(). 09689 template<typename t> 09690 CImg<T>& operator|=(const CImg<t>& img) { 09691 const unsigned int siz = size(), isiz = img.size(); 09692 if (siz && isiz) { 09693 if (is_overlapped(img)) return *this|=+img; 09694 T *ptrd = _data, *const ptre = _data + siz; 09695 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09696 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++)); 09697 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++)); 09698 } 09699 return *this; 09700 } 09701 09702 //! Operator|(). 09703 template<typename t> 09704 CImg<T> operator|(const t val) const { 09705 return (+*this)|=val; 09706 } 09707 09708 //! Operator^=(). 09709 template<typename t> 09710 CImg<T>& operator^=(const t val) { 09711 cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)val); 09712 return *this; 09713 } 09714 09715 //! Operator^=(). 09716 CImg<T>& operator^=(const char *const expression) { 09717 const unsigned int omode = cimg::exception_mode(); 09718 cimg::exception_mode() = 0; 09719 try { 09720 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09721 _cimg_math_parser mp(base,expression,"operator^="); 09722 T *ptrd = _data; 09723 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp.eval(x,y,z,c)); ++ptrd; } 09724 } catch (CImgException&) { 09725 cimg::exception_mode() = omode; 09726 CImg<T> values(_width,_height,_depth,_spectrum); 09727 values = expression; 09728 *this^=values; 09729 } 09730 cimg::exception_mode() = omode; 09731 return *this; 09732 } 09733 09734 //! Operator^=(). 09735 template<typename t> 09736 CImg<T>& operator^=(const CImg<t>& img) { 09737 const unsigned int siz = size(), isiz = img.size(); 09738 if (siz && isiz) { 09739 if (is_overlapped(img)) return *this^=+img; 09740 T *ptrd = _data, *const ptre = _data + siz; 09741 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09742 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++)); 09743 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++)); 09744 } 09745 return *this; 09746 } 09747 09748 //! Operator^(). 09749 template<typename t> 09750 CImg<T> operator^(const t val) const { 09751 return (+*this)^=val; 09752 } 09753 09754 //! Operator<<=(). 09755 template<typename t> 09756 CImg<T>& operator<<=(const t val) { 09757 cimg_for(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)val); 09758 return *this; 09759 } 09760 09761 //! Operator<<=(). 09762 CImg<T>& operator<<=(const char *const expression) { 09763 const unsigned int omode = cimg::exception_mode(); 09764 cimg::exception_mode() = 0; 09765 try { 09766 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09767 _cimg_math_parser mp(base,expression,"operator<<="); 09768 T *ptrd = _data; 09769 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp.eval(x,y,z,c)); ++ptrd; } 09770 } catch (CImgException&) { 09771 cimg::exception_mode() = omode; 09772 CImg<T> values(_width,_height,_depth,_spectrum); 09773 values = expression; 09774 *this<<=values; 09775 } 09776 cimg::exception_mode() = omode; 09777 return *this; 09778 } 09779 09780 //! Operator<<=(). 09781 template<typename t> 09782 CImg<T>& operator<<=(const CImg<t>& img) { 09783 const unsigned int siz = size(), isiz = img.size(); 09784 if (siz && isiz) { 09785 if (is_overlapped(img)) return *this^=+img; 09786 T *ptrd = _data, *const ptre = _data + siz; 09787 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09788 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((long)*ptrd << (int)*(ptrs++)); 09789 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((long)*ptrd << (int)*(ptrs++)); 09790 } 09791 return *this; 09792 } 09793 09794 //! Operator<<(). 09795 template<typename t> 09796 CImg<T> operator<<(const t val) const { 09797 return (+*this)<<=val; 09798 } 09799 09800 //! Operator>>=(). 09801 template<typename t> 09802 CImg<T>& operator>>=(const t val) { 09803 cimg_for(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)val); 09804 return *this; 09805 } 09806 09807 //! Operator>>=(). 09808 CImg<T>& operator>>=(const char *const expression) { 09809 const unsigned int omode = cimg::exception_mode(); 09810 cimg::exception_mode() = 0; 09811 try { 09812 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 09813 _cimg_math_parser mp(base,expression,"operator<<="); 09814 T *ptrd = _data; 09815 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp.eval(x,y,z,c)); ++ptrd; } 09816 } catch (CImgException&) { 09817 cimg::exception_mode() = omode; 09818 CImg<T> values(_width,_height,_depth,_spectrum); 09819 values = expression; 09820 *this>>=values; 09821 } 09822 cimg::exception_mode() = omode; 09823 return *this; 09824 } 09825 09826 //! Operator>>=(). 09827 template<typename t> 09828 CImg<T>& operator>>=(const CImg<t>& img) { 09829 const unsigned int siz = size(), isiz = img.size(); 09830 if (siz && isiz) { 09831 if (is_overlapped(img)) return *this^=+img; 09832 T *ptrd = _data, *const ptre = _data + siz; 09833 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 09834 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((long)*ptrd >> (int)*(ptrs++)); 09835 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((long)*ptrd >> (int)*(ptrs++)); 09836 } 09837 return *this; 09838 } 09839 09840 //! Operator>>(). 09841 template<typename t> 09842 CImg<T> operator>>(const t val) const { 09843 return (+*this)>>=val; 09844 } 09845 09846 //! Operator==(). 09847 template<typename t> 09848 bool operator==(const CImg<t>& img) const { 09849 const unsigned int siz = size(); 09850 bool vequal = true; 09851 if (siz!=img.size()) return false; 09852 t *ptrs = img._data + siz; 09853 for (T *ptrd = _data + siz; vequal && ptrd>_data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {} 09854 return vequal; 09855 } 09856 09857 //! Operator!=(). 09858 template<typename t> 09859 bool operator!=(const CImg<t>& img) const { 09860 return !((*this)==img); 09861 } 09862 09863 //! Operator,(). 09864 template<typename t> 09865 CImgList<_cimg_Tt> operator,(const CImg<t>& img) const { 09866 return CImgList<_cimg_Tt>(*this,img); 09867 } 09868 09869 //! Operator,(). 09870 template<typename t> 09871 CImgList<_cimg_Tt> operator,(CImgList<t>& list) const { 09872 return CImgList<_cimg_Tt>(list).insert(*this,0); 09873 } 09874 09875 //! Operator<(). 09876 CImgList<T> operator<(const char axis) const { 09877 return get_split(axis); 09878 } 09879 09880 //! Operator~(). 09881 CImg<T> operator~() const { 09882 CImg<T> res(_width,_height,_depth,_spectrum); 09883 const T *ptrs = end(); 09884 cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; } 09885 return res; 09886 } 09887 09888 //@} 09889 //------------------------------------- 09890 // 09891 //! \name Instance Characteristics 09892 //@{ 09893 //------------------------------------- 09894 09895 //! Return the type of the pixel values. 09896 /** 09897 \return a string describing the type of the image pixels (template parameter \p T). 09898 - The string returned may contains spaces (<tt>"unsigned char"</tt>). 09899 - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned. 09900 **/ 09901 static const char* pixel_type() { 09902 return cimg::type<T>::string(); 09903 } 09904 09905 //! Return the number of columns of the instance image (size along the X-axis, i.e image width). 09906 int width() const { 09907 return (int)_width; 09908 } 09909 09910 //! Return the number of rows of the instance image (size along the Y-axis, i.e image height). 09911 int height() const { 09912 return (int)_height; 09913 } 09914 09915 //! Return the number of slices of the instance image (size along the Z-axis). 09916 int depth() const { 09917 return (int)_depth; 09918 } 09919 09920 //! Return the number of vector channels of the instance image (size along the C-axis). 09921 int spectrum() const { 09922 return (int)_spectrum; 09923 } 09924 09925 //! Return the number of image buffer elements. 09926 /** 09927 - Equivalent to : width() * height() * depth() * spectrum(). 09928 09929 \par example: 09930 \code 09931 CImg<> img(100,100,1,3); 09932 if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true"); 09933 \endcode 09934 **/ 09935 unsigned int size() const { 09936 return _width*_height*_depth*_spectrum; 09937 } 09938 09939 //! Return a pointer to the pixel buffer. 09940 T* data() { 09941 return _data; 09942 } 09943 09944 const T* data() const { 09945 return _data; 09946 } 09947 09948 //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v). 09949 /** 09950 \param x X-coordinate of the pixel. 09951 \param y Y-coordinate of the pixel. 09952 \param z Z-coordinate of the pixel. 09953 \param v C-coordinate of the pixel. 09954 09955 - When called without parameters, data() returns a pointer to the begining of the pixel buffer. 09956 - If the macro \c 'cimg_verbosity'>=3, boundary checking is performed and warning messages may appear if 09957 given coordinates are outside the image range (but function performances decrease). 09958 09959 \par example: 09960 \code 09961 CImg<float> img(100,100,1,1,0); // Define a 100x100 greyscale image with float-valued pixels. 09962 float *ptr = data(10,10); // Get a pointer to the pixel located at (10,10). 09963 float val = *ptr; // Get the pixel value. 09964 \endcode 09965 **/ 09966 #if cimg_verbosity>=3 09967 T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { 09968 const unsigned int off = (unsigned int)offset(x,y,z,c); 09969 if (off>=size()) { 09970 cimg::warn(_cimg_instance 09971 "data() : Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].", 09972 cimg_instance, 09973 x,y,z,c,off); 09974 return _data; 09975 } 09976 return _data + off; 09977 } 09978 09979 const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { 09980 return const_cast<CImg<T>*>(this)->data(x,y,z,c); 09981 } 09982 #else 09983 T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { 09984 return _data + x + y*_width + z*_width*_height + c*_width*_height*_depth; 09985 } 09986 09987 const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { 09988 return _data + x + y*_width + z*_width*_height + c*_width*_height*_depth; 09989 } 09990 #endif 09991 09992 //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data. 09993 /** 09994 \param x X-coordinate of the pixel. 09995 \param y Y-coordinate of the pixel. 09996 \param z Z-coordinate of the pixel. 09997 \param v C-coordinate of the pixel. 09998 09999 - No checking is done on the validity of the given coordinates. 10000 10001 \par Example: 10002 \code 10003 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. 10004 long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10). 10005 float val = img[off]; // Get the blue value of the pixel. 10006 \endcode 10007 **/ 10008 int offset(const int x, const int y=0, const int z=0, const int c=0) const { 10009 return x + y*_width + z*_width*_height + c*_width*_height*_depth; 10010 } 10011 10012 //! Return an iterator to the first image pixel 10013 iterator begin() { 10014 return _data; 10015 } 10016 10017 const_iterator begin() const { 10018 return _data; 10019 } 10020 10021 //! Return an iterator pointing after the last image pixel (STL-compliant name). 10022 iterator end() { 10023 return _data + size(); 10024 } 10025 10026 const_iterator end() const { 10027 return _data + size(); 10028 } 10029 10030 //! Return reference to the first image pixel (STL-compliant name). 10031 const T& front() const { 10032 return *_data; 10033 } 10034 10035 T& front() { 10036 return *_data; 10037 } 10038 10039 //! Return a reference to the last image pixel (STL-compliant name). 10040 const T& back() const { 10041 return *(_data + size() - 1); 10042 } 10043 10044 T& back() { 10045 return *(_data + size() - 1); 10046 } 10047 10048 //! Read a pixel value with Dirichlet boundary conditions. 10049 T& at(const int off, const T out_val) { 10050 return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off]; 10051 } 10052 10053 T at(const int off, const T out_val) const { 10054 return (off<0 || off>=(int)size())?out_val:(*this)[off]; 10055 } 10056 10057 //! Read a pixel value with Neumann boundary conditions. 10058 T& at(const int off) { 10059 if (is_empty()) 10060 throw CImgInstanceException(_cimg_instance 10061 "at() : Empty instance.", 10062 cimg_instance); 10063 return _at(off); 10064 } 10065 10066 T at(const int off) const { 10067 if (is_empty()) 10068 throw CImgInstanceException(_cimg_instance 10069 "at() : Empty instance.", 10070 cimg_instance); 10071 return _at(off); 10072 } 10073 10074 T& _at(const int off) { 10075 const unsigned int siz = (unsigned int)size(); 10076 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off]; 10077 } 10078 10079 T _at(const int off) const { 10080 const unsigned int siz = (unsigned int)size(); 10081 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off]; 10082 } 10083 10084 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x). 10085 T& atX(const int x, const int y, const int z, const int c, const T out_val) { 10086 return (x<0 || x>=width())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,c); 10087 } 10088 10089 T atX(const int x, const int y, const int z, const int c, const T out_val) const { 10090 return (x<0 || x>=width())?out_val:(*this)(x,y,z,c); 10091 } 10092 10093 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x). 10094 T& atX(const int x, const int y=0, const int z=0, const int c=0) { 10095 if (is_empty()) 10096 throw CImgInstanceException(_cimg_instance 10097 "atX() : Empty instance.", 10098 cimg_instance); 10099 return _atX(x,y,z,c); 10100 } 10101 10102 T atX(const int x, const int y=0, const int z=0, const int c=0) const { 10103 if (is_empty()) 10104 throw CImgInstanceException(_cimg_instance 10105 "atX() : Empty instance.", 10106 cimg_instance); 10107 return _atX(x,y,z,c); 10108 } 10109 10110 T& _atX(const int x, const int y=0, const int z=0, const int c=0) { 10111 return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c); 10112 } 10113 10114 T _atX(const int x, const int y=0, const int z=0, const int c=0) const { 10115 return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c); 10116 } 10117 10118 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y). 10119 T& atXY(const int x, const int y, const int z, const int c, const T out_val) { 10120 return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,c); 10121 } 10122 10123 T atXY(const int x, const int y, const int z, const int c, const T out_val) const { 10124 return (x<0 || y<0 || x>=width() || y>=height())?out_val:(*this)(x,y,z,c); 10125 } 10126 10127 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y). 10128 T& atXY(const int x, const int y, const int z=0, const int c=0) { 10129 if (is_empty()) 10130 throw CImgInstanceException(_cimg_instance 10131 "atXY() : Empty instance.", 10132 cimg_instance); 10133 return _atXY(x,y,z,c); 10134 } 10135 10136 T atXY(const int x, const int y, const int z=0, const int c=0) const { 10137 if (is_empty()) 10138 throw CImgInstanceException(_cimg_instance 10139 "atXY() : Empty instance.", 10140 cimg_instance); 10141 return _atXY(x,y,z,c); 10142 } 10143 10144 T& _atXY(const int x, const int y, const int z=0, const int c=0) { 10145 return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c); 10146 } 10147 10148 T _atXY(const int x, const int y, const int z=0, const int c=0) const { 10149 return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c); 10150 } 10151 10152 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z). 10153 T& atXYZ(const int x, const int y, const int z, const int c, const T out_val) { 10154 return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())? 10155 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,c); 10156 } 10157 10158 T atXYZ(const int x, const int y, const int z, const int c, const T out_val) const { 10159 return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_val:(*this)(x,y,z,c); 10160 } 10161 10162 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z). 10163 T& atXYZ(const int x, const int y, const int z, const int c=0) { 10164 if (is_empty()) 10165 throw CImgInstanceException(_cimg_instance 10166 "atXYZ() : Empty instance.", 10167 cimg_instance); 10168 return _atXYZ(x,y,z,c); 10169 } 10170 10171 T atXYZ(const int x, const int y, const int z, const int c=0) const { 10172 if (is_empty()) 10173 throw CImgInstanceException(_cimg_instance 10174 "atXYZ() : Empty instance.", 10175 cimg_instance); 10176 return _atXYZ(x,y,z,c); 10177 } 10178 10179 T& _atXYZ(const int x, const int y, const int z, const int c=0) { 10180 return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y), 10181 z<0?0:(z>=depth()?depth()-1:z),c); 10182 } 10183 10184 T _atXYZ(const int x, const int y, const int z, const int c=0) const { 10185 return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y), 10186 z<0?0:(z>=depth()?depth()-1:z),c); 10187 } 10188 10189 //! Read a pixel value with Dirichlet boundary conditions. 10190 T& atXYZC(const int x, const int y, const int z, const int c, const T out_val) { 10191 return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())? 10192 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,c); 10193 } 10194 10195 T atXYZC(const int x, const int y, const int z, const int c, const T out_val) const { 10196 return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_val:(*this)(x,y,z,c); 10197 } 10198 10199 //! Read a pixel value with Neumann boundary conditions. 10200 T& atXYZC(const int x, const int y, const int z, const int c) { 10201 if (is_empty()) 10202 throw CImgInstanceException(_cimg_instance 10203 "atXYZC() : Empty instance.", 10204 cimg_instance); 10205 return _atXYZC(x,y,z,c); 10206 } 10207 10208 T atXYZC(const int x, const int y, const int z, const int c) const { 10209 if (is_empty()) 10210 throw CImgInstanceException(_cimg_instance 10211 "atXYZC() : Empty instance.", 10212 cimg_instance); 10213 return _atXYZC(x,y,z,c); 10214 } 10215 10216 T& _atXYZC(const int x, const int y, const int z, const int c) { 10217 return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y), 10218 z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c)); 10219 } 10220 10221 T _atXYZC(const int x, const int y, const int z, const int c) const { 10222 return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y), 10223 z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c)); 10224 } 10225 10226 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate). 10227 Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T out_val) const { 10228 const int 10229 x = (int)fx - (fx>=0?0:1), nx = x + 1; 10230 const float 10231 dx = fx - x; 10232 const Tfloat 10233 Ic = (Tfloat)atX(x,y,z,c,out_val), In = (Tfloat)atXY(nx,y,z,c,out_val); 10234 return Ic + dx*(In-Ic); 10235 } 10236 10237 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate). 10238 Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { 10239 if (is_empty()) 10240 throw CImgInstanceException(_cimg_instance 10241 "linear_atX() : Empty instance.", 10242 cimg_instance); 10243 10244 return _linear_atX(fx,y,z,c); 10245 } 10246 10247 Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { 10248 const float 10249 nfx = fx<0?0:(fx>_width-1?_width-1:fx); 10250 const unsigned int 10251 x = (unsigned int)nfx; 10252 const float 10253 dx = nfx - x; 10254 const unsigned int 10255 nx = dx>0?x+1:x; 10256 const Tfloat 10257 Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c); 10258 return Ic + dx*(In-Ic); 10259 } 10260 10261 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates). 10262 Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T out_val) const { 10263 const int 10264 x = (int)fx - (fx>=0?0:1), nx = x + 1, 10265 y = (int)fy - (fy>=0?0:1), ny = y + 1; 10266 const float 10267 dx = fx - x, 10268 dy = fy - y; 10269 const Tfloat 10270 Icc = (Tfloat)atXY(x,y,z,c,out_val), Inc = (Tfloat)atXY(nx,y,z,c,out_val), 10271 Icn = (Tfloat)atXY(x,ny,z,c,out_val), Inn = (Tfloat)atXY(nx,ny,z,c,out_val); 10272 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); 10273 } 10274 10275 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates). 10276 Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { 10277 if (is_empty()) 10278 throw CImgInstanceException(_cimg_instance 10279 "linear_atXY() : Empty instance.", 10280 cimg_instance); 10281 10282 return _linear_atXY(fx,fy,z,c); 10283 } 10284 10285 Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { 10286 const float 10287 nfx = fx<0?0:(fx>_width-1?_width-1:fx), 10288 nfy = fy<0?0:(fy>_height-1?_height-1:fy); 10289 const unsigned int 10290 x = (unsigned int)nfx, 10291 y = (unsigned int)nfy; 10292 const float 10293 dx = nfx - x, 10294 dy = nfy - y; 10295 const unsigned int 10296 nx = dx>0?x+1:x, 10297 ny = dy>0?y+1:y; 10298 const Tfloat 10299 Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), 10300 Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c); 10301 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); 10302 } 10303 10304 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates). 10305 Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_val) const { 10306 const int 10307 x = (int)fx - (fx>=0?0:1), nx = x + 1, 10308 y = (int)fy - (fy>=0?0:1), ny = y + 1, 10309 z = (int)fz - (fz>=0?0:1), nz = z + 1; 10310 const float 10311 dx = fx - x, 10312 dy = fy - y, 10313 dz = fz - z; 10314 const Tfloat 10315 Iccc = (Tfloat)atXYZ(x,y,z,c,out_val), Incc = (Tfloat)atXYZ(nx,y,z,c,out_val), 10316 Icnc = (Tfloat)atXYZ(x,ny,z,c,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_val), 10317 Iccn = (Tfloat)atXYZ(x,y,nz,c,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_val), 10318 Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_val); 10319 return Iccc + 10320 dx*(Incc-Iccc + 10321 dy*(Iccc+Innc-Icnc-Incc + 10322 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + 10323 dz*(Iccc+Incn-Iccn-Incc)) + 10324 dy*(Icnc-Iccc + 10325 dz*(Iccc+Icnn-Iccn-Icnc)) + 10326 dz*(Iccn-Iccc); 10327 } 10328 10329 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates). 10330 Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { 10331 if (is_empty()) 10332 throw CImgInstanceException(_cimg_instance 10333 "linear_atXYZ() : Empty instance.", 10334 cimg_instance); 10335 10336 return _linear_atXYZ(fx,fy,fz,c); 10337 } 10338 10339 Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { 10340 const float 10341 nfx = fx<0?0:(fx>_width-1?_width-1:fx), 10342 nfy = fy<0?0:(fy>_height-1?_height-1:fy), 10343 nfz = fz<0?0:(fz>_depth-1?_depth-1:fz); 10344 const unsigned int 10345 x = (unsigned int)nfx, 10346 y = (unsigned int)nfy, 10347 z = (unsigned int)nfz; 10348 const float 10349 dx = nfx - x, 10350 dy = nfy - y, 10351 dz = nfz - z; 10352 const unsigned int 10353 nx = dx>0?x+1:x, 10354 ny = dy>0?y+1:y, 10355 nz = dz>0?z+1:z; 10356 const Tfloat 10357 Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), 10358 Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), 10359 Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), 10360 Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c); 10361 return Iccc + 10362 dx*(Incc-Iccc + 10363 dy*(Iccc+Innc-Icnc-Incc + 10364 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + 10365 dz*(Iccc+Incn-Iccn-Incc)) + 10366 dy*(Icnc-Iccc + 10367 dz*(Iccc+Icnn-Iccn-Icnc)) + 10368 dz*(Iccn-Iccc); 10369 } 10370 10371 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions. 10372 Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T out_val) const { 10373 const int 10374 x = (int)fx - (fx>=0?0:1), nx = x + 1, 10375 y = (int)fy - (fy>=0?0:1), ny = y + 1, 10376 z = (int)fz - (fz>=0?0:1), nz = z + 1, 10377 c = (int)fc - (fc>=0?0:1), nc = c + 1; 10378 const float 10379 dx = fx - x, 10380 dy = fy - y, 10381 dz = fz - z, 10382 dc = fc - c; 10383 const Tfloat 10384 Icccc = (Tfloat)atXYZC(x,y,z,c,out_val), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_val), 10385 Icncc = (Tfloat)atXYZC(x,ny,z,c,out_val), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_val), 10386 Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_val), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_val), 10387 Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_val), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_val), 10388 Icccn = (Tfloat)atXYZC(x,y,z,nc,out_val), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_val), 10389 Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_val), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_val), 10390 Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_val), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_val), 10391 Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_val), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_val); 10392 return Icccc + 10393 dx*(Inccc-Icccc + 10394 dy*(Icccc+Inncc-Icncc-Inccc + 10395 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + 10396 dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + 10397 dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + 10398 dz*(Icccc+Incnc-Iccnc-Inccc + 10399 dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + 10400 dc*(Icccc+Inccn-Inccc-Icccn)) + 10401 dy*(Icncc-Icccc + 10402 dz*(Icccc+Icnnc-Iccnc-Icncc + 10403 dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + 10404 dc*(Icccc+Icncn-Icncc-Icccn)) + 10405 dz*(Iccnc-Icccc + 10406 dc*(Icccc+Iccnn-Iccnc-Icccn)) + 10407 dc*(Icccn-Icccc); 10408 } 10409 10410 //! Read a pixel value using linear interpolation and Neumann boundary conditions. 10411 Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { 10412 if (is_empty()) 10413 throw CImgInstanceException(_cimg_instance 10414 "linear_atXYZC() : Empty instance.", 10415 cimg_instance); 10416 10417 return _linear_atXYZC(fx,fy,fz,fc); 10418 } 10419 10420 Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { 10421 const float 10422 nfx = fx<0?0:(fx>_width-1?_width-1:fx), 10423 nfy = fy<0?0:(fy>_height-1?_height-1:fy), 10424 nfz = fz<0?0:(fz>_depth-1?_depth-1:fz), 10425 nfc = fc<0?0:(fc>_spectrum-1?_spectrum-1:fc); 10426 const unsigned int 10427 x = (unsigned int)nfx, 10428 y = (unsigned int)nfy, 10429 z = (unsigned int)nfz, 10430 c = (unsigned int)nfc; 10431 const float 10432 dx = nfx - x, 10433 dy = nfy - y, 10434 dz = nfz - z, 10435 dc = nfc - c; 10436 const unsigned int 10437 nx = dx>0?x+1:x, 10438 ny = dy>0?y+1:y, 10439 nz = dz>0?z+1:z, 10440 nc = dc>0?c+1:c; 10441 const Tfloat 10442 Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c), 10443 Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c), 10444 Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c), 10445 Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c), 10446 Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc), 10447 Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc), 10448 Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc), 10449 Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc); 10450 return Icccc + 10451 dx*(Inccc-Icccc + 10452 dy*(Icccc+Inncc-Icncc-Inccc + 10453 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + 10454 dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + 10455 dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + 10456 dz*(Icccc+Incnc-Iccnc-Inccc + 10457 dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + 10458 dc*(Icccc+Inccn-Inccc-Icccn)) + 10459 dy*(Icncc-Icccc + 10460 dz*(Icccc+Icnnc-Iccnc-Icncc + 10461 dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + 10462 dc*(Icccc+Icncn-Icncc-Icccn)) + 10463 dz*(Iccnc-Icccc + 10464 dc*(Icccc+Iccnn-Iccnc-Icccn)) + 10465 dc*(Icccn-Icccc); 10466 } 10467 10468 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates). 10469 Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_val) const { 10470 const int 10471 x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2; 10472 const float 10473 dx = fx - x; 10474 const Tfloat 10475 Ip = (Tfloat)atX(px,y,z,c,out_val), Ic = (Tfloat)atX(x,y,z,c,out_val), 10476 In = (Tfloat)atX(nx,y,z,c,out_val), Ia = (Tfloat)atX(ax,y,z,c,out_val); 10477 return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia)); 10478 } 10479 10480 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates). 10481 Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_val, 10482 const Tfloat min_val, const Tfloat max_val) const { 10483 const Tfloat val = cubic_atX(fx,y,z,c,out_val); 10484 return val<min_val?min_val:val>max_val?max_val:val; 10485 } 10486 10487 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates). 10488 Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { 10489 if (is_empty()) 10490 throw CImgInstanceException(_cimg_instance 10491 "cubic_atX() : Empty instance.", 10492 cimg_instance); 10493 return _cubic_atX(fx,y,z,c); 10494 } 10495 10496 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates). 10497 Tfloat cubic_atX(const float fx, const int y, const int z, const int c, 10498 const Tfloat min_val, const Tfloat max_val) const { 10499 const Tfloat val = cubic_atX(fx,y,z,c); 10500 return val<min_val?min_val:val>max_val?max_val:val; 10501 } 10502 10503 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates). 10504 Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { 10505 const float 10506 nfx = fx<0?0:(fx>_width-1?_width-1:fx); 10507 const int 10508 x = (int)nfx; 10509 const float 10510 dx = nfx - x; 10511 const int 10512 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2; 10513 const Tfloat 10514 Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c), 10515 In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c); 10516 return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia)); 10517 } 10518 10519 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates). 10520 Tfloat _cubic_atX(const float fx, const int y, const int z, const int c, 10521 const Tfloat min_val, const Tfloat max_val) const { 10522 const Tfloat val = _cubic_atX(fx,y,z,c); 10523 return val<min_val?min_val:val>max_val?max_val:val; 10524 } 10525 10526 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions. 10527 Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_val) const { 10528 const int 10529 x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, 10530 y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2; 10531 const float dx = fx - x, dy = fy - y; 10532 const Tfloat 10533 Ipp = (Tfloat)atXY(px,py,z,c,out_val), Icp = (Tfloat)atXY(x,py,z,c,out_val), Inp = (Tfloat)atXY(nx,py,z,c,out_val), Iap = (Tfloat)atXY(ax,py,z,c,out_val), 10534 Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)), 10535 Ipc = (Tfloat)atXY(px,y,z,c,out_val), Icc = (Tfloat)atXY(x, y,z,c,out_val), Inc = (Tfloat)atXY(nx,y,z,c,out_val), Iac = (Tfloat)atXY(ax,y,z,c,out_val), 10536 Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)), 10537 Ipn = (Tfloat)atXY(px,ny,z,c,out_val), Icn = (Tfloat)atXY(x,ny,z,c,out_val), Inn = (Tfloat)atXY(nx,ny,z,c,out_val), Ian = (Tfloat)atXY(ax,ny,z,c,out_val), 10538 In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)), 10539 Ipa = (Tfloat)atXY(px,ay,z,c,out_val), Ica = (Tfloat)atXY(x,ay,z,c,out_val), Ina = (Tfloat)atXY(nx,ay,z,c,out_val), Iaa = (Tfloat)atXY(ax,ay,z,c,out_val), 10540 Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa)); 10541 return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia)); 10542 } 10543 10544 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions. 10545 Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_val, 10546 const Tfloat min_val, const Tfloat max_val) const { 10547 const Tfloat val = cubic_atXY(fx,fy,z,c,out_val); 10548 return val<min_val?min_val:val>max_val?max_val:val; 10549 } 10550 10551 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10552 Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { 10553 if (is_empty()) 10554 throw CImgInstanceException(_cimg_instance 10555 "cubic_atXY() : Empty instance.", 10556 cimg_instance); 10557 10558 return _cubic_atXY(fx,fy,z,c); 10559 } 10560 10561 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10562 Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, 10563 const Tfloat min_val, const Tfloat max_val) const { 10564 const Tfloat val = cubic_atXY(fx,fy,z,c); 10565 return val<min_val?min_val:val>max_val?max_val:val; 10566 } 10567 10568 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10569 Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { 10570 const float 10571 nfx = fx<0?0:(fx>_width-1?_width-1:fx), 10572 nfy = fy<0?0:(fy>_height-1?_height-1:fy); 10573 const int x = (int)nfx, y = (int)nfy; 10574 const float dx = nfx - x, dy = nfy - y; 10575 const int 10576 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2, 10577 py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2; 10578 const Tfloat 10579 Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), Iap = (Tfloat)(*this)(ax,py,z,c), 10580 Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)), 10581 Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), Iac = (Tfloat)(*this)(ax,y,z,c), 10582 Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)), 10583 Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), Ian = (Tfloat)(*this)(ax,ny,z,c), 10584 In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)), 10585 Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), Iaa = (Tfloat)(*this)(ax,ay,z,c), 10586 Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa)); 10587 return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia)); 10588 } 10589 10590 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10591 Tfloat _cubic_atXY(const float fx, const float fy, const int z, const int c, 10592 const Tfloat min_val, const Tfloat max_val) const { 10593 const Tfloat val = _cubic_atXY(fx,fy,z,c); 10594 return val<min_val?min_val:val>max_val?max_val:val; 10595 } 10596 10597 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions. 10598 Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_val) const { 10599 const int 10600 x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, 10601 y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2, 10602 z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2; 10603 const float dx = fx - x, dy = fy - y, dz = fz - z; 10604 const Tfloat 10605 Ippp = (Tfloat)atXYZ(px,py,pz,c,out_val), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_val), 10606 Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_val), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_val), 10607 Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)), 10608 Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_val), Iccp = (Tfloat)atXYZ(x, y,pz,c,out_val), 10609 Incp = (Tfloat)atXYZ(nx,y,pz,c,out_val), Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_val), 10610 Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)), 10611 Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_val), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_val), 10612 Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_val), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_val), 10613 Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)), 10614 Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_val), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_val), 10615 Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_val), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_val), 10616 Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)), 10617 Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)), 10618 Ippc = (Tfloat)atXYZ(px,py,z,c,out_val), Icpc = (Tfloat)atXYZ(x,py,z,c,out_val), 10619 Inpc = (Tfloat)atXYZ(nx,py,z,c,out_val), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_val), 10620 Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)), 10621 Ipcc = (Tfloat)atXYZ(px,y,z,c,out_val), Iccc = (Tfloat)atXYZ(x, y,z,c,out_val), 10622 Incc = (Tfloat)atXYZ(nx,y,z,c,out_val), Iacc = (Tfloat)atXYZ(ax,y,z,c,out_val), 10623 Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)), 10624 Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_val), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_val), 10625 Innc = (Tfloat)atXYZ(nx,ny,z,c,out_val), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_val), 10626 Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)), 10627 Ipac = (Tfloat)atXYZ(px,ay,z,c,out_val), Icac = (Tfloat)atXYZ(x,ay,z,c,out_val), 10628 Inac = (Tfloat)atXYZ(nx,ay,z,c,out_val), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_val), 10629 Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)), 10630 Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)), 10631 Ippn = (Tfloat)atXYZ(px,py,nz,c,out_val), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_val), 10632 Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_val), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_val), 10633 Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)), 10634 Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_val), Iccn = (Tfloat)atXYZ(x, y,nz,c,out_val), 10635 Incn = (Tfloat)atXYZ(nx,y,nz,c,out_val), Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_val), 10636 Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)), 10637 Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_val), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_val), 10638 Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_val), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_val), 10639 Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)), 10640 Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_val), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_val), 10641 Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_val), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_val), 10642 Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)), 10643 In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)), 10644 Ippa = (Tfloat)atXYZ(px,py,az,c,out_val), Icpa = (Tfloat)atXYZ(x,py,az,c,out_val), 10645 Inpa = (Tfloat)atXYZ(nx,py,az,c,out_val), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_val), 10646 Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)), 10647 Ipca = (Tfloat)atXYZ(px,y,az,c,out_val), Icca = (Tfloat)atXYZ(x, y,az,c,out_val), 10648 Inca = (Tfloat)atXYZ(nx,y,az,c,out_val), Iaca = (Tfloat)atXYZ(ax,y,az,c,out_val), 10649 Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)), 10650 Ipna = (Tfloat)atXYZ(px,ny,az,c,out_val), Icna = (Tfloat)atXYZ(x,ny,az,c,out_val), 10651 Inna = (Tfloat)atXYZ(nx,ny,az,c,out_val), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_val), 10652 Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)), 10653 Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_val), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_val), 10654 Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_val), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_val), 10655 Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)), 10656 Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa)); 10657 return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia)); 10658 } 10659 10660 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions. 10661 Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_val, 10662 const Tfloat min_val, const Tfloat max_val) const { 10663 const Tfloat val = cubic_atXYZ(fx,fy,fz,c,out_val); 10664 return val<min_val?min_val:val>max_val?max_val:val; 10665 } 10666 10667 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10668 Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { 10669 if (is_empty()) 10670 throw CImgInstanceException(_cimg_instance 10671 "cubic_atXYZ() : Empty instance.", 10672 cimg_instance); 10673 10674 return _cubic_atXYZ(fx,fy,fz,c); 10675 } 10676 10677 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10678 Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, 10679 const Tfloat min_val, const Tfloat max_val) const { 10680 const Tfloat val = cubic_atXYZ(fx,fy,fz,c); 10681 return val<min_val?min_val:val>max_val?max_val:val; 10682 } 10683 10684 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10685 Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { 10686 const float 10687 nfx = fx<0?0:(fx>_width-1?_width-1:fx), 10688 nfy = fy<0?0:(fy>_height-1?_height-1:fy), 10689 nfz = fz<0?0:(fz>_depth-1?_depth-1:fz); 10690 const int x = (int)nfx, y = (int)nfy, z = (int)nfz; 10691 const float dx = nfx - x, dy = nfy - y, dz = nfz - z; 10692 const int 10693 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2, 10694 py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2, 10695 pz = z-1<0?0:z-1, nz = dz>0?z+1:z, az = z+2>=depth()?depth()-1:z+2; 10696 const Tfloat 10697 Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c), 10698 Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c), 10699 Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)), 10700 Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c), 10701 Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c), 10702 Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)), 10703 Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c), 10704 Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c), 10705 Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)), 10706 Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c), 10707 Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c), 10708 Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)), 10709 Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)), 10710 Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c), 10711 Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c), 10712 Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)), 10713 Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c), 10714 Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c), 10715 Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)), 10716 Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), 10717 Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c), 10718 Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)), 10719 Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c), 10720 Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c), 10721 Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)), 10722 Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)), 10723 Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c), 10724 Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c), 10725 Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)), 10726 Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c), 10727 Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c), 10728 Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)), 10729 Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), 10730 Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c), 10731 Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)), 10732 Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c), 10733 Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c), 10734 Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)), 10735 In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)), 10736 Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c), 10737 Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c), 10738 Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)), 10739 Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c), 10740 Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c), 10741 Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)), 10742 Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c), 10743 Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c), 10744 Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)), 10745 Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c), 10746 Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c), 10747 Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)), 10748 Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa)); 10749 return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia)); 10750 } 10751 10752 //! Read a pixel value using cubic interpolation and Neumann boundary conditions. 10753 Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c, 10754 const Tfloat min_val, const Tfloat max_val) const { 10755 const Tfloat val = _cubic_atXYZ(fx,fy,fz,c); 10756 return val<min_val?min_val:val>max_val?max_val:val; 10757 } 10758 10759 //! Set a pixel value, with 3d float coordinates, using linear interpolation. 10760 CImg<T>& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int c=0, 10761 const bool add=false) { 10762 const int 10763 x = (int)fx - (fx>=0?0:1), nx = x + 1, 10764 y = (int)fy - (fy>=0?0:1), ny = y + 1, 10765 z = (int)fz - (fz>=0?0:1), nz = z + 1; 10766 const float 10767 dx = fx - x, 10768 dy = fy - y, 10769 dz = fz - z; 10770 if (c>=0 && c<spectrum()) { 10771 if (z>=0 && z<depth()) { 10772 if (y>=0 && y<height()) { 10773 if (x>=0 && x<width()) { 10774 const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1); 10775 (*this)(x,y,z,c) = (T)(w1*val + w2*(*this)(x,y,z,c)); 10776 } 10777 if (nx>=0 && nx<width()) { 10778 const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1); 10779 (*this)(nx,y,z,c) = (T)(w1*val + w2*(*this)(nx,y,z,c)); 10780 } 10781 } 10782 if (ny>=0 && ny<height()) { 10783 if (x>=0 && x<width()) { 10784 const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1); 10785 (*this)(x,ny,z,c) = (T)(w1*val + w2*(*this)(x,ny,z,c)); 10786 } 10787 if (nx>=0 && nx<width()) { 10788 const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1); 10789 (*this)(nx,ny,z,c) = (T)(w1*val + w2*(*this)(nx,ny,z,c)); 10790 } 10791 } 10792 } 10793 if (nz>=0 && nz<depth()) { 10794 if (y>=0 && y<height()) { 10795 if (x>=0 && x<width()) { 10796 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1); 10797 (*this)(x,y,nz,c) = (T)(w1*val + w2*(*this)(x,y,nz,c)); 10798 } 10799 if (nx>=0 && nx<width()) { 10800 const float w1 = dx*(1-dy), w2 = add?1:(1-w1); 10801 (*this)(nx,y,nz,c) = (T)(w1*val + w2*(*this)(nx,y,nz,c)); 10802 } 10803 } 10804 if (ny>=0 && ny<height()) { 10805 if (x>=0 && x<width()) { 10806 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1); 10807 (*this)(x,ny,nz,c) = (T)(w1*val + w2*(*this)(x,ny,nz,c)); 10808 } 10809 if (nx>=0 && nx<width()) { 10810 const float w1 = dx*dy, w2 = add?1:(1-w1); 10811 (*this)(nx,ny,nz,c) = (T)(w1*val + w2*(*this)(nx,ny,nz,c)); 10812 } 10813 } 10814 } 10815 } 10816 return *this; 10817 } 10818 10819 //! Set a pixel value, with 2d float coordinates, using linear interpolation. 10820 CImg<T>& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int c=0, 10821 const bool add=false) { 10822 const int 10823 x = (int)fx - (fx>=0?0:1), nx = x + 1, 10824 y = (int)fy - (fy>=0?0:1), ny = y + 1; 10825 const float 10826 dx = fx - x, 10827 dy = fy - y; 10828 if (z>=0 && z<depth() && c>=0 && c<spectrum()) { 10829 if (y>=0 && y<height()) { 10830 if (x>=0 && x<width()) { 10831 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1); 10832 (*this)(x,y,z,c) = (T)(w1*val + w2*(*this)(x,y,z,c)); 10833 } 10834 if (nx>=0 && nx<width()) { 10835 const float w1 = dx*(1-dy), w2 = add?1:(1-w1); 10836 (*this)(nx,y,z,c) = (T)(w1*val + w2*(*this)(nx,y,z,c)); 10837 } 10838 } 10839 if (ny>=0 && ny<height()) { 10840 if (x>=0 && x<width()) { 10841 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1); 10842 (*this)(x,ny,z,c) = (T)(w1*val + w2*(*this)(x,ny,z,c)); 10843 } 10844 if (nx>=0 && nx<width()) { 10845 const float w1 = dx*dy, w2 = add?1:(1-w1); 10846 (*this)(nx,ny,z,c) = (T)(w1*val + w2*(*this)(nx,ny,z,c)); 10847 } 10848 } 10849 } 10850 return *this; 10851 } 10852 10853 //! Return a C-string containing the values of the instance image. 10854 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const { 10855 if (is_empty()) return CImg<charT>(1,1,1,1,0); 10856 const unsigned int siz = (unsigned int)size(); 10857 CImgList<charT> items; 10858 char item[256] = { 0 }; 10859 const T *ptrs = _data; 10860 for (unsigned int off = 0; off<siz-1; ++off) { 10861 std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++))); 10862 const unsigned int l = std::strlen(item); 10863 CImg<charT>(item,l+1).move_to(items).back()[l] = separator; 10864 } 10865 std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs)); 10866 CImg<charT>(item,std::strlen(item)+1).move_to(items); 10867 CImg<ucharT> res; (items>'x').move_to(res); 10868 if (max_size) { res.crop(0,max_size); res(max_size) = 0; } 10869 return res; 10870 } 10871 10872 //@} 10873 //------------------------------------- 10874 // 10875 //! \name Instance Checking 10876 //@{ 10877 //------------------------------------- 10878 10879 //! Return \c true if current image has shared memory. 10880 bool is_shared() const { 10881 return _is_shared; 10882 } 10883 10884 //! Return \c true if current image is empty. 10885 bool is_empty() const { 10886 return !(_data && _width && _height && _depth && _spectrum); 10887 } 10888 10889 //! Return \c true if image (*this) has the specified width. 10890 bool is_sameX(const unsigned int dx) const { 10891 return (_width==dx); 10892 } 10893 10894 //! Return \c true if images \c (*this) and \c img have same width. 10895 template<typename t> 10896 bool is_sameX(const CImg<t>& img) const { 10897 return is_sameX(img._width); 10898 } 10899 10900 //! Return \c true if images \c (*this) and the display \c disp have same width. 10901 bool is_sameX(const CImgDisplay& disp) const { 10902 return is_sameX((unsigned int)disp.width()); 10903 } 10904 10905 //! Return \c true if image (*this) has the specified height. 10906 bool is_sameY(const unsigned int dy) const { 10907 return (_height==dy); 10908 } 10909 10910 //! Return \c true if images \c (*this) and \c img have same height. 10911 template<typename t> 10912 bool is_sameY(const CImg<t>& img) const { 10913 return is_sameY(img._height); 10914 } 10915 10916 //! Return \c true if images \c (*this) and the display \c disp have same height. 10917 bool is_sameY(const CImgDisplay& disp) const { 10918 return is_sameY((unsigned int)disp.height()); 10919 } 10920 10921 //! Return \c true if image (*this) has the specified depth. 10922 bool is_sameZ(const unsigned int dz) const { 10923 return (_depth==dz); 10924 } 10925 10926 //! Return \c true if images \c (*this) and \c img have same depth. 10927 template<typename t> 10928 bool is_sameZ(const CImg<t>& img) const { 10929 return is_sameZ(img._depth); 10930 } 10931 10932 //! Return \c true if image (*this) has the specified number of channels. 10933 bool is_sameC(const unsigned int dc) const { 10934 return (_spectrum==dc); 10935 } 10936 10937 //! Return \c true if images \c (*this) and \c img have same _spectrum. 10938 template<typename t> 10939 bool is_sameC(const CImg<t>& img) const { 10940 return is_sameC(img._spectrum); 10941 } 10942 10943 //! Return \c true if image (*this) has the specified width and height. 10944 bool is_sameXY(const unsigned int dx, const unsigned int dy) const { 10945 return (is_sameX(dx) && is_sameY(dy)); 10946 } 10947 10948 //! Return \c true if images have same width and same height. 10949 template<typename t> 10950 bool is_sameXY(const CImg<t>& img) const { 10951 return (is_sameX(img) && is_sameY(img)); 10952 } 10953 10954 //! Return \c true if image \c (*this) and the display \c disp have same width and same height. 10955 bool is_sameXY(const CImgDisplay& disp) const { 10956 return (is_sameX(disp) && is_sameY(disp)); 10957 } 10958 10959 //! Return \c true if image (*this) has the specified width and depth. 10960 bool is_sameXZ(const unsigned int dx, const unsigned int dz) const { 10961 return (is_sameX(dx) && is_sameZ(dz)); 10962 } 10963 10964 //! Return \c true if images have same width and same depth. 10965 template<typename t> 10966 bool is_sameXZ(const CImg<t>& img) const { 10967 return (is_sameX(img) && is_sameZ(img)); 10968 } 10969 10970 //! Return \c true if image (*this) has the specified width and number of channels. 10971 bool is_sameXC(const unsigned int dx, const unsigned int dc) const { 10972 return (is_sameX(dx) && is_sameC(dc)); 10973 } 10974 10975 //! Return \c true if images have same width and same number of channels. 10976 template<typename t> 10977 bool is_sameXC(const CImg<t>& img) const { 10978 return (is_sameX(img) && is_sameC(img)); 10979 } 10980 10981 //! Return \c true if image (*this) has the specified height and depth. 10982 bool is_sameYZ(const unsigned int dy, const unsigned int dz) const { 10983 return (is_sameY(dy) && is_sameZ(dz)); 10984 } 10985 10986 //! Return \c true if images have same height and same depth. 10987 template<typename t> 10988 bool is_sameYZ(const CImg<t>& img) const { 10989 return (is_sameY(img) && is_sameZ(img)); 10990 } 10991 10992 //! Return \c true if image (*this) has the specified height and number of channels. 10993 bool is_sameYC(const unsigned int dy, const unsigned int dc) const { 10994 return (is_sameY(dy) && is_sameC(dc)); 10995 } 10996 10997 //! Return \c true if images have same height and same number of channels. 10998 template<typename t> 10999 bool is_sameYC(const CImg<t>& img) const { 11000 return (is_sameY(img) && is_sameC(img)); 11001 } 11002 11003 //! Return \c true if image (*this) has the specified depth and number of channels. 11004 bool is_sameZC(const unsigned int dz, const unsigned int dc) const { 11005 return (is_sameZ(dz) && is_sameC(dc)); 11006 } 11007 11008 //! Return \c true if images have same depth and same number of channels. 11009 template<typename t> 11010 bool is_sameZC(const CImg<t>& img) const { 11011 return (is_sameZ(img) && is_sameC(img)); 11012 } 11013 11014 //! Return \c true if image (*this) has the specified width, height and depth. 11015 bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const { 11016 return (is_sameXY(dx,dy) && is_sameZ(dz)); 11017 } 11018 11019 //! Return \c true if images have same width, same height and same depth. 11020 template<typename t> 11021 bool is_sameXYZ(const CImg<t>& img) const { 11022 return (is_sameXY(img) && is_sameZ(img)); 11023 } 11024 11025 //! Return \c true if image (*this) has the specified width, height and depth. 11026 bool is_sameXYC(const unsigned int dx, const unsigned int dy, const unsigned int dc) const { 11027 return (is_sameXY(dx,dy) && is_sameC(dc)); 11028 } 11029 11030 //! Return \c true if images have same width, same height and same number of channels. 11031 template<typename t> 11032 bool is_sameXYC(const CImg<t>& img) const { 11033 return (is_sameXY(img) && is_sameC(img)); 11034 } 11035 11036 //! Return \c true if image (*this) has the specified width, height and number of channels. 11037 bool is_sameXZC(const unsigned int dx, const unsigned int dz, const unsigned int dc) const { 11038 return (is_sameXZ(dx,dz) && is_sameC(dc)); 11039 } 11040 11041 //! Return \c true if images have same width, same depth and same number of channels. 11042 template<typename t> 11043 bool is_sameXZC(const CImg<t>& img) const { 11044 return (is_sameXZ(img) && is_sameC(img)); 11045 } 11046 11047 //! Return \c true if image (*this) has the specified height, depth and number of channels. 11048 bool is_sameYZC(const unsigned int dy, const unsigned int dz, const unsigned int dc) const { 11049 return (is_sameYZ(dy,dz) && is_sameC(dc)); 11050 } 11051 11052 //! Return \c true if images have same heigth, same depth and same number of channels. 11053 template<typename t> 11054 bool is_sameYZC(const CImg<t>& img) const { 11055 return (is_sameYZ(img) && is_sameC(img)); 11056 } 11057 11058 //! Return \c true if image (*this) has the specified width, height, depth and number of channels. 11059 bool is_sameXYZC(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) const { 11060 return (is_sameXYZ(dx,dy,dz) && is_sameC(dc)); 11061 } 11062 11063 //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels. 11064 template<typename t> 11065 bool is_sameXYZC(const CImg<t>& img) const { 11066 return (is_sameXYZ(img) && is_sameC(img)); 11067 } 11068 11069 //! Return \c true if pixel (x,y,z,c) is inside image boundaries. 11070 bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const { 11071 return !is_empty() && x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum(); 11072 } 11073 11074 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,c). 11075 template<typename t> 11076 bool contains(const T& pixel, t& x, t& y, t& z, t& c) const { 11077 const unsigned int wh = _width*_height, whd = wh*_depth, siz = whd*_spectrum; 11078 const T *const ppixel = &pixel; 11079 if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false; 11080 unsigned int off = (unsigned int)(ppixel - _data); 11081 const unsigned int nc = off/whd; 11082 off%=whd; 11083 const unsigned int nz = off/wh; 11084 off%=wh; 11085 const unsigned int ny = off/_width, nx = off%_width; 11086 x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc; 11087 return true; 11088 } 11089 11090 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z). 11091 template<typename t> 11092 bool contains(const T& pixel, t& x, t& y, t& z) const { 11093 const unsigned int wh = _width*_height, whd = wh*_depth, siz = whd*_spectrum; 11094 const T *const ppixel = &pixel; 11095 if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false; 11096 unsigned int off = ((unsigned int)(ppixel - _data))%whd; 11097 const unsigned int nz = off/wh; 11098 off%=wh; 11099 const unsigned int ny = off/_width, nx = off%_width; 11100 x = (t)nx; y = (t)ny; z = (t)nz; 11101 return true; 11102 } 11103 11104 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y). 11105 template<typename t> 11106 bool contains(const T& pixel, t& x, t& y) const { 11107 const unsigned int wh = _width*_height, siz = wh*_depth*_spectrum; 11108 const T *const ppixel = &pixel; 11109 if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false; 11110 unsigned int off = ((unsigned int)(ppixel - _data))%wh; 11111 const unsigned int ny = off/_width, nx = off%_width; 11112 x = (t)nx; y = (t)ny; 11113 return true; 11114 } 11115 11116 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x). 11117 template<typename t> 11118 bool contains(const T& pixel, t& x) const { 11119 const T *const ppixel = &pixel; 11120 if (is_empty() || ppixel<_data || ppixel>=_data+size()) return false; 11121 x = (t)(((unsigned int)(ppixel - _data))%_width); 11122 return true; 11123 } 11124 11125 //! Return \c true if specified referenced value is inside the image boundaries. 11126 bool contains(const T& pixel) const { 11127 const T *const ppixel = &pixel; 11128 return !is_empty() && ppixel>=_data && ppixel<_data + size(); 11129 } 11130 11131 //! Return \c true if the memory buffers of the two images overlaps. 11132 template<typename t> 11133 bool is_overlapped(const CImg<t>& img) const { 11134 const unsigned int csiz = size(), isiz = img.size(); 11135 return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz)); 11136 } 11137 11138 //! Return true if the set (instance,primitives,colors,opacities) stands for a valid 3d object. 11139 template<typename tp, typename tc, typename to> 11140 bool is_object3d(const CImgList<tp>& primitives, 11141 const CImgList<tc>& colors, 11142 const to& opacities, 11143 const bool full_check=true, 11144 char *const error_message=0) const { 11145 if (error_message) *error_message = 0; 11146 11147 // Check consistency for the particular case of an empty 3d object. 11148 if (is_empty()) { 11149 if (primitives || colors || opacities) { 11150 if (error_message) std::sprintf(error_message, 11151 "3d object has no vertices but %u primitives, %u colors and %u opacities", 11152 primitives._width,colors._width,opacities.size()); 11153 return false; 11154 } 11155 return true; 11156 } 11157 11158 // Check consistency of vertices. 11159 if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions. 11160 if (error_message) std::sprintf(error_message, 11161 "3d object (%u,%u) has invalid vertices dimensions (%u,%u,%u,%u)", 11162 _width,primitives._width,_width,_height,_depth,_spectrum); 11163 return false; 11164 } 11165 if (colors._width>primitives._width+1) { 11166 if (error_message) std::sprintf(error_message, 11167 "3d object (%u,%u) defines %u colors", 11168 _width,primitives._width,colors._width); 11169 return false; 11170 } 11171 if (opacities.size()>primitives._width) { 11172 if (error_message) std::sprintf(error_message, 11173 "3d object (%u,%u) defines %u opacities", 11174 _width,primitives._width,opacities.size()); 11175 return false; 11176 } 11177 if (!full_check) return true; 11178 11179 // Check consistency of primitives. 11180 cimglist_for(primitives,l) { 11181 const CImg<tp>& primitive = primitives[l]; 11182 const unsigned int psiz = primitive.size(); 11183 switch (psiz) { 11184 case 1 : { // Point. 11185 const unsigned int i0 = (unsigned int)primitive[0]; 11186 if (i0>=_width) { 11187 if (error_message) std::sprintf(error_message, 11188 "3d object (%u,%u) refers to invalid vertex indice %u in point primitive %u", 11189 _width,primitives._width,i0,l); 11190 return false; 11191 } 11192 } break; 11193 case 5 : { // Sphere. 11194 const unsigned int 11195 i0 = (unsigned int)primitive(0), 11196 i1 = (unsigned int)primitive(1); 11197 if (i0>=_width || i1>=_width) { 11198 if (error_message) std::sprintf(error_message, 11199 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in sphere primitive %u", 11200 _width,primitives._width,i0,i1,l); 11201 return false; 11202 } 11203 } break; 11204 case 2 : // Segment. 11205 case 6 : { 11206 const unsigned int 11207 i0 = (unsigned int)primitive(0), 11208 i1 = (unsigned int)primitive(1); 11209 if (i0>=_width || i1>=_width) { 11210 if (error_message) std::sprintf(error_message, 11211 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in segment primitive %u", 11212 _width,primitives._width,i0,i1,l); 11213 return false; 11214 } 11215 } break; 11216 case 3 : // Triangle. 11217 case 9 : { 11218 const unsigned int 11219 i0 = (unsigned int)primitive(0), 11220 i1 = (unsigned int)primitive(1), 11221 i2 = (unsigned int)primitive(2); 11222 if (i0>=_width || i1>=_width || i2>=_width) { 11223 if (error_message) std::sprintf(error_message, 11224 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in triangle primitive %u", 11225 _width,primitives._width,i0,i1,i2,l); 11226 return false; 11227 } 11228 } break; 11229 case 4 : // Quadrangle. 11230 case 12 : { 11231 const unsigned int 11232 i0 = (unsigned int)primitive(0), 11233 i1 = (unsigned int)primitive(1), 11234 i2 = (unsigned int)primitive(2), 11235 i3 = (unsigned int)primitive(3); 11236 if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) { 11237 if (error_message) std::sprintf(error_message, 11238 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in quadrangle primitive %u", 11239 _width,primitives._width,i0,i1,i2,i3,l); 11240 return false; 11241 } 11242 } break; 11243 default : 11244 if (error_message) std::sprintf(error_message, 11245 "3d object has invalid primitive %u of size %u", 11246 l,psiz); 11247 return false; 11248 } 11249 } 11250 11251 // Check consistency of colors. 11252 cimglist_for(colors,c) { 11253 const CImg<tc>& color = colors[c]; 11254 if (!color) { 11255 if (error_message) std::sprintf(error_message, 11256 "3d object has empty color for primitive %u", 11257 c); 11258 return false; 11259 } 11260 } 11261 11262 // Check consistency of light texture. 11263 if (colors._width>primitives._width) { 11264 const CImg<tc> &light = colors.back(); 11265 if (!light || light._depth>1) { 11266 if (error_message) std::sprintf(error_message, 11267 "3d object has invalid light texture (%u,%u,%u,%u)", 11268 light._width,light._height,light._depth,light._spectrum); 11269 return false; 11270 } 11271 } 11272 11273 // Check consistency of opacities. 11274 return _is_object3d(opacities,error_message); 11275 } 11276 11277 template<typename to> 11278 bool _is_object3d(const CImgList<to>& opacities, char *const error_message) const { 11279 cimglist_for(opacities,o) { 11280 const CImg<to>& opacity = opacities[o]; 11281 if (opacity._spectrum!=1) { 11282 if (error_message) std::sprintf(error_message, 11283 "3d object has invalid opacity (%u,%u,%u,%u) for primitive %u", 11284 opacity._width,opacity._height,opacity._depth,opacity._spectrum,o); 11285 return false; 11286 } 11287 } 11288 return true; 11289 } 11290 11291 template<typename to> 11292 bool _is_object3d(const CImg<to>&, char *const) const { 11293 return true; 11294 } 11295 11296 //! Test if an image is a valid CImg3d object. 11297 bool is_CImg3d(const bool full_check=true, char *const error_message=0) const { 11298 if (error_message) *error_message = 0; 11299 11300 // Check instance dimension and header. 11301 if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) { 11302 if (error_message) std::sprintf(error_message, 11303 "CImg3d has invalid dimensions (%u,%u,%u,%u)", 11304 _width,_height,_depth,_spectrum); 11305 return false; 11306 } 11307 const T *ptrs = _data, *const ptre = end(); 11308 if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') || 11309 !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) { 11310 if (error_message) std::sprintf(error_message, 11311 "CImg3d header not found"); 11312 return false; 11313 } 11314 const unsigned int nb_points = (unsigned int)*(ptrs++), nb_primitives = (unsigned int)*(ptrs++); 11315 11316 // Check consistency of vertex data. 11317 if (!nb_points) { 11318 if (nb_primitives) { 11319 if (error_message) std::sprintf(error_message, 11320 "CImg3d has no vertices but %u primitives", 11321 nb_primitives); 11322 return false; 11323 } 11324 if (ptrs!=ptre) { 11325 if (error_message) std::sprintf(error_message, 11326 "CImg3d (%u,%u) is empty but contains %u byte%s more than expected", 11327 nb_points,nb_primitives,(unsigned int)(ptre-ptrs),(ptre-ptrs)>1?"s":""); 11328 return false; 11329 } 11330 return true; 11331 } 11332 ptrs+=3*nb_points; 11333 if (ptrs>ptre) { 11334 if (error_message) std::sprintf(error_message, 11335 "CImg3d (%u,%u) has incomplete vertex data", 11336 nb_points,nb_primitives); 11337 return false; 11338 } 11339 if (!full_check) return true; 11340 11341 // Check primitive consistency. 11342 if (ptrs==ptre) { 11343 if (error_message) std::sprintf(error_message, 11344 "CImg3d (%u,%u) has no primitive data", 11345 nb_points,nb_primitives); 11346 return false; 11347 } 11348 for (unsigned int p = 0; p<nb_primitives; ++p) { 11349 const unsigned int nb_inds = (unsigned int)*(ptrs++); 11350 switch (nb_inds) { 11351 case 1 : { // Point. 11352 const unsigned int ind0 = (unsigned int)*(ptrs++); 11353 if (ind0>=nb_points) { 11354 if (error_message) std::sprintf(error_message, 11355 "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive %u", 11356 nb_points,nb_primitives,ind0,p); 11357 return false; 11358 } 11359 } break; 11360 case 5 : { // Sphere. 11361 const unsigned int 11362 i0 = (unsigned int)*(ptrs++), 11363 i1 = (unsigned int)*(ptrs++); 11364 ptrs+=3; 11365 if (i0>=nb_points || i1>=nb_points) { 11366 if (error_message) std::sprintf(error_message, 11367 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in sphere primitive %u", 11368 nb_points,nb_primitives,i0,i1,p); 11369 return false; 11370 } 11371 } break; 11372 case 2 : case 6 : { // Segment. 11373 const unsigned int 11374 i0 = (unsigned int)*(ptrs++), 11375 i1 = (unsigned int)*(ptrs++); 11376 if (nb_inds==6) ptrs+=4; 11377 if (i0>=nb_points || i1>=nb_points) { 11378 if (error_message) std::sprintf(error_message, 11379 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in segment primitive %u", 11380 nb_points,nb_primitives,i0,i1,p); 11381 return false; 11382 } 11383 } break; 11384 case 3 : case 9 : { // Triangle. 11385 const unsigned int 11386 i0 = (unsigned int)*(ptrs++), 11387 i1 = (unsigned int)*(ptrs++), 11388 i2 = (unsigned int)*(ptrs++); 11389 if (nb_inds==9) ptrs+=6; 11390 if (i0>=nb_points || i1>=nb_points || i2>=nb_points) { 11391 if (error_message) std::sprintf(error_message, 11392 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in triangle primitive %u", 11393 nb_points,nb_primitives,i0,i1,i2,p); 11394 return false; 11395 } 11396 } break; 11397 case 4 : case 12 : { // Quadrangle. 11398 const unsigned int 11399 i0 = (unsigned int)*(ptrs++), 11400 i1 = (unsigned int)*(ptrs++), 11401 i2 = (unsigned int)*(ptrs++), 11402 i3 = (unsigned int)*(ptrs++); 11403 if (nb_inds==12) ptrs+=8; 11404 if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) { 11405 if (error_message) std::sprintf(error_message, 11406 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in quadrangle primitive %u", 11407 nb_points,nb_primitives,i0,i1,i2,i3,p); 11408 return false; 11409 } 11410 } break; 11411 default : 11412 if (error_message) std::sprintf(error_message, 11413 "CImg3d (%u,%u) has invalid primitive %u of size %u", 11414 nb_points,nb_primitives,p,nb_inds); 11415 return false; 11416 } 11417 if (ptrs>ptre) { 11418 if (error_message) std::sprintf(error_message, 11419 "CImg3d (%u,%u) has incomplete primitive data for primitive %u", 11420 nb_points,nb_primitives,p); 11421 return false; 11422 } 11423 } 11424 11425 // Check color consistency. 11426 if (ptrs==ptre) { 11427 if (error_message) std::sprintf(error_message, 11428 "CImg3d (%u,%u) has no color/texture data", 11429 nb_points,nb_primitives); 11430 return false; 11431 } 11432 for (unsigned int c = 0; c<nb_primitives; ++c) { 11433 if ((int)*(ptrs++)!=-128) ptrs+=2; 11434 else if ((ptrs+=3)<ptre) { 11435 const unsigned int w = (unsigned int)*(ptrs-3), h = (unsigned int)*(ptrs-2), s = (unsigned int)*(ptrs-1); 11436 if (!h && !s) { 11437 if (w>=c) { 11438 if (error_message) std::sprintf(error_message, 11439 "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u for primitive %u", 11440 nb_points,nb_primitives,w,c); 11441 return false; 11442 } 11443 } else ptrs+=w*h*s; 11444 } 11445 if (ptrs>ptre) { 11446 if (error_message) std::sprintf(error_message, 11447 "CImg3d (%u,%u) has incomplete color/texture data for primitive %u", 11448 nb_points,nb_primitives,c); 11449 return false; 11450 } 11451 } 11452 11453 // Check opacity consistency. 11454 if (ptrs==ptre) { 11455 if (error_message) std::sprintf(error_message, 11456 "CImg3d (%u,%u) has no opacity data", 11457 nb_points,nb_primitives); 11458 return false; 11459 } 11460 for (unsigned int o = 0; o<nb_primitives; ++o) { 11461 if ((int)*(ptrs++)==-128 && (ptrs+=3)<ptre) { 11462 const unsigned int w = (unsigned int)*(ptrs-3), h = (unsigned int)*(ptrs-2), s = (unsigned int)*(ptrs-1); 11463 if (!h && !s) { 11464 if (w>=o) { 11465 if (error_message) std::sprintf(error_message, 11466 "CImg3d (%u,%u) refers to invalid shared opacity indice %u for primitive %u", 11467 nb_points,nb_primitives,w,o); 11468 return false; 11469 } 11470 } else ptrs+=w*h*s; 11471 } 11472 if (ptrs>ptre) { 11473 if (error_message) std::sprintf(error_message, 11474 "CImg3d (%u,%u) has incomplete opacity data for primitive %u", 11475 nb_points,nb_primitives,o); 11476 return false; 11477 } 11478 } 11479 11480 // Check end of data. 11481 if (ptrs<ptre) { 11482 if (error_message) std::sprintf(error_message, 11483 "CImg3d (%u,%u) contains %u byte%s more than expected", 11484 nb_points,nb_primitives,(unsigned int)(ptre-ptrs),(ptre-ptrs)>1?"s":""); 11485 return false; 11486 } 11487 return true; 11488 } 11489 11490 static bool _is_CImg3d(const T val, const char c) { 11491 if (val>=(T)c && val<(T)(c+1)) return true; 11492 return false; 11493 } 11494 11495 //@} 11496 //------------------------------------- 11497 // 11498 //! \name Mathematical Functions 11499 //@{ 11500 //------------------------------------- 11501 11502 // Define the math formula parser/compiler and evaluator. 11503 struct _cimg_math_parser { 11504 CImgList<charT> label; 11505 CImgList<uintT> code; 11506 CImg<uintT> level, opcode; 11507 CImg<doubleT> mem; 11508 CImg<charT> expr; 11509 const CImg<T>& reference; 11510 CImg<Tdouble> reference_stats; 11511 unsigned int mempos, result; 11512 const char *const calling_function; 11513 #define _cimg_mp_return(x) { *se = saved_char; return x; } 11514 #define _cimg_mp_opcode0(op) _cimg_mp_return(opcode0(op)); 11515 #define _cimg_mp_opcode1(op,i1) _cimg_mp_return(opcode1(op,i1)); 11516 #define _cimg_mp_opcode2(op,i1,i2) { const unsigned int _i1 = i1, _i2 = i2; _cimg_mp_return(opcode2(op,_i1,_i2)); } 11517 #define _cimg_mp_opcode3(op,i1,i2,i3) { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3; _cimg_mp_return(opcode3(op,_i1,_i2,_i3)); } 11518 #define _cimg_mp_opcode5(op,i1,i2,i3,i4,i5) { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, _i5 = i5; \ 11519 _cimg_mp_return(opcode5(op,_i1,_i2,_i3,_i4,_i5)); } 11520 11521 // Constructor - Destructor. 11522 _cimg_math_parser(const CImg<T>& img, const char *const expression, const char *const funcname=0): 11523 reference(img),calling_function(funcname?funcname:"cimg_math_parser") { 11524 unsigned int l = 0; 11525 if (expression) { 11526 l = std::strlen(expression); 11527 expr.assign(expression,l+1); 11528 if (*expr._data) { 11529 char *d = expr._data; 11530 for (const char *s = expr._data; *s || (bool)(*d=0); ++s) if (*s!=' ') *(d++) = *s; 11531 l = d - expr._data; 11532 } 11533 } 11534 if (!l) throw CImgArgumentException("[_cimg_math_parser] " 11535 "CImg<%s>::%s() : Empty specified expression.", 11536 pixel_type(),calling_function); 11537 11538 int lv = 0; // Count parenthesis level of expression. 11539 level.assign(l); 11540 unsigned int *pd = level._data; 11541 for (const char *ps = expr._data; *ps && lv>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('?lv++:*ps==')'?--lv:lv); 11542 if (lv!=0) { 11543 throw CImgArgumentException("[_cimg_math_parser] " 11544 "CImg<%s>::%s() : Unbalanced parentheses in specified expression '%s'.", 11545 pixel_type(),calling_function, 11546 expr._data); 11547 } 11548 mem.assign(512); label.assign(512); // Init constant values. 11549 mem[0] = 0; mem[1] = 1; 11550 mem[2] = (double)reference._width; mem[3] = (double)reference._height; mem[4] = (double)reference._depth; mem[5] = (double)reference._spectrum; 11551 mem[6] = cimg::PI; mem[7] = std::exp(1.0); // Then [8] = x, [9] = y, [10] = z, [11] = c 11552 mempos = 12; 11553 result = compile(expr._data,expr._data+l); // Compile formula into a serie of opcodes. 11554 } 11555 11556 // Insert code instructions. 11557 unsigned int opcode0(const char op) { 11558 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11559 const unsigned int pos = mempos++; 11560 CImg<uintT>::vector(op,pos).move_to(code); 11561 return pos; 11562 } 11563 11564 unsigned int opcode1(const char op, const unsigned int arg1) { 11565 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11566 const unsigned int pos = mempos++; 11567 CImg<uintT>::vector(op,pos,arg1).move_to(code); 11568 return pos; 11569 } 11570 11571 unsigned int opcode2(const char op, const unsigned int arg1, const unsigned int arg2) { 11572 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11573 const unsigned int pos = mempos++; 11574 CImg<uintT>::vector(op,pos,arg1,arg2).move_to(code); 11575 return pos; 11576 } 11577 11578 unsigned int opcode3(const char op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { 11579 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11580 const unsigned int pos = mempos++; 11581 CImg<uintT>::vector(op,pos,arg1,arg2,arg3).move_to(code); 11582 return pos; 11583 } 11584 11585 unsigned int opcode5(const char op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, 11586 const unsigned int arg4, const unsigned int arg5) { 11587 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11588 const unsigned int pos = mempos++; 11589 CImg<uintT>::vector(op,pos,arg1,arg2,arg3,arg4,arg5).move_to(code); 11590 return pos; 11591 } 11592 11593 // Compilation procedure. 11594 unsigned int compile(char *const ss, char *const se) { 11595 if (!ss || se<=ss || !*ss) { 11596 throw CImgArgumentException("[_cimg_math_parser] " 11597 "CImg<%s>::%s() : Missing item in specified expression '%s'.", 11598 pixel_type(),calling_function, 11599 expr._data); 11600 } 11601 char 11602 *const se1 = se-1, *const se2 = se-2, *const se3 = se-3, *const se4 = se-4, 11603 *const ss1 = ss+1, *const ss2 = ss+2, *const ss3 = ss+3, *const ss4 = ss+4, 11604 *const ss5 = ss+5, *const ss6 = ss+6, *const ss7 = ss+7; 11605 const char saved_char = *se; *se = 0; 11606 const unsigned int clevel = level[ss-expr._data], clevel1 = clevel+1; 11607 11608 // Look for a single value, variable or variable assignment. 11609 char end = 0; double val = 0; 11610 if (std::sscanf(ss,"%lf%c",&val,&end)==1) { 11611 if (val==0) _cimg_mp_return(0); 11612 if (val==1) _cimg_mp_return(1); 11613 if (mempos>=mem._width) mem.resize(-200,1,1,1,0); 11614 const unsigned int pos = mempos++; 11615 mem[pos] = val; 11616 _cimg_mp_return(pos); 11617 } 11618 if (ss1==se) switch (*ss) { 11619 case 'w' : _cimg_mp_return(2); case 'h' : _cimg_mp_return(3); case 'd' : _cimg_mp_return(4); case 's' : _cimg_mp_return(5); 11620 case 'x' : _cimg_mp_return(8); case 'y' : _cimg_mp_return(9); case 'z' : _cimg_mp_return(10); case 'c' : _cimg_mp_return(11); 11621 case 'e' : _cimg_mp_return(7); 11622 case 'u' : case '?' : _cimg_mp_opcode2(0,0,1); 11623 case 'g' : _cimg_mp_opcode0(1); 11624 case 'i' : _cimg_mp_opcode0(2); 11625 } 11626 if (ss1==se1) { 11627 if (*ss=='p' && *ss1=='i') _cimg_mp_return(6); // pi 11628 if (*ss=='i') { 11629 if (*ss1=='m') _cimg_mp_opcode0(57); // im 11630 if (*ss1=='M') _cimg_mp_opcode0(58); // iM 11631 if (*ss1=='a') _cimg_mp_opcode0(59); // ia 11632 if (*ss1=='v') _cimg_mp_opcode0(60); // iv 11633 } 11634 if (*ss1=='m') { 11635 if (*ss=='x') _cimg_mp_opcode0(61); // xm 11636 if (*ss=='y') _cimg_mp_opcode0(62); // ym 11637 if (*ss=='z') _cimg_mp_opcode0(63); // zm 11638 if (*ss=='c') _cimg_mp_opcode0(64); // cm 11639 } 11640 if (*ss1=='M') { 11641 if (*ss=='x') _cimg_mp_opcode0(65); // xM 11642 if (*ss=='y') _cimg_mp_opcode0(66); // yM 11643 if (*ss=='z') _cimg_mp_opcode0(67); // zM 11644 if (*ss=='c') _cimg_mp_opcode0(68); // cM 11645 } 11646 } 11647 if (ss3==se) { 11648 if (*ss=='x' && *ss1=='/' && *ss2=='w') _cimg_mp_opcode0(3); 11649 if (*ss=='y' && *ss1=='/' && *ss2=='h') _cimg_mp_opcode0(4); 11650 if (*ss=='z' && *ss1=='/' && *ss2=='d') _cimg_mp_opcode0(5); 11651 if (*ss=='c' && *ss1=='/' && *ss2=='s') _cimg_mp_opcode0(6); 11652 } 11653 11654 // Look for variable declarations. 11655 for (char *s = se2; s>ss; --s) if (*s==';' && level[s-expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s+1,se)); } 11656 for (char *s = ss1, *ps = ss, *ns = ss2; s<se1; ++s, ++ps, ++ns) 11657 if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && level[s-expr._data]==clevel) { 11658 CImg<charT> variable_name(ss,s-ss+1); variable_name.back() = 0; 11659 bool is_valid_name = true; 11660 if ((*ss>='0' && *ss<='9') || 11661 (s==ss+1 && (*ss=='x' || *ss=='y' || *ss=='z' || *ss=='c' || 11662 *ss=='w' || *ss=='h' || *ss=='d' || *ss=='s' || 11663 *ss=='e' || *ss=='u' || *ss=='g' || *ss=='i')) || 11664 (s==ss+2 && ((*ss=='p' && *(ss+1)=='i') || 11665 (*ss=='i' && (*(ss+1)=='m' || *(ss+1)=='M' || *(ss+1)=='a' || *(ss+1)=='v'))))) is_valid_name = false; 11666 for (const char *ns = ss; ns<s; ++ns) 11667 if ((*ns<'a' || *ns>'z') && (*ns<'A' || *ns>'Z') && (*ns<'0' || *ns>'9') && *ns!='_') { 11668 is_valid_name = false; break; 11669 } 11670 if (!is_valid_name) { 11671 *se = saved_char; 11672 if (!std::strcmp(variable_name,"x") || !std::strcmp(variable_name,"y") || !std::strcmp(variable_name,"z") || 11673 !std::strcmp(variable_name,"c") || !std::strcmp(variable_name,"w") || !std::strcmp(variable_name,"h") || 11674 !std::strcmp(variable_name,"d") || !std::strcmp(variable_name,"s") || !std::strcmp(variable_name,"e") || 11675 !std::strcmp(variable_name,"u") || !std::strcmp(variable_name,"g") || !std::strcmp(variable_name,"i") || 11676 !std::strcmp(variable_name,"pi") || !std::strcmp(variable_name,"im") || !std::strcmp(variable_name,"iM") || 11677 !std::strcmp(variable_name,"ia") || !std::strcmp(variable_name,"iv")) 11678 throw CImgArgumentException("[_cimg_math_parser] " 11679 "CImg<%s>::%s() : Invalid assignment of reserved variable name '%s' in specified expression '%s'.", 11680 pixel_type(),calling_function, 11681 variable_name._data,expr._data); 11682 else 11683 throw CImgArgumentException("[_cimg_math_parser] " 11684 "CImg<%s>::%s() : Invalid variable name '%s' in specified expression '%s'.", 11685 pixel_type(),calling_function, 11686 variable_name._data,expr._data); 11687 } 11688 for (unsigned int i = 0; i<mempos; ++i) // Check for existing variable with same name. 11689 if (label[i]._data && !std::strcmp(variable_name,label[i])) { 11690 *se = saved_char; 11691 throw CImgArgumentException("[_cimg_math_parser] " 11692 "CImg<%s>::%s() : Invalid multiple assignments of variable '%s' in specified expression '%s'.", 11693 pixel_type(),calling_function, 11694 variable_name._data,expr._data); 11695 } 11696 const unsigned int src_pos = compile(s+1,se); 11697 if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); 11698 const unsigned int dest_pos = mempos++; 11699 variable_name.move_to(label[dest_pos]); 11700 CImg<uintT>::vector(7,dest_pos,src_pos).move_to(code); 11701 _cimg_mp_return(dest_pos); 11702 } 11703 11704 // Look for unary/binary operators. The operator precedences is defined as in C++. 11705 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s-expr._data]==clevel) _cimg_mp_opcode2(8,compile(ss,s),compile(s+2,se)); 11706 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s-expr._data]==clevel) _cimg_mp_opcode2(9,compile(ss,s),compile(s+2,se)); 11707 for (char *s = se2; s>ss; --s) if (*s=='|' && level[s-expr._data]==clevel) _cimg_mp_opcode2(10,compile(ss,s),compile(s+1,se)); 11708 for (char *s = se2; s>ss; --s) if (*s=='&' && level[s-expr._data]==clevel) _cimg_mp_opcode2(11,compile(ss,s),compile(s+1,se)); 11709 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='!' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(12,compile(ss,s),compile(s+2,se)); 11710 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='=' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(13,compile(ss,s),compile(s+2,se)); 11711 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(14,compile(ss,s),compile(s+2,se)); 11712 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(15,compile(ss,s),compile(s+2,se)); 11713 for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) 11714 if (*s=='<' && *ns!='<' && *ps!='<' && level[s-expr._data]==clevel) _cimg_mp_opcode2(16,compile(ss,s),compile(s+1,se)); 11715 for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps) 11716 if (*s=='>' && *ns!='>' && *ps!='>' && level[s-expr._data]==clevel) _cimg_mp_opcode2(17,compile(ss,s),compile(s+1,se)); 11717 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='<' && level[s-expr._data]==clevel) _cimg_mp_opcode2(18,compile(ss,s),compile(s+2,se)); 11718 for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='>' && level[s-expr._data]==clevel) _cimg_mp_opcode2(19,compile(ss,s),compile(s+2,se)); 11719 for (char *s = se2, *ps = se3; s>ss; --s, --ps) 11720 if (*s=='-' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && 11721 (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel) 11722 _cimg_mp_opcode2(20,compile(ss,s),compile(s+1,se)); 11723 for (char *s = se2, *ps = se3; s>ss; --s, --ps) 11724 if (*s=='+' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && 11725 (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel) 11726 _cimg_mp_opcode2(21,compile(ss,s),compile(s+1,se)); 11727 for (char *s = se2; s>ss; --s) if (*s=='*' && level[s-expr._data]==clevel) _cimg_mp_opcode2(22,compile(ss,s),compile(s+1,se)); 11728 for (char *s = se2; s>ss; --s) if (*s=='/' && level[s-expr._data]==clevel) _cimg_mp_opcode2(23,compile(ss,s),compile(s+1,se)); 11729 for (char *s = se2; s>ss; --s) if (*s=='%' && level[s-expr._data]==clevel) _cimg_mp_opcode2(24,compile(ss,s),compile(s+1,se)); 11730 if (ss<se1) { 11731 if (*ss=='-') _cimg_mp_opcode1(26,compile(ss1,se)); 11732 if (*ss=='+') _cimg_mp_return(compile(ss1,se)); 11733 if (*ss=='!') _cimg_mp_opcode1(27,compile(ss1,se)); 11734 if (*ss=='~') _cimg_mp_opcode1(28,compile(ss1,se)); 11735 } 11736 for (char *s = se2; s>ss; --s) if (*s=='^' && level[s-expr._data]==clevel) _cimg_mp_opcode2(25,compile(ss,s),compile(s+1,se)); 11737 11738 // Look for a function call or a parenthesis. 11739 if (*se1==')') { 11740 if (*ss=='(') _cimg_mp_return(compile(ss1,se1)); 11741 if (!std::strncmp(ss,"sin(",4)) _cimg_mp_opcode1(29,compile(ss4,se1)); 11742 if (!std::strncmp(ss,"cos(",4)) _cimg_mp_opcode1(30,compile(ss4,se1)); 11743 if (!std::strncmp(ss,"tan(",4)) _cimg_mp_opcode1(31,compile(ss4,se1)); 11744 if (!std::strncmp(ss,"asin(",5)) _cimg_mp_opcode1(32,compile(ss5,se1)); 11745 if (!std::strncmp(ss,"acos(",5)) _cimg_mp_opcode1(33,compile(ss5,se1)); 11746 if (!std::strncmp(ss,"atan(",5)) _cimg_mp_opcode1(34,compile(ss5,se1)); 11747 if (!std::strncmp(ss,"sinh(",5)) _cimg_mp_opcode1(35,compile(ss5,se1)); 11748 if (!std::strncmp(ss,"cosh(",5)) _cimg_mp_opcode1(36,compile(ss5,se1)); 11749 if (!std::strncmp(ss,"tanh(",5)) _cimg_mp_opcode1(37,compile(ss5,se1)); 11750 if (!std::strncmp(ss,"log10(",6)) _cimg_mp_opcode1(38,compile(ss6,se1)); 11751 if (!std::strncmp(ss,"log(",4)) _cimg_mp_opcode1(39,compile(ss4,se1)); 11752 if (!std::strncmp(ss,"exp(",4)) _cimg_mp_opcode1(40,compile(ss4,se1)); 11753 if (!std::strncmp(ss,"sqrt(",5)) _cimg_mp_opcode1(41,compile(ss5,se1)); 11754 if (!std::strncmp(ss,"sign(",5)) _cimg_mp_opcode1(42,compile(ss5,se1)); 11755 if (!std::strncmp(ss,"abs(",4)) _cimg_mp_opcode1(43,compile(ss4,se1)); 11756 if (!std::strncmp(ss,"atan2(",6)) { 11757 char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11758 _cimg_mp_opcode2(44,compile(ss6,s1),compile(s1+1,se1)); 11759 } 11760 if (!std::strncmp(ss,"if(",3)) { 11761 char *s1 = ss3; while (s1<se4 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11762 char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2; 11763 _cimg_mp_opcode3(45,compile(ss3,s1),compile(s1+1,s2),compile(s2+1,se1)); 11764 } 11765 if (!std::strncmp(ss,"round(",6)) { 11766 unsigned int value = 0, round = 1, direction = 0; 11767 char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11768 value = compile(ss6,s1==se2?++s1:s1); 11769 if (s1<se1) { 11770 char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2; 11771 round = compile(s1+1,s2==se2?++s2:s2); 11772 if (s2<se1) direction = compile(s2+1,se1); 11773 } 11774 _cimg_mp_opcode3(46,value,round,direction); 11775 } 11776 if (!std::strncmp(ss,"?(",2) || !std::strncmp(ss,"u(",2)) { 11777 if (*ss2==')') _cimg_mp_opcode2(0,0,1); 11778 char *s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11779 if (s1<se1) _cimg_mp_opcode2(0,compile(ss2,s1),compile(s1+1,se1)); 11780 _cimg_mp_opcode2(0,0,compile(ss2,s1)); 11781 } 11782 if (!std::strncmp(ss,"i(",2)) { 11783 if (*ss2==')') _cimg_mp_return(0); 11784 unsigned int indx = 8, indy = 9, indz = 10, indc = 11, borders = 0; 11785 if (ss2!=se1) { 11786 char *s1 = ss2; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11787 indx = compile(ss2,s1==se2?++s1:s1); 11788 if (s1<se1) { 11789 char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2; 11790 indy = compile(s1+1,s2==se2?++s2:s2); 11791 if (s2<se1) { 11792 char *s3 = s2+1; while (s3<se2 && (*s3!=',' || level[s3-expr._data]!=clevel1)) ++s3; 11793 indz = compile(s2+1,s3==se2?++s3:s3); 11794 if (s3<se1) { 11795 char *s4 = s3+1; while (s4<se2 && (*s4!=',' || level[s4-expr._data]!=clevel1)) ++s4; 11796 indc = compile(s3+1,s4==se2?++s4:s4); 11797 if (s4<se1) borders = compile(s4+1,se1); 11798 } 11799 } 11800 } 11801 } 11802 _cimg_mp_opcode5(47,indx,indy,indz,indc,borders); 11803 } 11804 if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4)) { 11805 CImgList<uintT> opcode; 11806 if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); 11807 const unsigned int pos = mempos++; 11808 CImg<uintT>::vector(ss[1]=='i'?48:49,pos).move_to(opcode); 11809 for (char *s = ss4; s<se; ++s) { 11810 char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr._data]!=clevel1) && (*ns!=')' || level[ns-expr._data]!=clevel)) ++ns; 11811 CImg<uintT>::vector(compile(s,ns)).move_to(opcode); 11812 s = ns; 11813 } 11814 (opcode>'y').move_to(code); 11815 _cimg_mp_return(pos); 11816 } 11817 if (!std::strncmp(ss,"narg(",5)) { 11818 if (*ss5==')') _cimg_mp_return(0); 11819 unsigned int nb = 0; 11820 for (char *s = ss5; s<se; ++s) { 11821 char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr._data]!=clevel1) && (*ns!=')' || level[ns-expr._data]!=clevel)) ++ns; 11822 ++nb; s = ns; 11823 } 11824 if (nb==0 || nb==1) _cimg_mp_return(nb); 11825 if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); 11826 const unsigned int pos = mempos++; 11827 mem[pos] = nb; 11828 _cimg_mp_return(pos); 11829 } 11830 if (!std::strncmp(ss,"isval(",6)) { 11831 char sep = 0, end = 0; double val = 0; 11832 if (std::sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); 11833 _cimg_mp_return(0); 11834 } 11835 if (!std::strncmp(ss,"isnan(",6)) _cimg_mp_opcode1(50,compile(ss6,se1)); 11836 if (!std::strncmp(ss,"isinf(",6)) _cimg_mp_opcode1(51,compile(ss6,se1)); 11837 if (!std::strncmp(ss,"isint(",6)) _cimg_mp_opcode1(52,compile(ss6,se1)); 11838 if (!std::strncmp(ss,"isbool(",7)) _cimg_mp_opcode1(53,compile(ss7,se1)); 11839 if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { 11840 unsigned int value = 0, nb = 1; 11841 char *s1 = ss4; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1; 11842 value = compile(ss4,s1==se2?++s1:s1); 11843 if (s1<se1) { 11844 char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2; 11845 nb = compile(s1+1,se1); 11846 } 11847 _cimg_mp_opcode2(*ss2=='l'?54:55,value,nb); 11848 } 11849 11850 if (!std::strncmp(ss,"sinc(",5)) _cimg_mp_opcode1(56,compile(ss5,se1)); 11851 11852 } 11853 11854 // No known item found, assuming this is an already initialize variable. 11855 CImg<charT> variable_name(ss,se-ss+1); variable_name.back() = 0; 11856 for (unsigned int i = 0; i<mempos; ++i) if (label[i]._data && !std::strcmp(variable_name,label[i])) _cimg_mp_return(i); 11857 *se = saved_char; 11858 throw CImgArgumentException("[_cimg_math_parser] " 11859 "CImg<%s>::%s() : Invalid item '%s' in specified expression '%s'.\n", 11860 pixel_type(),calling_function, 11861 variable_name._data,expr._data); 11862 return 0; 11863 } 11864 11865 // Evaluation functions, known by the parser. 11866 double mp_u() { 11867 return mem[opcode(2)] + cimg::rand()*(mem[opcode(3)]-mem[opcode(2)]); 11868 } 11869 double mp_g() { 11870 return cimg::grand(); 11871 } 11872 double mp_i() { 11873 return (double)reference.atXYZC((int)mem[8],(int)mem[9],(int)mem[10],(int)mem[11],0); 11874 } 11875 double mp_xw() { 11876 return mem[8]/reference.width(); 11877 } 11878 double mp_yh() { 11879 return mem[9]/reference.height(); 11880 } 11881 double mp_zd() { 11882 return mem[10]/reference.depth(); 11883 } 11884 double mp_cs() { 11885 return mem[11]/reference.spectrum(); 11886 } 11887 double mp_equal() { 11888 return mem[opcode[2]]; 11889 } 11890 double mp_logical_and() { 11891 return (double)((bool)mem[opcode(2)] && (bool)mem[opcode(3)]); 11892 } 11893 double mp_logical_or() { 11894 return (double)((bool)mem[opcode(2)] || (bool)mem[opcode(3)]); 11895 } 11896 double mp_infeq() { 11897 return (double)(mem[opcode(2)] <= mem[opcode(3)]); 11898 } 11899 double mp_supeq() { 11900 return (double)(mem[opcode(2)] >= mem[opcode(3)]); 11901 } 11902 double mp_noteq() { 11903 return (double)(mem[opcode(2)] != mem[opcode(3)]); 11904 } 11905 double mp_eqeq() { 11906 return (double)(mem[opcode(2)] == mem[opcode(3)]); 11907 } 11908 double mp_inf() { 11909 return (double)(mem[opcode(2)] < mem[opcode(3)]); 11910 } 11911 double mp_sup() { 11912 return (double)(mem[opcode(2)] > mem[opcode(3)]); 11913 } 11914 double mp_add() { 11915 return mem[opcode(2)] + mem[opcode(3)]; 11916 } 11917 double mp_sub() { 11918 return mem[opcode(2)] - mem[opcode(3)]; 11919 } 11920 double mp_mul() { 11921 return mem[opcode(2)] * mem[opcode(3)]; 11922 } 11923 double mp_div() { 11924 return mem[opcode(2)] / mem[opcode(3)]; 11925 } 11926 double mp_minus() { 11927 return -mem[opcode(2)]; 11928 } 11929 double mp_not() { 11930 return !mem[opcode(2)]; 11931 } 11932 double mp_logical_not() { 11933 return !mem[opcode(2)]; 11934 } 11935 double mp_bitwise_not() { 11936 return ~(unsigned long)mem[opcode(2)]; 11937 } 11938 double mp_modulo() { 11939 return cimg::mod(mem[opcode(2)],mem[opcode(3)]); 11940 } 11941 double mp_bitwise_and() { 11942 return ((unsigned long)mem[opcode(2)] & (unsigned long)mem[opcode(3)]); 11943 } 11944 double mp_bitwise_or() { 11945 return ((unsigned long)mem[opcode(2)] | (unsigned long)mem[opcode(3)]); 11946 } 11947 double mp_pow() { 11948 return std::pow(mem[opcode(2)],mem[opcode(3)]); 11949 } 11950 double mp_sin() { 11951 return std::sin(mem[opcode(2)]); 11952 } 11953 double mp_cos() { 11954 return std::cos(mem[opcode(2)]); 11955 } 11956 double mp_tan() { 11957 return std::tan(mem[opcode(2)]); 11958 } 11959 double mp_asin() { 11960 return std::asin(mem[opcode(2)]); 11961 } 11962 double mp_acos() { 11963 return std::acos(mem[opcode(2)]); 11964 } 11965 double mp_atan() { 11966 return std::atan(mem[opcode(2)]); 11967 } 11968 double mp_sinh() { 11969 return std::sinh(mem[opcode(2)]); 11970 } 11971 double mp_cosh() { 11972 return std::cosh(mem[opcode(2)]); 11973 } 11974 double mp_tanh() { 11975 return std::tanh(mem[opcode(2)]); 11976 } 11977 double mp_log10() { 11978 return std::log10(mem[opcode(2)]); 11979 } 11980 double mp_log() { 11981 return std::log(mem[opcode(2)]); 11982 } 11983 double mp_exp() { 11984 return std::exp(mem[opcode(2)]); 11985 } 11986 double mp_sqrt() { 11987 return std::sqrt(mem[opcode(2)]); 11988 } 11989 double mp_sign() { 11990 return cimg::sign(mem[opcode(2)]); 11991 } 11992 double mp_abs() { 11993 return cimg::abs(mem[opcode(2)]); 11994 } 11995 double mp_atan2() { 11996 return std::atan2(mem[opcode(2)],mem[opcode(3)]); 11997 } 11998 double mp_if() { 11999 return mem[opcode(2)]?mem[opcode(3)]:mem[opcode(4)]; 12000 } 12001 double mp_round() { 12002 return cimg::round(mem[opcode(2)],mem[opcode(3)],(int)mem[opcode(4)]); 12003 } 12004 double mp_ixyzc() { 12005 const int c = (int)mem[opcode(5)], b = (int)mem[opcode(6)]; 12006 if (b==0) return (double)reference.linear_atXYZ((float)mem[opcode(2)], 12007 (float)mem[opcode(3)], 12008 (float)mem[opcode(4)], 12009 c<0?0:c>=reference.spectrum()?reference.spectrum()-1:c,0); 12010 if (b==1) return (double)reference.linear_atXYZ((float)mem[opcode(2)], 12011 (float)mem[opcode(3)], 12012 (float)mem[opcode(4)], 12013 c<0?0:c>=reference.spectrum()?reference.spectrum()-1:c); 12014 return (double)reference.linear_atXYZ((float)cimg::mod(mem[opcode(2)],(double)reference.width()), 12015 (float)cimg::mod(mem[opcode(3)],(double)reference.height()), 12016 (float)cimg::mod(mem[opcode(4)],(double)reference.depth()), 12017 c<0?0:c>=reference.spectrum()?reference.spectrum()-1:c); 12018 } 12019 double mp_min() { 12020 double val = mem[opcode(2)]; 12021 for (unsigned int i = 3; i<opcode._height; ++i) val = cimg::min(val,mem[opcode(i)]); 12022 return val; 12023 } 12024 double mp_max() { 12025 double val = mem[opcode(2)]; 12026 for (unsigned int i = 3; i<opcode._height; ++i) val = cimg::max(val,mem[opcode(i)]); 12027 return val; 12028 } 12029 double mp_isnan() { 12030 const double val = mem[opcode(2)]; 12031 return !(val == val); 12032 } 12033 double mp_isinf() { 12034 const double val = mem[opcode(2)]; 12035 return val == (val+1); 12036 } 12037 double mp_isint() { 12038 const double val = mem[opcode(2)]; 12039 return (double)(int)val == val; 12040 } 12041 double mp_isbool() { 12042 const double val = mem[opcode(2)]; 12043 return (val==0.0 || val==1.0); 12044 } 12045 double mp_rol() { 12046 return cimg::rol(mem[opcode(2)],(unsigned int)mem[opcode(3)]); 12047 } 12048 double mp_ror() { 12049 return cimg::ror(mem[opcode(2)],(unsigned int)mem[opcode(3)]); 12050 } 12051 double mp_lsl() { 12052 return (long)mem[opcode(2)]<<(unsigned int)mem[opcode(3)]; 12053 } 12054 double mp_lsr() { 12055 return (long)mem[opcode(2)]>>(unsigned int)mem[opcode(3)]; 12056 } 12057 double mp_sinc() { 12058 return cimg::sinc(mem[opcode(2)]); 12059 } 12060 double mp_im() { 12061 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12062 return reference_stats?reference_stats[0]:0; 12063 } 12064 double mp_iM() { 12065 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12066 return reference_stats?reference_stats[1]:0; 12067 } 12068 double mp_ia() { 12069 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12070 return reference_stats?reference_stats[2]:0; 12071 } 12072 double mp_iv() { 12073 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12074 return reference_stats?reference_stats[3]:0; 12075 } 12076 double mp_xm() { 12077 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12078 return reference_stats?reference_stats[4]:0; 12079 } 12080 double mp_ym() { 12081 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12082 return reference_stats?reference_stats[5]:0; 12083 } 12084 double mp_zm() { 12085 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12086 return reference_stats?reference_stats[6]:0; 12087 } 12088 double mp_cm() { 12089 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12090 return reference_stats?reference_stats[7]:0; 12091 } 12092 double mp_xM() { 12093 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12094 return reference_stats?reference_stats[8]:0; 12095 } 12096 double mp_yM() { 12097 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12098 return reference_stats?reference_stats[9]:0; 12099 } 12100 double mp_zM() { 12101 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12102 return reference_stats?reference_stats[10]:0; 12103 } 12104 double mp_cM() { 12105 if (!reference_stats) reference.get_stats().move_to(reference_stats); 12106 return reference_stats?reference_stats[11]:0; 12107 } 12108 12109 // Evaluation procedure, with image data. 12110 double eval(const double x, const double y, const double z, const double c) { 12111 typedef double (_cimg_math_parser::*mp_func)(); 12112 const mp_func mp_funcs[] = { 12113 &_cimg_math_parser::mp_u, // 0 12114 &_cimg_math_parser::mp_g, // 1 12115 &_cimg_math_parser::mp_i, // 2 12116 &_cimg_math_parser::mp_xw, // 3 12117 &_cimg_math_parser::mp_yh, // 4 12118 &_cimg_math_parser::mp_zd, // 5 12119 &_cimg_math_parser::mp_cs, // 6 12120 &_cimg_math_parser::mp_equal, // 7 12121 &_cimg_math_parser::mp_logical_or, // 8 12122 &_cimg_math_parser::mp_logical_and, // 9 12123 &_cimg_math_parser::mp_bitwise_or, // 10 12124 &_cimg_math_parser::mp_bitwise_and, // 11 12125 &_cimg_math_parser::mp_noteq, // 12 12126 &_cimg_math_parser::mp_eqeq, // 13 12127 &_cimg_math_parser::mp_infeq, // 14 12128 &_cimg_math_parser::mp_supeq, // 15 12129 &_cimg_math_parser::mp_inf, // 16 12130 &_cimg_math_parser::mp_sup, // 17 12131 &_cimg_math_parser::mp_lsl, // 18 12132 &_cimg_math_parser::mp_lsr, // 19 12133 &_cimg_math_parser::mp_sub, // 20 12134 &_cimg_math_parser::mp_add, // 21 12135 &_cimg_math_parser::mp_mul, // 22 12136 &_cimg_math_parser::mp_div, // 23 12137 &_cimg_math_parser::mp_modulo, // 24 12138 &_cimg_math_parser::mp_pow, // 25 12139 &_cimg_math_parser::mp_minus, // 26 12140 &_cimg_math_parser::mp_logical_not, // 27 12141 &_cimg_math_parser::mp_bitwise_not, // 28 12142 &_cimg_math_parser::mp_sin, // 29 12143 &_cimg_math_parser::mp_cos, // 30 12144 &_cimg_math_parser::mp_tan, // 31 12145 &_cimg_math_parser::mp_asin, // 32 12146 &_cimg_math_parser::mp_acos, // 33 12147 &_cimg_math_parser::mp_atan, // 34 12148 &_cimg_math_parser::mp_sinh, // 35 12149 &_cimg_math_parser::mp_cosh, // 36 12150 &_cimg_math_parser::mp_tanh, // 37 12151 &_cimg_math_parser::mp_log10, // 38 12152 &_cimg_math_parser::mp_log, // 39 12153 &_cimg_math_parser::mp_exp, // 40 12154 &_cimg_math_parser::mp_sqrt, // 41 12155 &_cimg_math_parser::mp_sign, // 42 12156 &_cimg_math_parser::mp_abs, // 43 12157 &_cimg_math_parser::mp_atan2, // 44 12158 &_cimg_math_parser::mp_if, // 45 12159 &_cimg_math_parser::mp_round, // 46 12160 &_cimg_math_parser::mp_ixyzc, // 47 12161 &_cimg_math_parser::mp_min, // 48 12162 &_cimg_math_parser::mp_max, // 49 12163 &_cimg_math_parser::mp_isnan, // 50 12164 &_cimg_math_parser::mp_isinf, // 51 12165 &_cimg_math_parser::mp_isint, // 52 12166 &_cimg_math_parser::mp_isbool, // 53 12167 &_cimg_math_parser::mp_rol, // 54 12168 &_cimg_math_parser::mp_ror, // 55 12169 &_cimg_math_parser::mp_sinc, // 56 12170 &_cimg_math_parser::mp_im, // 57 12171 &_cimg_math_parser::mp_iM, // 58 12172 &_cimg_math_parser::mp_ia, // 59 12173 &_cimg_math_parser::mp_iv, // 60 12174 &_cimg_math_parser::mp_xm, // 61 12175 &_cimg_math_parser::mp_ym, // 62 12176 &_cimg_math_parser::mp_zm, // 63 12177 &_cimg_math_parser::mp_cm, // 64 12178 &_cimg_math_parser::mp_xM, // 65 12179 &_cimg_math_parser::mp_yM, // 66 12180 &_cimg_math_parser::mp_zM, // 67 12181 &_cimg_math_parser::mp_cM // 68 12182 }; 12183 12184 if (!mem) return 0; 12185 mem[8] = x; mem[9] = y; mem[10] = z; mem[11] = c; 12186 opcode._is_shared = true; opcode._width = opcode._depth = opcode._spectrum = 1; 12187 cimglist_for(code,l) { 12188 const CImg<uintT> &op = code[l]; 12189 opcode._data = op._data; opcode._height = op._height; // Allows to avoid parameter passing to evaluation functions. 12190 mem[opcode(1)] = (this->*mp_funcs[opcode[0]])(); 12191 } 12192 return mem[result]; 12193 } 12194 }; 12195 12196 //! Compute the square value of each pixel. 12197 CImg<T>& sqr() { 12198 cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); }; 12199 return *this; 12200 } 12201 12202 CImg<Tfloat> get_sqr() const { 12203 return CImg<Tfloat>(*this,false).sqr(); 12204 } 12205 12206 //! Compute the square root of each pixel value. 12207 CImg<T>& sqrt() { 12208 cimg_for(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd); 12209 return *this; 12210 } 12211 12212 CImg<Tfloat> get_sqrt() const { 12213 return CImg<Tfloat>(*this,false).sqrt(); 12214 } 12215 12216 //! Compute the exponential of each pixel value. 12217 CImg<T>& exp() { 12218 cimg_for(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd); 12219 return *this; 12220 } 12221 12222 CImg<Tfloat> get_exp() const { 12223 return CImg<Tfloat>(*this,false).exp(); 12224 } 12225 12226 //! Compute the log of each each pixel value. 12227 CImg<T>& log() { 12228 cimg_for(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd); 12229 return *this; 12230 } 12231 12232 CImg<Tfloat> get_log() const { 12233 return CImg<Tfloat>(*this,false).log(); 12234 } 12235 12236 //! Compute the log10 of each each pixel value. 12237 CImg<T>& log10() { 12238 cimg_for(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd); 12239 return *this; 12240 } 12241 12242 CImg<Tfloat> get_log10() const { 12243 return CImg<Tfloat>(*this,false).log10(); 12244 } 12245 12246 //! Compute the absolute value of each pixel value. 12247 CImg<T>& abs() { 12248 cimg_for(*this,ptrd,T) *ptrd = cimg::abs(*ptrd); 12249 return *this; 12250 } 12251 12252 CImg<Tfloat> get_abs() const { 12253 return CImg<Tfloat>(*this,false).abs(); 12254 } 12255 12256 //! Compute the sign of each pixel value. 12257 CImg<T>& sign() { 12258 cimg_for(*this,ptrd,T) *ptrd = cimg::sign(*ptrd); 12259 return *this; 12260 } 12261 12262 CImg<Tfloat> get_sign() const { 12263 return CImg<Tfloat>(*this,false).sign(); 12264 } 12265 12266 //! Compute the cosinus of each pixel value. 12267 CImg<T>& cos() { 12268 cimg_for(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd); 12269 return *this; 12270 } 12271 12272 CImg<Tfloat> get_cos() const { 12273 return CImg<Tfloat>(*this,false).cos(); 12274 } 12275 12276 //! Compute the sinus of each pixel value. 12277 CImg<T>& sin() { 12278 cimg_for(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd); 12279 return *this; 12280 } 12281 12282 CImg<Tfloat> get_sin() const { 12283 return CImg<Tfloat>(*this,false).sin(); 12284 } 12285 12286 //! Compute the sinus cardinal of each pixel value. 12287 CImg<T>& sinc() { 12288 cimg_for(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd); 12289 return *this; 12290 } 12291 12292 CImg<Tfloat> get_sinc() const { 12293 return CImg<Tfloat>(*this,false).sinc(); 12294 } 12295 12296 //! Compute the tangent of each pixel. 12297 CImg<T>& tan() { 12298 cimg_for(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd); 12299 return *this; 12300 } 12301 12302 CImg<Tfloat> get_tan() const { 12303 return CImg<Tfloat>(*this,false).tan(); 12304 } 12305 12306 //! Compute the hyperbolic cosine of each pixel value. 12307 CImg<T>& cosh() { 12308 cimg_for(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd); 12309 return *this; 12310 } 12311 12312 CImg<Tfloat> get_cosh() const { 12313 return CImg<Tfloat>(*this,false).cosh(); 12314 } 12315 12316 //! Compute the hyperbolic sine of each pixel value. 12317 CImg<T>& sinh() { 12318 cimg_for(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd); 12319 return *this; 12320 } 12321 12322 CImg<Tfloat> get_sinh() const { 12323 return CImg<Tfloat>(*this,false).sinh(); 12324 } 12325 12326 //! Compute the hyperbolic tangent of each pixel value. 12327 CImg<T>& tanh() { 12328 cimg_for(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd); 12329 return *this; 12330 } 12331 12332 CImg<Tfloat> get_tanh() const { 12333 return CImg<Tfloat>(*this,false).tanh(); 12334 } 12335 12336 //! Compute the arc-cosine of each pixel value. 12337 CImg<T>& acos() { 12338 cimg_for(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd); 12339 return *this; 12340 } 12341 12342 CImg<Tfloat> get_acos() const { 12343 return CImg<Tfloat>(*this,false).acos(); 12344 } 12345 12346 //! Compute the arc-sinus of each pixel value. 12347 CImg<T>& asin() { 12348 cimg_for(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd); 12349 return *this; 12350 } 12351 12352 CImg<Tfloat> get_asin() const { 12353 return CImg<Tfloat>(*this,false).asin(); 12354 } 12355 12356 //! Compute the arc-tangent of each pixel. 12357 CImg<T>& atan() { 12358 cimg_for(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd); 12359 return *this; 12360 } 12361 12362 CImg<Tfloat> get_atan() const { 12363 return CImg<Tfloat>(*this,false).atan(); 12364 } 12365 12366 //! Compute the arc-tangent of each pixel. 12367 template<typename t> 12368 CImg<T>& atan2(const CImg<t>& img) { 12369 const unsigned int smin = cimg::min(size(),img.size()); 12370 t *ptrs = img._data + smin; 12371 for (T *ptrd = _data + smin; ptrd>_data; --ptrd, *ptrd = (T)std::atan2((double)*ptrd,(double)*(--ptrs))) {} 12372 return *this; 12373 } 12374 12375 template<typename t> 12376 CImg<Tfloat> get_atan2(const CImg<t>& img) const { 12377 return CImg<Tfloat>(*this,false).atan2(img); 12378 } 12379 12380 //! Pointwise multiplication between an image and an expression. 12381 CImg<T>& mul(const char *const expression) { 12382 const unsigned int omode = cimg::exception_mode(); 12383 cimg::exception_mode() = 0; 12384 try { 12385 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12386 _cimg_math_parser mp(base,expression,"mul"); 12387 T *ptrd = _data; 12388 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp.eval(x,y,z,c)); ++ptrd; } 12389 } catch (CImgException&) { 12390 cimg::exception_mode() = omode; 12391 CImg<T> values(_width,_height,_depth,_spectrum); 12392 values = expression; 12393 mul(values); 12394 } 12395 cimg::exception_mode() = omode; 12396 return *this; 12397 } 12398 12399 //! Pointwise multiplication between two images. 12400 template<typename t> 12401 CImg<T>& mul(const CImg<t>& img) { 12402 const unsigned int siz = size(), isiz = img.size(); 12403 if (siz && isiz) { 12404 if (is_overlapped(img)) return mul(+img); 12405 T *ptrd = _data, *const ptre = _data + siz; 12406 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 12407 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++)); 12408 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++)); 12409 } 12410 return *this; 12411 } 12412 12413 template<typename t> 12414 CImg<_cimg_Tt> get_mul(const CImg<t>& img) const { 12415 return CImg<_cimg_Tt>(*this,false).mul(img); 12416 } 12417 12418 //! Pointwise division between an image and an expression. 12419 CImg<T>& div(const char *const expression) { 12420 const unsigned int omode = cimg::exception_mode(); 12421 cimg::exception_mode() = 0; 12422 try { 12423 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12424 _cimg_math_parser mp(base,expression,"div"); 12425 T *ptrd = _data; 12426 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp.eval(x,y,z,c)); ++ptrd; } 12427 } catch (CImgException&) { 12428 cimg::exception_mode() = omode; 12429 CImg<T> values(_width,_height,_depth,_spectrum); 12430 values = expression; 12431 div(values); 12432 } 12433 cimg::exception_mode() = omode; 12434 return *this; 12435 } 12436 12437 //! Pointwise division between two images. 12438 template<typename t> 12439 CImg<T>& div(const CImg<t>& img) { 12440 const unsigned int siz = size(), isiz = img.size(); 12441 if (siz && isiz) { 12442 if (is_overlapped(img)) return div(+img); 12443 T *ptrd = _data, *const ptre = _data + siz; 12444 if (siz>isiz) for (unsigned int n = siz/isiz; n; --n) 12445 for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++)); 12446 for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++)); 12447 } 12448 return *this; 12449 } 12450 12451 template<typename t> 12452 CImg<_cimg_Tt> get_div(const CImg<t>& img) const { 12453 return CImg<_cimg_Tt>(*this,false).div(img); 12454 } 12455 12456 //! Compute the power by p of each pixel value. 12457 CImg<T>& pow(const double p) { 12458 if (p==0) return fill(1); 12459 if (p==0.5) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)std::sqrt((double)val); } return *this; } 12460 if (p==1) return *this; 12461 if (p==2) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val; } return *this; } 12462 if (p==3) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; } return *this; } 12463 if (p==4) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; } return *this; } 12464 cimg_for(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p); 12465 return *this; 12466 } 12467 12468 CImg<Tfloat> get_pow(const double p) const { 12469 return CImg<Tfloat>(*this,false).pow(p); 12470 } 12471 12472 //! Compute the power of each pixel value. 12473 template<typename t> 12474 CImg<T>& pow(const CImg<t>& img) { 12475 if (is_overlapped(img)) return pow(+img); 12476 t *ptrs = img._data; 12477 T *ptrf = _data + cimg::min(size(),img.size()); 12478 for (T* ptrd = _data; ptrd<ptrf; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++))); 12479 return *this; 12480 } 12481 12482 template<typename t> 12483 CImg<Tfloat> get_pow(const CImg<t>& img) const { 12484 return CImg<Tfloat>(*this,false).pow(img); 12485 } 12486 12487 //! Compute the power of each pixel value. 12488 CImg<T>& pow(const char *const expression) { 12489 const unsigned int omode = cimg::exception_mode(); 12490 cimg::exception_mode() = 0; 12491 try { 12492 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12493 _cimg_math_parser mp(base,expression,"pow"); 12494 T *ptrd = _data; 12495 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp.eval(x,y,z,c)); ++ptrd; } 12496 } catch (CImgException&) { 12497 CImg<Tfloat> values(_width,_height,_depth,_spectrum); 12498 try { 12499 values.fill(expression,true); 12500 } catch (CImgException&) { 12501 cimg::exception_mode() = omode; 12502 values.load(expression); 12503 } 12504 pow(values); 12505 } 12506 cimg::exception_mode() = omode; 12507 return *this; 12508 } 12509 12510 CImg<Tfloat> get_pow(const char *const expression) const { 12511 return CImg<Tfloat>(*this,false).pow(expression); 12512 } 12513 12514 //! Compute the bitwise left rotation of each pixel value. 12515 CImg<T>& rol(const unsigned int n=1) { 12516 cimg_for(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n); 12517 return *this; 12518 } 12519 12520 CImg<T> get_rol(const unsigned int n=1) const { 12521 return (+*this).rol(n); 12522 } 12523 12524 template<typename t> 12525 CImg<T>& rol(const CImg<t>& img) { 12526 if (is_overlapped(img)) return rol(+img); 12527 t *ptrs = img._data; 12528 T *ptrf = _data + cimg::min(size(),img.size()); 12529 for (T* ptrd = _data; ptrd<ptrf; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++))); 12530 return *this; 12531 } 12532 12533 template<typename t> 12534 CImg<T> get_rol(const CImg<t>& img) const { 12535 return (+*this).rol(img); 12536 } 12537 12538 CImg<T>& rol(const char *const expression) { 12539 const unsigned int omode = cimg::exception_mode(); 12540 cimg::exception_mode() = 0; 12541 try { 12542 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12543 _cimg_math_parser mp(base,expression,"rol"); 12544 T *ptrd = _data; 12545 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp.eval(x,y,z,c)); ++ptrd; } 12546 } catch (CImgException&) { 12547 CImg<Tfloat> values(_width,_height,_depth,_spectrum); 12548 try { 12549 values.fill(expression,true); 12550 } catch (CImgException&) { 12551 cimg::exception_mode() = omode; 12552 values.load(expression); 12553 } 12554 rol(values); 12555 } 12556 cimg::exception_mode() = omode; 12557 return *this; 12558 } 12559 12560 CImg<T> get_rol(const char *const expression) const { 12561 return (+*this).rol(expression); 12562 } 12563 12564 //! Compute the bitwise right rotation of each pixel value. 12565 CImg<T>& ror(const unsigned int n=1) { 12566 cimg_for(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n); 12567 return *this; 12568 } 12569 12570 CImg<T> get_ror(const unsigned int n=1) const { 12571 return (+*this).ror(n); 12572 } 12573 12574 template<typename t> 12575 CImg<T>& ror(const CImg<t>& img) { 12576 if (is_overlapped(img)) return ror(+img); 12577 t *ptrs = img._data; 12578 T *ptrf = _data + cimg::min(size(),img.size()); 12579 for (T* ptrd = _data; ptrd<ptrf; ++ptrd) *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++))); 12580 return *this; 12581 } 12582 12583 template<typename t> 12584 CImg<T> get_ror(const CImg<t>& img) const { 12585 return (+*this).ror(img); 12586 } 12587 12588 CImg<T>& ror(const char *const expression) { 12589 const unsigned int omode = cimg::exception_mode(); 12590 cimg::exception_mode() = 0; 12591 try { 12592 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12593 _cimg_math_parser mp(base,expression,"ror"); 12594 T *ptrd = _data; 12595 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp.eval(x,y,z,c)); ++ptrd; } 12596 } catch (CImgException&) { 12597 CImg<Tfloat> values(_width,_height,_depth,_spectrum); 12598 try { 12599 values.fill(expression,true); 12600 } catch (CImgException&) { 12601 cimg::exception_mode() = omode; 12602 values.load(expression); 12603 } 12604 ror(values); 12605 } 12606 cimg::exception_mode() = omode; 12607 return *this; 12608 } 12609 12610 CImg<T> get_ror(const char *const expression) const { 12611 return (+*this).ror(expression); 12612 } 12613 12614 //! Pointwise min operator between an image and a value. 12615 CImg<T>& min(const T val) { 12616 cimg_for(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val); 12617 return *this; 12618 } 12619 12620 CImg<T> get_min(const T val) const { 12621 return (+*this).min(val); 12622 } 12623 12624 //! Pointwise min operator between two images. 12625 template<typename t> 12626 CImg<T>& min(const CImg<t>& img) { 12627 if (is_overlapped(img)) return min(+img); 12628 t *ptrs = img._data; 12629 T *ptrf = _data + cimg::min(size(),img.size()); 12630 for (T* ptrd = _data; ptrd<ptrf; ++ptrd) *ptrd = cimg::min((T)*(ptrs++),*ptrd); 12631 return *this; 12632 } 12633 12634 template<typename t> 12635 CImg<_cimg_Tt> get_min(const CImg<t>& img) const { 12636 return CImg<_cimg_Tt>(*this,false).min(img); 12637 } 12638 12639 //! Pointwise min operator between an image and a string. 12640 CImg<T>& min(const char *const expression) { 12641 const unsigned int omode = cimg::exception_mode(); 12642 cimg::exception_mode() = 0; 12643 try { 12644 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12645 _cimg_math_parser mp(base,expression,"min"); 12646 T *ptrd = _data; 12647 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; } 12648 } catch (CImgException&) { 12649 CImg<T> values(_width,_height,_depth,_spectrum); 12650 try { 12651 values.fill(expression,true); 12652 } catch (CImgException&) { 12653 cimg::exception_mode() = omode; 12654 values.load(expression); 12655 } 12656 min(values); 12657 } 12658 cimg::exception_mode() = omode; 12659 return *this; 12660 } 12661 12662 CImg<Tfloat> get_min(const char *const expression) const { 12663 return CImg<Tfloat>(*this,false).min(expression); 12664 } 12665 12666 //! Pointwise max operator between an image and a value. 12667 CImg<T>& max(const T val) { 12668 cimg_for(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val); 12669 return *this; 12670 } 12671 12672 CImg<T> get_max(const T val) const { 12673 return (+*this).max(val); 12674 } 12675 12676 //! Pointwise max operator between two images. 12677 template<typename t> 12678 CImg<T>& max(const CImg<t>& img) { 12679 if (is_overlapped(img)) return max(+img); 12680 t *ptrs = img._data; 12681 T *ptrf = _data + cimg::min(size(),img.size()); 12682 for (T* ptrd = _data; ptrd<ptrf; ++ptrd) *ptrd = cimg::max((T)*(ptrs++),*ptrd); 12683 return *this; 12684 } 12685 12686 template<typename t> 12687 CImg<_cimg_Tt> get_max(const CImg<t>& img) const { 12688 return CImg<_cimg_Tt>(*this,false).max(img); 12689 } 12690 12691 //! Pointwise max operator between an image and a string. 12692 CImg<T>& max(const char *const expression) { 12693 const unsigned int omode = cimg::exception_mode(); 12694 cimg::exception_mode() = 0; 12695 try { 12696 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 12697 _cimg_math_parser mp(base,expression,"max"); 12698 T *ptrd = _data; 12699 cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; } 12700 } catch (CImgException&) { 12701 CImg<T> values(_width,_height,_depth,_spectrum); 12702 try { 12703 values.fill(expression,true); 12704 } catch (CImgException&) { 12705 cimg::exception_mode() = omode; 12706 values.load(expression); 12707 } 12708 max(values); 12709 } 12710 cimg::exception_mode() = omode; 12711 return *this; 12712 } 12713 12714 CImg<Tfloat> get_max(const char *const expression) const { 12715 return CImg<Tfloat>(*this,false).max(expression); 12716 } 12717 12718 //! Return a reference to the minimum pixel value of the instance image 12719 T& min() { 12720 if (is_empty()) 12721 throw CImgInstanceException(_cimg_instance 12722 "min() : Empty instance.", 12723 cimg_instance); 12724 T *ptr_min = _data; 12725 T min_value = *ptr_min; 12726 cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs); 12727 return *ptr_min; 12728 } 12729 12730 const T& min() const { 12731 if (is_empty()) 12732 throw CImgInstanceException(_cimg_instance 12733 "min() : Empty instance.", 12734 cimg_instance); 12735 const T *ptr_min = _data; 12736 T min_value = *ptr_min; 12737 cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs); 12738 return *ptr_min; 12739 } 12740 12741 //! Return a reference to the maximum pixel value of the instance image 12742 T& max() { 12743 if (is_empty()) 12744 throw CImgInstanceException(_cimg_instance 12745 "max() : Empty instance.", 12746 cimg_instance); 12747 T *ptr_max = _data; 12748 T max_value = *ptr_max; 12749 cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); 12750 return *ptr_max; 12751 } 12752 12753 const T& max() const { 12754 if (is_empty()) 12755 throw CImgInstanceException(_cimg_instance 12756 "max() : Empty instance.", 12757 cimg_instance); 12758 const T *ptr_max = _data; 12759 T max_value = *ptr_max; 12760 cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); 12761 return *ptr_max; 12762 } 12763 12764 //! Return a reference to the minimum pixel value and return also the maximum pixel value. 12765 template<typename t> 12766 T& min_max(t& max_val) { 12767 if (is_empty()) 12768 throw CImgInstanceException(_cimg_instance 12769 "min_max() : Empty instance.", 12770 cimg_instance); 12771 T *ptr_min = _data; 12772 T min_value = *ptr_min, max_value = min_value; 12773 cimg_for(*this,ptrs,T) { 12774 const T val = *ptrs; 12775 if (val<min_value) { min_value = val; ptr_min = ptrs; } 12776 if (val>max_value) max_value = val; 12777 } 12778 max_val = (t)max_value; 12779 return *ptr_min; 12780 } 12781 12782 template<typename t> 12783 const T& min_max(t& max_val) const { 12784 if (is_empty()) 12785 throw CImgInstanceException(_cimg_instance 12786 "min_max() : Empty instance.", 12787 cimg_instance); 12788 const T *ptr_min = _data; 12789 T min_value = *ptr_min, max_value = min_value; 12790 cimg_for(*this,ptrs,T) { 12791 const T val = *ptrs; 12792 if (val<min_value) { min_value = val; ptr_min = ptrs; } 12793 if (val>max_value) max_value = val; 12794 } 12795 max_val = (t)max_value; 12796 return *ptr_min; 12797 } 12798 12799 //! Return a reference to the maximum pixel value and return also the minimum pixel value. 12800 template<typename t> 12801 T& max_min(t& min_val) { 12802 if (is_empty()) 12803 throw CImgInstanceException(_cimg_instance 12804 "max_min() : Empty instance.", 12805 cimg_instance); 12806 T *ptr_max = _data; 12807 T max_value = *ptr_max, min_value = max_value; 12808 cimg_for(*this,ptrs,T) { 12809 const T val = *ptrs; 12810 if (val>max_value) { max_value = val; ptr_max = ptrs; } 12811 if (val<min_value) min_value = val; 12812 } 12813 min_val = (t)min_value; 12814 return *ptr_max; 12815 } 12816 12817 template<typename t> 12818 const T& max_min(t& min_val) const { 12819 if (is_empty()) 12820 throw CImgInstanceException(_cimg_instance 12821 "max_min() : Empty instance.", 12822 cimg_instance); 12823 const T *ptr_max = _data; 12824 T max_value = *ptr_max, min_value = max_value; 12825 cimg_for(*this,ptrs,T) { 12826 const T val = *ptrs; 12827 if (val>max_value) { max_value = val; ptr_max = ptrs; } 12828 if (val<min_value) min_value = val; 12829 } 12830 min_val = (t)min_value; 12831 return *ptr_max; 12832 } 12833 12834 //! Return the kth smallest element of the image. 12835 T kth_smallest(const unsigned int k) const { 12836 if (is_empty()) 12837 throw CImgInstanceException(_cimg_instance 12838 "kth_smallest() : Empty instance.", 12839 cimg_instance); 12840 CImg<T> arr(*this); 12841 unsigned int l = 0, ir = size() - 1; 12842 for (;;) { 12843 if (ir<=l+1) { 12844 if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]); 12845 return arr[k]; 12846 } else { 12847 const unsigned int mid = (l + ir)>>1; 12848 cimg::swap(arr[mid],arr[l+1]); 12849 if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); 12850 if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]); 12851 if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]); 12852 unsigned int i = l + 1, j = ir; 12853 const T pivot = arr[l+1]; 12854 for (;;) { 12855 do ++i; while (arr[i]<pivot); 12856 do --j; while (arr[j]>pivot); 12857 if (j<i) break; 12858 cimg::swap(arr[i],arr[j]); 12859 } 12860 arr[l+1] = arr[j]; 12861 arr[j] = pivot; 12862 if (j>=k) ir = j - 1; 12863 if (j<=k) l = i; 12864 } 12865 } 12866 return 0; 12867 } 12868 12869 //! Return the median value of the image. 12870 T median() const { 12871 const unsigned int s = size(); 12872 const T res = kth_smallest(s>>1); 12873 return (s%2)?res:((res+kth_smallest((s>>1)-1))/2); 12874 } 12875 12876 //! Return the sum of all the pixel values in an image. 12877 Tdouble sum() const { 12878 if (is_empty()) 12879 throw CImgInstanceException(_cimg_instance 12880 "sum() : Empty instance.", 12881 cimg_instance); 12882 Tdouble res = 0; 12883 cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs; 12884 return res; 12885 } 12886 12887 //! Return the mean pixel value of the instance image. 12888 Tdouble mean() const { 12889 if (is_empty()) 12890 throw CImgInstanceException(_cimg_instance 12891 "mean() : Empty instance.", 12892 cimg_instance); 12893 Tdouble res = 0; 12894 cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs; 12895 return res/size(); 12896 } 12897 12898 //! Return the variance of the image. 12899 /** 12900 @param variance_method Determines how to calculate the variance 12901 <table border="0"> 12902 <tr><td>0</td> 12903 <td>Second moment: 12904 @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2 12905 = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$ 12906 with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr> 12907 <tr><td>1</td> 12908 <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr> 12909 <tr><td>2</td> 12910 <td>Least median of squares</td></tr> 12911 <tr><td>3</td> 12912 <td>Least trimmed of squares</td></tr> 12913 </table> 12914 */ 12915 Tdouble variance(const unsigned int variance_method=1) const { 12916 Tdouble foo; 12917 return variance_mean(variance_method,foo); 12918 } 12919 12920 //! Return the variance and the mean of the image. 12921 template<typename t> 12922 Tdouble variance_mean(const unsigned int variance_method, t& mean) const { 12923 if (is_empty()) 12924 throw CImgInstanceException(_cimg_instance 12925 "variance() : Empty instance.", 12926 cimg_instance); 12927 12928 Tdouble variance = 0, average = 0; 12929 const unsigned int siz = size(); 12930 switch (variance_method) { 12931 case 0 :{ // Least mean square (standard definition) 12932 Tdouble S = 0, S2 = 0; 12933 cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; } 12934 variance = (S2 - S*S/siz)/siz; 12935 average = S; 12936 } break; 12937 case 1 : { // Least mean square (robust definition) 12938 Tdouble S = 0, S2 = 0; 12939 cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; } 12940 variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; 12941 average = S; 12942 } break; 12943 case 2 : { // Least Median of Squares (MAD) 12944 CImg<Tfloat> buf(*this); 12945 buf.sort(); 12946 const unsigned int siz2 = siz>>1; 12947 const Tdouble med_i = (double)buf[siz2]; 12948 cimg_for(buf,ptrs,Tfloat) { const Tdouble val = (Tdouble)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; } 12949 buf.sort(); 12950 const Tdouble sig = (Tdouble)(1.4828*buf[siz2]); 12951 variance = sig*sig; 12952 } break; 12953 default : { // Least trimmed of Squares 12954 CImg<Tfloat> buf(*this); 12955 const unsigned int siz2 = siz>>1; 12956 cimg_for(buf,ptrs,Tfloat) { const Tdouble val = (Tdouble)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; } 12957 buf.sort(); 12958 Tdouble a = 0; 12959 const Tfloat *ptrs = buf._data; 12960 for (unsigned int j = 0; j<siz2; ++j) a+=(Tdouble)*(ptrs++); 12961 const Tdouble sig = (Tdouble)(2.6477*std::sqrt(a/siz2)); 12962 variance = sig*sig; 12963 } 12964 } 12965 mean = (t)(average/siz); 12966 return variance>0?variance:0; 12967 } 12968 12969 //! Estimate noise variance of the instance image. 12970 Tdouble variance_noise(const unsigned int variance_method=1) const { 12971 const unsigned int siz = size(); 12972 if (!siz || !_data) return 0; 12973 if (variance_method>1) return get_laplacian().variance(variance_method); 12974 Tdouble variance = 0, S = 0, S2 = 0; 12975 if (_depth==1) { 12976 CImg_3x3(I,T); 12977 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) { 12978 const Tdouble val = (Tdouble)Inc + (Tdouble)Ipc + (Tdouble)Icn + (Tdouble)Icp - 4*(Tdouble)Icc; 12979 S+=val; S2+=val*val; 12980 } 12981 } else { 12982 CImg_3x3x3(I,T); 12983 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) { 12984 const Tdouble val = 12985 (Tdouble)Incc + (Tdouble)Ipcc + (Tdouble)Icnc + (Tdouble)Icpc + 12986 (Tdouble)Iccn + (Tdouble)Iccp - 6*(Tdouble)Iccc; 12987 S+=val; S2+=val*val; 12988 } 12989 } 12990 if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; 12991 else variance = (S2 - S*S/siz)/siz; 12992 return variance>0?variance:0; 12993 } 12994 12995 //! Compute the MSE (Mean-Squared Error) between two images. 12996 template<typename t> 12997 Tdouble MSE(const CImg<t>& img) const { 12998 if (img.size()!=size()) 12999 throw CImgArgumentException(_cimg_instance 13000 "MSE() : Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.", 13001 cimg_instance, 13002 img._width,img._height,img._depth,img._spectrum,img._data); 13003 Tdouble vMSE = 0; 13004 const t* ptr2 = img.end(); 13005 cimg_for(*this,ptr1,T) { 13006 const Tdouble diff = (Tdouble)*ptr1 - (Tdouble)*(--ptr2); 13007 vMSE+=diff*diff; 13008 } 13009 vMSE/=img.size(); 13010 return vMSE; 13011 } 13012 13013 //! Compute the PSNR between two images. 13014 template<typename t> 13015 Tdouble PSNR(const CImg<t>& img, const Tdouble valmax=255) const { 13016 const Tdouble vMSE = (Tdouble)std::sqrt(MSE(img)); 13017 return (vMSE!=0)?(Tdouble)(20*std::log10(valmax/vMSE)):(Tdouble)(cimg::type<Tdouble>::max()); 13018 } 13019 13020 //! Evaluate math expression. 13021 /** 13022 If you make successive evaluations on the same image and with the same expression, 13023 you can set 'expr' to 0 after the first call, to skip the math parsing step. 13024 **/ 13025 double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0) const { 13026 static _cimg_math_parser *mp = 0; 13027 if (expression) { if (mp) delete mp; mp = 0; mp = new _cimg_math_parser(*this,expression,"eval"); } 13028 if (!mp) 13029 throw CImgArgumentException(_cimg_instance 13030 "eval() : No expression has been previously specified.", 13031 cimg_instance); 13032 return mp->eval(x,y,z,c); 13033 } 13034 13035 //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,cmin,xmax,ymax,zmax,cmax). 13036 CImg<T>& stats(const unsigned int variance_method=1) { 13037 return get_stats(variance_method).move_to(*this); 13038 } 13039 13040 CImg<Tdouble> get_stats(const unsigned int variance_method=1) const { 13041 if (is_empty()) return CImg<doubleT>(); 13042 const unsigned int siz = size(); 13043 const T *const odata = _data; 13044 const T *pm = odata, *pM = odata; 13045 Tdouble S = 0, S2 = 0; 13046 T m = *pm, M = m; 13047 cimg_for(*this,ptrs,T) { 13048 const T val = *ptrs; 13049 const Tdouble _val = (Tdouble)val; 13050 if (val<m) { m = val; pm = ptrs; } 13051 if (val>M) { M = val; pM = ptrs; } 13052 S+=_val; 13053 S2+=_val*_val; 13054 } 13055 const Tdouble 13056 mean_value = S/siz, 13057 _variance_value = variance_method==0?(S2 - S*S/siz)/siz: 13058 (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0): 13059 variance(variance_method)), 13060 variance_value = _variance_value>0?_variance_value:0; 13061 int 13062 xm = 0, ym = 0, zm = 0, cm = 0, 13063 xM = 0, yM = 0, zM = 0, cM = 0; 13064 contains(*pm,xm,ym,zm,cm); 13065 contains(*pM,xM,yM,zM,cM); 13066 return CImg<Tdouble>(1,12).fill((Tdouble)m,(Tdouble)M,mean_value,variance_value, 13067 (Tdouble)xm,(Tdouble)ym,(Tdouble)zm,(Tdouble)cm, 13068 (Tdouble)xM,(Tdouble)yM,(Tdouble)zM,(Tdouble)cM); 13069 } 13070 13071 //@} 13072 //------------------------------------- 13073 // 13074 //! \name Vector / Matrix Operations 13075 //@{ 13076 //------------------------------------- 13077 13078 //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf). 13079 Tdouble magnitude(const int magnitude_type=2) const { 13080 if (is_empty()) 13081 throw CImgInstanceException(_cimg_instance 13082 "magnitude() : Empty instance.", 13083 cimg_instance); 13084 Tdouble res = 0; 13085 switch (magnitude_type) { 13086 case -1 : { 13087 cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)cimg::abs(*ptrs); if (val>res) res = val; } 13088 } break; 13089 case 1 : { 13090 cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::abs(*ptrs); 13091 } break; 13092 default : { 13093 cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::sqr(*ptrs); 13094 res = (Tdouble)std::sqrt(res); 13095 } 13096 } 13097 return res; 13098 } 13099 13100 //! Return the trace of the image, viewed as a matrix. 13101 Tdouble trace() const { 13102 if (is_empty()) 13103 throw CImgInstanceException(_cimg_instance 13104 "trace() : Empty instance.", 13105 cimg_instance); 13106 Tdouble res = 0; 13107 cimg_forX(*this,k) res+=(Tdouble)(*this)(k,k); 13108 return res; 13109 } 13110 13111 //! Return the determinant of the image, viewed as a matrix. 13112 Tdouble det() const { 13113 if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1) 13114 throw CImgInstanceException(_cimg_instance 13115 "det() : Instance is empty or not a square matrix.", 13116 cimg_instance); 13117 13118 switch (_width) { 13119 case 1 : return (Tdouble)((*this)(0,0)); 13120 case 2 : return (Tdouble)((*this)(0,0))*(Tdouble)((*this)(1,1)) - (Tdouble)((*this)(0,1))*(Tdouble)((*this)(1,0)); 13121 case 3 : { 13122 const Tdouble 13123 a = (Tdouble)_data[0], d = (Tdouble)_data[1], g = (Tdouble)_data[2], 13124 b = (Tdouble)_data[3], e = (Tdouble)_data[4], h = (Tdouble)_data[5], 13125 c = (Tdouble)_data[6], f = (Tdouble)_data[7], i = (Tdouble)_data[8]; 13126 return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e; 13127 } 13128 default : { 13129 CImg<Tfloat> lu(*this); 13130 CImg<uintT> indx; 13131 bool d; 13132 lu._LU(indx,d); 13133 Tdouble res = d?(Tdouble)1:(Tdouble)-1; 13134 cimg_forX(lu,i) res*=lu(i,i); 13135 return res; 13136 } 13137 } 13138 return 0; 13139 } 13140 13141 //! Return the dot product of the current vector/matrix with the vector/matrix \p img. 13142 template<typename t> 13143 Tdouble dot(const CImg<t>& img) const { 13144 if (is_empty()) 13145 throw CImgInstanceException(_cimg_instance 13146 "dot() : Empty instance.", 13147 cimg_instance); 13148 if (!img) 13149 throw CImgArgumentException(_cimg_instance 13150 "dot() : Empty specified image.", 13151 cimg_instance); 13152 13153 const unsigned int nb = cimg::min(size(),img.size()); 13154 Tdouble res = 0; 13155 for (unsigned int off = 0; off<nb; ++off) res+=(Tdouble)_data[off]*(Tdouble)img[off]; 13156 return res; 13157 } 13158 13159 //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image. 13160 CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { 13161 static CImg<T> res; 13162 if (res._height!=_spectrum) res.assign(1,_spectrum); 13163 const unsigned int whd = _width*_height*_depth; 13164 const T *ptrs = data(x,y,z); 13165 T *ptrd = res._data; 13166 cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } 13167 return res; 13168 } 13169 13170 //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image. 13171 CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const { 13172 const int n = (int)std::sqrt((double)_spectrum); 13173 const T *ptrs = data(x,y,z,0); 13174 const unsigned int whd = _width*_height*_depth; 13175 CImg<T> res(n,n); 13176 T *ptrd = res._data; 13177 cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } 13178 return res; 13179 } 13180 13181 //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image. 13182 CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { 13183 const T *ptrs = data(x,y,z,0); 13184 const unsigned int whd = _width*_height*_depth; 13185 if (_spectrum==6) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd),*(ptrs+3*whd),*(ptrs+4*whd),*(ptrs+5*whd)); 13186 if (_spectrum==3) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd)); 13187 return tensor(*ptrs); 13188 } 13189 13190 //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. 13191 template<typename t> 13192 CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) { 13193 if (x<_width && y<_height && z<_depth) { 13194 const t *ptrs = vec._data; 13195 const unsigned int whd = _width*_height*_depth; 13196 T *ptrd = data(x,y,z); 13197 for (unsigned int k = cimg::min((unsigned int)vec.size(),_spectrum); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whd; } 13198 } 13199 return *this; 13200 } 13201 13202 //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. 13203 template<typename t> 13204 CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { 13205 return set_vector_at(mat,x,y,z); 13206 } 13207 13208 //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. 13209 template<typename t> 13210 CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { 13211 T *ptrd = data(x,y,z,0); 13212 const unsigned int siz = _width*_height*_depth; 13213 if (ten._height==2) { 13214 *ptrd = (T)ten[0]; ptrd+=siz; 13215 *ptrd = (T)ten[1]; ptrd+=siz; 13216 *ptrd = (T)ten[3]; 13217 } 13218 else { 13219 *ptrd = (T)ten[0]; ptrd+=siz; 13220 *ptrd = (T)ten[1]; ptrd+=siz; 13221 *ptrd = (T)ten[2]; ptrd+=siz; 13222 *ptrd = (T)ten[4]; ptrd+=siz; 13223 *ptrd = (T)ten[5]; ptrd+=siz; 13224 *ptrd = (T)ten[8]; 13225 } 13226 return *this; 13227 } 13228 13229 //! Unroll all images values into a one-column vector. 13230 CImg<T>& vector() { 13231 return unroll('y'); 13232 } 13233 13234 CImg<T> get_vector() const { 13235 return get_unroll('y'); 13236 } 13237 13238 //! Realign pixel values of the instance image as a square matrix 13239 CImg<T>& matrix() { 13240 const unsigned int siz = size(); 13241 switch (siz) { 13242 case 1 : break; 13243 case 4 : _width = _height = 2; break; 13244 case 9 : _width = _height = 3; break; 13245 case 16 : _width = _height = 4; break; 13246 case 25 : _width = _height = 5; break; 13247 case 36 : _width = _height = 6; break; 13248 case 49 : _width = _height = 7; break; 13249 case 64 : _width = _height = 8; break; 13250 case 81 : _width = _height = 9; break; 13251 case 100 : _width = _height = 10; break; 13252 default : { 13253 unsigned int i = 11, i2 = i*i; 13254 while (i2<siz) { i2+=2*i + 1; ++i; } 13255 if (i2==siz) _width = _height = i; 13256 else throw CImgInstanceException(_cimg_instance 13257 "matrix() : Invalid instance size %u (should be a square integer).", 13258 cimg_instance, 13259 siz); 13260 } 13261 } 13262 return *this; 13263 } 13264 13265 CImg<T> get_matrix() const { 13266 return (+*this).matrix(); 13267 } 13268 13269 //! Realign pixel values of the instance image as a symmetric tensor. 13270 CImg<T>& tensor() { 13271 return get_tensor().move_to(*this); 13272 } 13273 13274 CImg<T> get_tensor() const { 13275 CImg<T> res; 13276 const unsigned int siz = size(); 13277 switch (siz) { 13278 case 1 : break; 13279 case 3 : 13280 res.assign(2,2); 13281 res(0,0) = (*this)(0); 13282 res(1,0) = res(0,1) = (*this)(1); 13283 res(1,1) = (*this)(2); 13284 break; 13285 case 6 : 13286 res.assign(3,3); 13287 res(0,0) = (*this)(0); 13288 res(1,0) = res(0,1) = (*this)(1); 13289 res(2,0) = res(0,2) = (*this)(2); 13290 res(1,1) = (*this)(3); 13291 res(2,1) = res(1,2) = (*this)(4); 13292 res(2,2) = (*this)(5); 13293 break; 13294 default : 13295 throw CImgInstanceException(_cimg_instance 13296 "tensor() : Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).", 13297 cimg_instance); 13298 } 13299 return res; 13300 } 13301 13302 //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image. 13303 CImg<T>& diagonal() { 13304 return get_diagonal().move_to(*this); 13305 } 13306 13307 CImg<T> get_diagonal() const { 13308 if (is_empty()) return *this; 13309 CImg<T> res(size(),size(),1,1,0); 13310 cimg_foroff(*this,off) res(off,off) = (*this)(off); 13311 return res; 13312 } 13313 13314 //! Get an identity matrix having same dimension than instance image. 13315 CImg<T>& identity_matrix() { 13316 return identity_matrix(cimg::max(_width,_height)).move_to(*this); 13317 } 13318 13319 CImg<T> get_identity_matrix() const { 13320 return identity_matrix(cimg::max(_width,_height)); 13321 } 13322 13323 //! Return a N-numbered sequence vector from \p a0 to \p a1. 13324 CImg<T>& sequence(const T a0, const T a1) { 13325 if (is_empty()) return *this; 13326 const unsigned int siz = size() - 1; 13327 T* ptr = _data; 13328 if (siz) { 13329 const Tdouble delta = (Tdouble)a1 - (Tdouble)a0; 13330 cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz); 13331 } else *ptr = a0; 13332 return *this; 13333 } 13334 13335 CImg<T> get_sequence(const T a0, const T a1) const { 13336 return (+*this).sequence(a0,a1); 13337 } 13338 13339 //! Transpose the current matrix. 13340 CImg<T>& transpose() { 13341 if (_width==1) { _width = _height; _height = 1; return *this; } 13342 if (_height==1) { _height = _width; _width = 1; return *this; } 13343 if (_width==_height) { 13344 cimg_forYZC(*this,y,z,c) for (int x = y; x<width(); ++x) cimg::swap((*this)(x,y,z,c),(*this)(y,x,z,c)); 13345 return *this; 13346 } 13347 return get_transpose().move_to(*this); 13348 } 13349 13350 CImg<T> get_transpose() const { 13351 return get_permute_axes("yxzc"); 13352 } 13353 13354 //! Compute the cross product between two 3d vectors. 13355 template<typename t> 13356 CImg<T>& cross(const CImg<t>& img) { 13357 if (_width!=1 || _height<3 || img._width!=1 || img._height<3) 13358 throw CImgInstanceException(_cimg_instance 13359 "cross() : Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.", 13360 cimg_instance, 13361 img._width,img._height,img._depth,img._spectrum,img._data); 13362 13363 const T x = (*this)[0], y = (*this)[1], z = (*this)[2]; 13364 (*this)[0] = (T)(y*img[2] - z*img[1]); 13365 (*this)[1] = (T)(z*img[0] - x*img[2]); 13366 (*this)[2] = (T)(x*img[1] - y*img[0]); 13367 return *this; 13368 } 13369 13370 template<typename t> 13371 CImg<_cimg_Tt> get_cross(const CImg<t>& img) const { 13372 return CImg<_cimg_Tt>(*this).cross(img); 13373 } 13374 13375 //! Invert the current matrix. 13376 CImg<T>& invert(const bool use_LU=true) { 13377 if (_width!=_height || _depth!=1 || _spectrum!=1) 13378 throw CImgInstanceException(_cimg_instance 13379 "invert() : Instance is not a square matrix.", 13380 cimg_instance); 13381 #ifdef cimg_use_lapack 13382 int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N]; 13383 Tfloat 13384 *const lapA = new Tfloat[N*N], 13385 *const WORK = new Tfloat[LWORK]; 13386 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l)); 13387 cimg::getrf(N,lapA,IPIV,INFO); 13388 if (INFO) 13389 cimg::warn(_cimg_instance 13390 "invert() : LAPACK function dgetrf_() returned error code %d.", 13391 cimg_instance, 13392 INFO); 13393 else { 13394 cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO); 13395 if (INFO) 13396 cimg::warn(_cimg_instance 13397 "invert() : LAPACK function dgetri_() returned error code %d.", 13398 cimg_instance, 13399 INFO); 13400 } 13401 if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0); 13402 delete[] IPIV; delete[] lapA; delete[] WORK; 13403 #else 13404 const double dete = _width>3?-1.0:det(); 13405 if (dete!=0.0 && _width==2) { 13406 const double 13407 a = _data[0], c = _data[1], 13408 b = _data[2], d = _data[3]; 13409 _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete); 13410 _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete); 13411 } else if (dete!=0.0 && _width==3) { 13412 const double 13413 a = _data[0], d = _data[1], g = _data[2], 13414 b = _data[3], e = _data[4], h = _data[5], 13415 c = _data[6], f = _data[7], i = _data[8]; 13416 _data[0] = (T)((i*e-f*h)/dete), _data[1] = (T)((g*f-i*d)/dete), _data[2] = (T)((d*h-g*e)/dete); 13417 _data[3] = (T)((h*c-i*b)/dete), _data[4] = (T)((i*a-c*g)/dete), _data[5] = (T)((g*b-a*h)/dete); 13418 _data[6] = (T)((b*f-e*c)/dete), _data[7] = (T)((d*c-a*f)/dete), _data[8] = (T)((a*e-d*b)/dete); 13419 } else { 13420 if (use_LU) { // LU-based inverse computation 13421 CImg<Tfloat> A(*this), indx, col(1,_width); 13422 bool d; 13423 A._LU(indx,d); 13424 cimg_forX(*this,j) { 13425 col.fill(0); 13426 col(j) = 1; 13427 col._solve(A,indx); 13428 cimg_forX(*this,i) (*this)(j,i) = (T)col(i); 13429 } 13430 } else { // SVD-based inverse computation 13431 CImg<Tfloat> U(_width,_width), S(1,_width), V(_width,_width); 13432 SVD(U,S,V,false); 13433 U.transpose(); 13434 cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k]; 13435 S.diagonal(); 13436 *this = V*S*U; 13437 } 13438 } 13439 #endif 13440 return *this; 13441 } 13442 13443 CImg<Tfloat> get_invert(const bool use_LU=true) const { 13444 return CImg<Tfloat>(*this,false).invert(use_LU); 13445 } 13446 13447 //! Compute the pseudo-inverse (Moore-Penrose) of the matrix. 13448 CImg<T>& pseudoinvert() { 13449 return get_pseudoinvert().move_to(*this); 13450 } 13451 13452 CImg<Tfloat> get_pseudoinvert() const { 13453 CImg<Tfloat> U, S, V; 13454 SVD(U,S,V); 13455 cimg_forX(V,x) { 13456 const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0; 13457 cimg_forY(V,y) V(x,y)*=invs; 13458 } 13459 return V*U.transpose(); 13460 } 13461 13462 //! Solve a linear system AX=B where B=*this. 13463 template<typename t> 13464 CImg<T>& solve(const CImg<t>& A) { 13465 if (_width!=1 || _depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1) 13466 throw CImgArgumentException(_cimg_instance 13467 "solve() : Instance and specified matrix (%u,%u,%u,%u,%p) have incompatible dimensions.", 13468 cimg_instance, 13469 A._width,A._height,A._depth,A._spectrum,A._data); 13470 13471 typedef _cimg_Ttfloat Ttfloat; 13472 if (A._width==A._height) { 13473 #ifdef cimg_use_lapack 13474 char TRANS='N'; 13475 int INFO, N = _height, LWORK = 4*N, one = 1, *const IPIV = new int[N]; 13476 Ttfloat 13477 *const lapA = new Ttfloat[N*N], 13478 *const lapB = new Ttfloat[N], 13479 *const WORK = new Ttfloat[LWORK]; 13480 cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l)); 13481 cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i)); 13482 cimg::getrf(N,lapA,IPIV,INFO); 13483 if (INFO) 13484 cimg::warn(_cimg_instance 13485 "solve() : LAPACK library function dgetrf_() returned error code %d.", 13486 cimg_instance, 13487 INFO); 13488 13489 if (!INFO) { 13490 cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO); 13491 if (INFO) 13492 cimg::warn(_cimg_instance 13493 "solve() : LAPACK library function dgetrs_() returned error code %d.", 13494 cimg_instance, 13495 INFO); 13496 } 13497 if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0); 13498 delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK; 13499 #else 13500 CImg<Ttfloat> lu(A); 13501 CImg<Ttfloat> indx; 13502 bool d; 13503 lu._LU(indx,d); 13504 _solve(lu,indx); 13505 #endif 13506 } else assign(A.get_pseudoinvert()*(*this)); 13507 return *this; 13508 } 13509 13510 template<typename t> 13511 CImg<_cimg_Ttfloat> get_solve(const CImg<t>& A) const { 13512 return CImg<_cimg_Ttfloat>(*this,false).solve(A); 13513 } 13514 13515 template<typename t, typename ti> 13516 CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) { 13517 typedef _cimg_Ttfloat Ttfloat; 13518 const int N = size(); 13519 int ii = -1; 13520 Ttfloat sum; 13521 for (int i = 0; i<N; ++i) { 13522 const int ip = (int)indx[i]; 13523 Ttfloat sum = (*this)(ip); 13524 (*this)(ip) = (*this)(i); 13525 if (ii>=0) for (int j = ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j); 13526 else if (sum!=0) ii=i; 13527 (*this)(i) = (T)sum; 13528 } 13529 for (int i = N-1; i>=0; --i) { 13530 sum = (*this)(i); 13531 for (int j = i+1; j<N; ++j) sum-=A(j,i)*(*this)(j); 13532 (*this)(i) = (T)(sum/A(i,i)); 13533 } 13534 return *this; 13535 } 13536 13537 //! Solve a linear system AX=B where B=*this and A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ]. 13538 // (Use the Thomas Algorithm). 13539 template<typename t> 13540 CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) { 13541 const int siz = (int)size(); 13542 if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz) 13543 throw CImgArgumentException(_cimg_instance 13544 "solve_tridiagonal() : Instance and tridiagonal coefficients " 13545 "(%u,%u,%u,%u,%p), (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) have incompatible dimensions.", 13546 cimg_instance, 13547 a._width,a._height,a._depth,a._spectrum,a._data, 13548 b._width,b._height,b._depth,b._spectrum,b._data, 13549 c._width,c._height,c._depth,c._spectrum,c._data); 13550 13551 typedef _cimg_Ttfloat Ttfloat; 13552 CImg<Ttfloat> nc(siz); 13553 const T *ptra = a._data, *ptrb = b._data, *ptrc = c._data; 13554 T *ptrnc = nc._data, *ptrd = _data; 13555 const Ttfloat valb0 = (Ttfloat)*(ptrb++); 13556 *ptrnc = *(ptrc++)/valb0; 13557 Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0); 13558 for (int i = 1; i<siz; ++i) { 13559 const Ttfloat 13560 vala = (Tfloat)*(ptra++), 13561 id = 1/(*(ptrb++) - *(ptrnc++)*vala); 13562 *ptrnc = *(ptrc++)*id; 13563 vald = ((*ptrd-=vala*vald)*=id); 13564 ++ptrd; 13565 } 13566 vald = *(--ptrd); 13567 for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald); 13568 return *this; 13569 } 13570 13571 template<typename t> 13572 CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const { 13573 return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(a,b,c); 13574 } 13575 13576 //! Compute the eigenvalues and eigenvectors of a matrix. 13577 template<typename t> 13578 const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const { 13579 if (is_empty()) { val.assign(); vec.assign(); } 13580 else { 13581 if (_width!=_height || _depth>1 || _spectrum>1) 13582 throw CImgInstanceException(_cimg_instance 13583 "eigen() : Instance is not a square matrix.", 13584 cimg_instance); 13585 13586 if (val.size()<_width) val.assign(1,_width); 13587 if (vec.size()<_width*_width) vec.assign(_width,_width); 13588 switch (_width) { 13589 case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break; 13590 case 2 : { 13591 const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d; 13592 double f = e*e - 4*(a*d - b*c); 13593 if (f<0) 13594 cimg::warn(_cimg_instance 13595 "CImg<%s>::eigen() : Complex eigenvalues found.", 13596 cimg_instance); 13597 13598 f = std::sqrt(f); 13599 const double l1 = 0.5*(e-f), l2 = 0.5*(e+f); 13600 const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b); 13601 val[0]=(t)l2; 13602 val[1]=(t)l1; 13603 vec(0,0) = (t)std::cos(theta1); 13604 vec(0,1) = (t)std::sin(theta1); 13605 vec(1,0) = (t)std::cos(theta2); 13606 vec(1,1) = (t)std::sin(theta2); 13607 } break; 13608 default : 13609 throw CImgInstanceException(_cimg_instance 13610 "eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices.", 13611 cimg_instance); 13612 } 13613 } 13614 return *this; 13615 } 13616 13617 CImgList<Tfloat> get_eigen() const { 13618 CImgList<Tfloat> res(2); 13619 eigen(res[0],res[1]); 13620 return res; 13621 } 13622 13623 //! Compute the eigenvalues and eigenvectors of a symmetric matrix. 13624 template<typename t> 13625 const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const { 13626 if (is_empty()) { val.assign(); vec.assign(); } 13627 else { 13628 #ifdef cimg_use_lapack 13629 char JOB = 'V', UPLO = 'U'; 13630 int N = _width, LWORK = 4*N, INFO; 13631 Tfloat 13632 *const lapA = new Tfloat[N*N], 13633 *const lapW = new Tfloat[N], 13634 *const WORK = new Tfloat[LWORK]; 13635 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l)); 13636 cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO); 13637 if (INFO) 13638 cimg::warn(_cimg_instance 13639 "symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.", 13640 cimg_instance, 13641 INFO); 13642 13643 val.assign(1,N); 13644 vec.assign(N,N); 13645 if (!INFO) { 13646 cimg_forY(val,i) val(i) = (T)lapW[N-1-i]; 13647 cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]); 13648 } else { val.fill(0); vec.fill(0); } 13649 delete[] lapA; delete[] lapW; delete[] WORK; 13650 #else 13651 if (_width!=_height || _depth>1 || _spectrum>1) 13652 throw CImgInstanceException(_cimg_instance 13653 "eigen() : Instance is not a square matrix.", 13654 cimg_instance); 13655 13656 val.assign(1,_width); 13657 if (vec._data) vec.assign(_width,_width); 13658 if (_width<3) return eigen(val,vec); 13659 CImg<t> V(_width,_width); 13660 SVD(vec,val,V,false); 13661 bool ambiguous = false; 13662 float eig = 0; 13663 cimg_forY(val,p) { // check for ambiguous cases. 13664 if (val[p]>eig) eig = (float)val[p]; 13665 t scal = 0; 13666 cimg_forY(vec,y) scal+=vec(p,y)*V(p,y); 13667 if (cimg::abs(scal)<0.9f) ambiguous = true; 13668 if (scal<0) val[p] = -val[p]; 13669 } 13670 if (ambiguous) { 13671 ++(eig*=2); 13672 SVD(vec,val,V,false,40,eig); 13673 val-=eig; 13674 } 13675 CImg<intT> permutations(_width); // sort eigenvalues in decreasing order 13676 CImg<t> tmp(_width); 13677 val.sort(permutations,false); 13678 cimg_forY(vec,k) { 13679 cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k); 13680 std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width); 13681 } 13682 #endif 13683 } 13684 return *this; 13685 } 13686 13687 CImgList<Tfloat> get_symmetric_eigen() const { 13688 CImgList<Tfloat> res(2); 13689 symmetric_eigen(res[0],res[1]); 13690 return res; 13691 } 13692 13693 //! Sort values of a vector and get permutations. 13694 template<typename t> 13695 CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) { 13696 if (is_empty()) permutations.assign(); 13697 else { 13698 if (permutations.size()!=size()) permutations.assign(size()); 13699 cimg_foroff(permutations,off) permutations[off] = (t)off; 13700 _quicksort(0,size()-1,permutations,increasing); 13701 } 13702 return *this; 13703 } 13704 13705 template<typename t> 13706 CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const { 13707 return (+*this).sort(permutations,increasing); 13708 } 13709 13710 //! Sort image values. 13711 CImg<T>& sort(const bool increasing=true) { 13712 CImg<T> foo; 13713 return sort(foo,increasing); 13714 } 13715 13716 CImg<T> get_sort(const bool increasing=true) const { 13717 return (+*this).sort(increasing); 13718 } 13719 13720 template<typename t> 13721 CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) { 13722 if (min<max) { 13723 const int mid = (min+max)/2; 13724 if (increasing) { 13725 if ((*this)[min]>(*this)[mid]) { 13726 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } 13727 if ((*this)[mid]>(*this)[max]) { 13728 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } 13729 if ((*this)[min]>(*this)[mid]) { 13730 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } 13731 } else { 13732 if ((*this)[min]<(*this)[mid]) { 13733 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } 13734 if ((*this)[mid]<(*this)[max]) { 13735 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } 13736 if ((*this)[min]<(*this)[mid]) { 13737 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } 13738 } 13739 if (max-min>=3) { 13740 const T pivot = (*this)[mid]; 13741 int i = min, j = max; 13742 if (increasing) { 13743 do { 13744 while ((*this)[i]<pivot) ++i; 13745 while ((*this)[j]>pivot) --j; 13746 if (i<=j) { 13747 cimg::swap((*this)[i],(*this)[j]); 13748 cimg::swap(permutations[i++],permutations[j--]); 13749 } 13750 } while (i<=j); 13751 } else { 13752 do { 13753 while ((*this)[i]>pivot) ++i; 13754 while ((*this)[j]<pivot) --j; 13755 if (i<=j) { 13756 cimg::swap((*this)[i],(*this)[j]); 13757 cimg::swap(permutations[i++],permutations[j--]); 13758 } 13759 } while (i<=j); 13760 } 13761 if (min<j) _quicksort(min,j,permutations,increasing); 13762 if (i<max) _quicksort(i,max,permutations,increasing); 13763 } 13764 } 13765 return *this; 13766 } 13767 13768 //! Compute the SVD of a general matrix. 13769 template<typename t> 13770 const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V, const bool sorting=true, 13771 const unsigned int max_iteration=40, const float lambda=0) const { 13772 if (is_empty()) { U.assign(); S.assign(); V.assign(); } 13773 else { 13774 U = *this; 13775 if (lambda!=0) { 13776 const unsigned int delta = cimg::min(U._width,U._height); 13777 for (unsigned int i = 0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda); 13778 } 13779 if (S.size()<_width) S.assign(1,_width); 13780 if (V._width<_width || V._height<_height) V.assign(_width,_width); 13781 CImg<t> rv1(_width); 13782 t anorm = 0, c, f, g = 0, h, s, scale = 0; 13783 int l = 0, nm = 0; 13784 13785 cimg_forX(U,i) { 13786 l = i+1; rv1[i] = scale*g; g = s = scale = 0; 13787 if (i<height()) { 13788 for (int k = i; k<height(); ++k) scale+= cimg::abs(U(i,k)); 13789 if (scale) { 13790 for (int k = i; k<height(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); } 13791 f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g; 13792 for (int j = l; j<width(); ++j) { 13793 s = 0; 13794 for (int k=i; k<height(); ++k) s+= U(i,k)*U(j,k); 13795 f = s/h; 13796 for (int k = i; k<height(); ++k) U(j,k)+= f*U(i,k); 13797 } 13798 for (int k = i; k<height(); ++k) U(i,k)*= scale; 13799 } 13800 } 13801 S[i]=scale*g; 13802 13803 g = s = scale = 0; 13804 if (i<height() && i!=width()-1) { 13805 for (int k = l; k<width(); ++k) scale+=cimg::abs(U(k,i)); 13806 if (scale) { 13807 for (int k = l; k<width(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); } 13808 f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; 13809 for (int k = l; k<width(); ++k) rv1[k]=U(k,i)/h; 13810 for (int j = l; j<height(); ++j) { 13811 s = 0; 13812 for (int k = l; k<width(); ++k) s+= U(k,j)*U(k,i); 13813 for (int k = l; k<width(); ++k) U(k,j)+= s*rv1[k]; 13814 } 13815 for (int k = l; k<width(); ++k) U(k,i)*= scale; 13816 } 13817 } 13818 anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i]))); 13819 } 13820 13821 for (int i = width()-1; i>=0; --i) { 13822 if (i<width()-1) { 13823 if (g) { 13824 for (int j = l; j<width(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; 13825 for (int j = l; j<width(); ++j) { 13826 s = 0; 13827 for (int k = l; k<width(); ++k) s+= U(k,i)*V(j,k); 13828 for (int k = l; k<width(); ++k) V(j,k)+= s*V(i,k); 13829 } 13830 } 13831 for (int j = l; j<width(); ++j) V(j,i) = V(i,j) = (t)0.0; 13832 } 13833 V(i,i) = (t)1.0; g = rv1[i]; l = i; 13834 } 13835 13836 for (int i = cimg::min(width(),height())-1; i>=0; --i) { 13837 l = i+1; g = S[i]; 13838 for (int j = l; j<width(); ++j) U(j,i) = 0; 13839 if (g) { 13840 g = 1/g; 13841 for (int j = l; j<width(); ++j) { 13842 s = 0; for (int k = l; k<height(); ++k) s+= U(i,k)*U(j,k); 13843 f = (s/U(i,i))*g; 13844 for (int k = i; k<height(); ++k) U(j,k)+= f*U(i,k); 13845 } 13846 for (int j = i; j<height(); ++j) U(i,j)*= g; 13847 } else for (int j = i; j<height(); ++j) U(i,j) = 0; 13848 ++U(i,i); 13849 } 13850 13851 for (int k = width()-1; k>=0; --k) { 13852 for (unsigned int its = 0; its<max_iteration; ++its) { 13853 bool flag = true; 13854 for (l = k; l>=1; --l) { 13855 nm = l-1; 13856 if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; } 13857 if ((cimg::abs(S[nm])+anorm)==anorm) break; 13858 } 13859 if (flag) { 13860 c = 0; s = 1; 13861 for (int i = l; i<=k; ++i) { 13862 f = s*rv1[i]; rv1[i] = c*rv1[i]; 13863 if ((cimg::abs(f)+anorm)==anorm) break; 13864 g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h; 13865 cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; } 13866 } 13867 } 13868 const t z = S[k]; 13869 if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; } 13870 nm = k-1; 13871 t x = S[l], y = S[nm]; 13872 g = rv1[nm]; h = rv1[k]; 13873 f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y); 13874 g = (t)cimg::_pythagore(f,1.0); 13875 f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x; 13876 c = s = 1; 13877 for (int j = l; j<=nm; ++j) { 13878 const int i = j+1; 13879 g = rv1[i]; h = s*g; g = c*g; 13880 t y = S[i]; 13881 t z = (t)cimg::_pythagore(f,h); 13882 rv1[j] = z; c = f/z; s = h/z; 13883 f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c; 13884 cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; } 13885 z = (t)cimg::_pythagore(f,h); S[j] = z; 13886 if (z) { z = 1/z; c = f*z; s = h*z; } 13887 f = c*g+s*y; x = c*y-s*g; 13888 cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; } 13889 } 13890 rv1[l] = 0; rv1[k]=f; S[k]=x; 13891 } 13892 } 13893 13894 if (sorting) { 13895 CImg<intT> permutations(_width); 13896 CImg<t> tmp(_width); 13897 S.sort(permutations,false); 13898 cimg_forY(U,k) { 13899 cimg_forX(permutations,x) tmp(x) = U(permutations(x),k); 13900 std::memcpy(U.data(0,k),tmp._data,sizeof(t)*_width); 13901 } 13902 cimg_forY(V,k) { 13903 cimg_forX(permutations,x) tmp(x) = V(permutations(x),k); 13904 std::memcpy(V.data(0,k),tmp._data,sizeof(t)*_width); 13905 } 13906 } 13907 } 13908 return *this; 13909 } 13910 13911 CImgList<Tfloat> get_SVD(const bool sorting=true, 13912 const unsigned int max_iteration=40, const float lambda=0) const { 13913 CImgList<Tfloat> res(3); 13914 SVD(res[0],res[1],res[2],sorting,max_iteration,lambda); 13915 return res; 13916 } 13917 13918 // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies) 13919 template<typename t> 13920 CImg<T>& _LU(CImg<t>& indx, bool& d) { 13921 const int N = width(); 13922 int imax = 0; 13923 CImg<Tfloat> vv(N); 13924 indx.assign(N); 13925 d = true; 13926 cimg_forX(*this,i) { 13927 Tfloat vmax = 0; 13928 cimg_forX(*this,j) { 13929 const Tfloat tmp = cimg::abs((*this)(j,i)); 13930 if (tmp>vmax) vmax = tmp; 13931 } 13932 if (vmax==0) { indx.fill(0); return fill(0); } 13933 vv[i] = 1/vmax; 13934 } 13935 cimg_forX(*this,j) { 13936 for (int i = 0; i<j; ++i) { 13937 Tfloat sum=(*this)(j,i); 13938 for (int k = 0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k); 13939 (*this)(j,i) = (T)sum; 13940 } 13941 Tfloat vmax = 0; 13942 for (int i = j; i<width(); ++i) { 13943 Tfloat sum=(*this)(j,i); 13944 for (int k = 0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k); 13945 (*this)(j,i) = (T)sum; 13946 const Tfloat tmp = vv[i]*cimg::abs(sum); 13947 if (tmp>=vmax) { vmax=tmp; imax=i; } 13948 } 13949 if (j!=imax) { 13950 cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j)); 13951 d =!d; 13952 vv[imax] = vv[j]; 13953 } 13954 indx[j] = (t)imax; 13955 if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20; 13956 if (j<N) { 13957 const Tfloat tmp = 1/(Tfloat)(*this)(j,j); 13958 for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp); 13959 } 13960 } 13961 return *this; 13962 } 13963 13964 //! Compute minimal path in a graph, using the Dijkstra algorithm. 13965 /** 13966 \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j). 13967 \param nb_nodes Number of graph nodes. 13968 \param starting_node Indice of the starting node. 13969 \param ending_node Indice of the ending node (set to ~0U to ignore ending node). 13970 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter). 13971 \return Array of distances of each node to the starting node. 13972 **/ 13973 template<typename tf, typename t> 13974 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes, 13975 const unsigned int starting_node, const unsigned int ending_node, 13976 CImg<t>& previous) { 13977 13978 CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max()); 13979 dist(starting_node) = 0; 13980 previous.assign(1,nb_nodes,1,1,(t)-1); 13981 previous(starting_node) = (t)starting_node; 13982 CImg<uintT> Q(nb_nodes); 13983 cimg_forX(Q,u) Q(u) = u; 13984 cimg::swap(Q(starting_node),Q(0)); 13985 unsigned int sizeQ = nb_nodes; 13986 while (sizeQ) { 13987 // Update neighbors from minimal vertex 13988 const unsigned int umin = Q(0); 13989 if (umin==ending_node) sizeQ = 0; 13990 else { 13991 const T dmin = dist(umin); 13992 const T infty = cimg::type<T>::max(); 13993 for (unsigned int q = 1; q<sizeQ; ++q) { 13994 const unsigned int v = Q(q); 13995 const T d = (T)distance(v,umin); 13996 if (d<infty) { 13997 const T alt = dmin + d; 13998 if (alt<dist(v)) { 13999 dist(v) = alt; 14000 previous(v) = (t)umin; 14001 const T distpos = dist(Q(q)); 14002 for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par)); 14003 } 14004 } 14005 } 14006 // Remove minimal vertex from queue 14007 Q(0) = Q(--sizeQ); 14008 const T distpos = dist(Q(0)); 14009 for (unsigned int pos = 0, left = 0, right = 0; 14010 ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) { 14011 if (right<sizeQ) { 14012 if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; } 14013 else { cimg::swap(Q(pos),Q(right)); pos = right; } 14014 } else { cimg::swap(Q(pos),Q(left)); pos = left; } 14015 } 14016 } 14017 } 14018 return dist; 14019 } 14020 14021 //! Return minimal path in a graph, using the Dijkstra algorithm. 14022 template<typename tf, typename t> 14023 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes, 14024 const unsigned int starting_node, const unsigned int ending_node=~0U) { 14025 CImg<uintT> foo; 14026 return dijkstra(distance,nb_nodes,starting_node,ending_node,foo); 14027 } 14028 14029 //! Return minimal path in a graph, using the Dijkstra algorithm. 14030 /** 14031 Instance image corresponds to the adjacency matrix of the graph. 14032 \param starting_node Indice of the starting node. 14033 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter). 14034 \return Array of distances of each node to the starting node. 14035 **/ 14036 template<typename t> 14037 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) { 14038 return get_dijkstra(starting_node,ending_node,previous).move_to(*this); 14039 } 14040 14041 template<typename t> 14042 CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const { 14043 if (_width!=_height || _depth!=1 || _spectrum!=1) 14044 throw CImgInstanceException(_cimg_instance 14045 "dijkstra() : Instance is not a graph adjacency matrix.", 14046 cimg_instance); 14047 14048 return dijkstra(*this,_width,starting_node,ending_node,previous); 14049 } 14050 14051 //! Return minimal path in a graph, using the Dijkstra algorithm. 14052 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) { 14053 return get_dijkstra(starting_node,ending_node).move_to(*this); 14054 } 14055 14056 CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const { 14057 CImg<uintT> foo; 14058 return get_dijkstra(starting_node,ending_node,foo); 14059 } 14060 14061 //! Return stream line of a 2d or 3d vector field. 14062 CImg<floatT> get_streamline(const float x, const float y, const float z, 14063 const float L=256, const float dl=0.1f, 14064 const unsigned int interpolation_type=2, const bool is_backward_tracking=false, 14065 const bool is_oriented_only=false) const { 14066 if (_spectrum!=2 && _spectrum!=3) 14067 throw CImgInstanceException(_cimg_instance 14068 "streamline() : Instance is not a 2d or 3d vector field.", 14069 cimg_instance); 14070 if (_spectrum==2) { 14071 if (is_oriented_only) { 14072 typename CImg<T>::_functor4d_streamline2d_oriented func(*this); 14073 return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,0,0,0,_width-1.0f,_height-1.0f,0.0f); 14074 } else { 14075 typename CImg<T>::_functor4d_streamline2d_directed func(*this); 14076 return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,0,0,0,_width-1.0f,_height-1.0f,0.0f); 14077 } 14078 } 14079 if (is_oriented_only) { 14080 typename CImg<T>::_functor4d_streamline3d_oriented func(*this); 14081 return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f); 14082 } 14083 typename CImg<T>::_functor4d_streamline3d_directed func(*this); 14084 return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f); 14085 } 14086 14087 //! Return stream line of a 3d vector field. 14088 /** 14089 \param interpolation_type Type of interpolation (can be 0=nearest int, 1=linear, 2=2nd-order RK, 3=4th-order RK. 14090 14091 **/ 14092 template<typename tfunc> 14093 static CImg<floatT> streamline(const tfunc& func, 14094 const float x, const float y, const float z, 14095 const float L=256, const float dl=0.1f, 14096 const unsigned int interpolation_type=2, const bool is_backward_tracking=false, 14097 const bool is_oriented_only=false, 14098 const float x0=0, const float y0=0, const float z0=0, 14099 const float x1=0, const float y1=0, const float z1=0) { 14100 if (dl<=0) 14101 throw CImgArgumentException("CImg<%s>::streamline() : Invalid specified integration length %g " 14102 "(should be >0).", 14103 pixel_type(), 14104 dl); 14105 14106 const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1); 14107 if (L<=0 || (is_bounded && (x<x0 || x>x1 || y<y0 || y>y1 || z<z0 || z>z1))) return CImg<floatT>(); 14108 const unsigned int size_L = (unsigned int)cimg::round(L/dl+1,1); 14109 CImg<floatT> coordinates(size_L,3); 14110 const float dl2 = dl/2; 14111 float 14112 *ptr_x = coordinates.data(0,0), 14113 *ptr_y = coordinates.data(0,1), 14114 *ptr_z = coordinates.data(0,2), 14115 pu = (float)(dl*func(x,y,z,0)), 14116 pv = (float)(dl*func(x,y,z,1)), 14117 pw = (float)(dl*func(x,y,z,2)), 14118 X = x, Y = y, Z = z; 14119 14120 switch (interpolation_type) { 14121 case 0 : { // Nearest integer interpolation. 14122 cimg_forX(coordinates,l) { 14123 *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; 14124 const int 14125 xi = (int)(X>0?X+0.5f:X-0.5f), 14126 yi = (int)(Y>0?Y+0.5f:Y-0.5f), 14127 zi = (int)(Z>0?Z+0.5f:Z-0.5f); 14128 float 14129 u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)), 14130 v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)), 14131 w = (float)(dl*func((float)xi,(float)yi,(float)zi,2)); 14132 if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } 14133 if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } 14134 if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break; 14135 } 14136 } break; 14137 case 1 : { // First-order interpolation. 14138 cimg_forX(coordinates,l) { 14139 *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; 14140 float 14141 u = (float)(dl*func(X,Y,Z,0)), 14142 v = (float)(dl*func(X,Y,Z,1)), 14143 w = (float)(dl*func(X,Y,Z,2)); 14144 if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } 14145 if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } 14146 if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break; 14147 } 14148 } break; 14149 case 2 : { // Second order interpolation. 14150 cimg_forX(coordinates,l) { 14151 *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; 14152 float 14153 u0 = (float)(dl2*func(X,Y,Z,0)), 14154 v0 = (float)(dl2*func(X,Y,Z,1)), 14155 w0 = (float)(dl2*func(X,Y,Z,2)); 14156 if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } 14157 float 14158 u = (float)(dl*func(X+u0,Y+v0,Z+w0,0)), 14159 v = (float)(dl*func(X+u0,Y+v0,Z+w0,1)), 14160 w = (float)(dl*func(X+u0,Y+v0,Z+w0,2)); 14161 if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } 14162 if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } 14163 if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break; 14164 } 14165 } break; 14166 default : { // Fourth order interpolation. 14167 cimg_forX(coordinates,x) { 14168 *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; 14169 float 14170 u0 = (float)(dl2*func(X,Y,Z,0)), 14171 v0 = (float)(dl2*func(X,Y,Z,1)), 14172 w0 = (float)(dl2*func(X,Y,Z,2)); 14173 if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } 14174 float 14175 u1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,0)), 14176 v1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,1)), 14177 w1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,2)); 14178 if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; } 14179 float 14180 u2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,0)), 14181 v2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,1)), 14182 w2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,2)); 14183 if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; } 14184 float 14185 u3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,0)), 14186 v3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,1)), 14187 w3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,2)); 14188 if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; } 14189 const float 14190 u = (u0 + u3)/3 + (u1 + u2)/1.5f, 14191 v = (v0 + v3)/3 + (v1 + v2)/1.5f, 14192 w = (w0 + w3)/3 + (w1 + w2)/1.5f; 14193 if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } 14194 if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break; 14195 } 14196 } 14197 } 14198 if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0); 14199 return coordinates; 14200 } 14201 14202 //! Return stream line of a vector field. 14203 static CImg<floatT> streamline(const char *const expression, 14204 const float x, const float y, const float z, 14205 const float L=256, const float dl=0.1f, 14206 const unsigned int interpolation_type=2, const bool is_backward_tracking=true, 14207 const bool is_oriented_only=false, 14208 const float x0=0, const float y0=0, const float z0=0, 14209 const float x1=0, const float y1=0, const float z1=0) { 14210 _functor4d_streamline_expr func(expression); 14211 return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1); 14212 } 14213 14214 struct _functor4d_streamline2d_directed { 14215 const CImg<T>& ref; 14216 _functor4d_streamline2d_directed(const CImg<T>& pref):ref(pref) {} 14217 float operator()(const float x, const float y, const float z, const unsigned int c) const { 14218 return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0; 14219 } 14220 }; 14221 14222 struct _functor4d_streamline3d_directed { 14223 const CImg<T>& ref; 14224 _functor4d_streamline3d_directed(const CImg<T>& pref):ref(pref) {} 14225 float operator()(const float x, const float y, const float z, const unsigned int c) const { 14226 return (float)ref._linear_atXYZ(x,y,z,c); 14227 } 14228 }; 14229 14230 struct _functor4d_streamline2d_oriented { 14231 const CImg<T>& ref; 14232 CImg<floatT> *pI; 14233 _functor4d_streamline2d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,1,2); } 14234 ~_functor4d_streamline2d_oriented() { if (pI) delete pI; } 14235 float operator()(const float x, const float y, const float z, const unsigned int c) const { 14236 #define _cimg_vecalign2d(i,j) if (I(i,j,0)*I(0,0,0)+I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); } 14237 int 14238 xi = (int)x - (x>=0?0:1), nxi = xi + 1, 14239 yi = (int)y - (y>=0?0:1), nyi = yi + 1, 14240 zi = (int)z; 14241 const float 14242 dx = x - xi, 14243 dy = y - yi; 14244 if (c==0) { 14245 CImg<floatT>& I = *pI; 14246 if (xi<0) xi = 0; if (nxi<0) nxi = 0; 14247 if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1; 14248 if (yi<0) yi = 0; if (nyi<0) nyi = 0; 14249 if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1; 14250 I(0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,1) = (float)ref(xi,yi,zi,1); 14251 I(1,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,1) = (float)ref(nxi,yi,zi,1); 14252 I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1); 14253 I(0,1,0) = (float)ref(xi,nyi,zi,0); I(0,1,1) = (float)ref(xi,nyi,zi,1); 14254 _cimg_vecalign2d(1,0); _cimg_vecalign2d(1,1); _cimg_vecalign2d(0,1); 14255 } 14256 return c<2?(float)pI->_linear_atXY(dx,dy,0,c):0; 14257 } 14258 }; 14259 14260 struct _functor4d_streamline3d_oriented { 14261 const CImg<T>& ref; 14262 CImg<floatT> *pI; 14263 _functor4d_streamline3d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,2,3); } 14264 ~_functor4d_streamline3d_oriented() { if (pI) delete pI; } 14265 float operator()(const float x, const float y, const float z, const unsigned int c) const { 14266 #define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0)+I(i,j,k,1)*I(0,0,0,1)+I(i,j,k,2)*I(0,0,0,2)<0) { \ 14267 I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); } 14268 int 14269 xi = (int)x - (x>=0?0:1), nxi = xi + 1, 14270 yi = (int)y - (y>=0?0:1), nyi = yi + 1, 14271 zi = (int)z - (z>=0?0:1), nzi = zi + 1; 14272 const float 14273 dx = x - xi, 14274 dy = y - yi, 14275 dz = z - zi; 14276 if (c==0) { 14277 CImg<floatT>& I = *pI; 14278 if (xi<0) xi = 0; if (nxi<0) nxi = 0; 14279 if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1; 14280 if (yi<0) yi = 0; if (nyi<0) nyi = 0; 14281 if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1; 14282 if (zi<0) zi = 0; if (nzi<0) nzi = 0; 14283 if (zi>=ref.depth()) zi = ref.depth()-1; if (nzi>=ref.depth()) nzi = ref.depth()-1; 14284 I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1); I(0,0,0,2) = (float)ref(xi,yi,zi,2); 14285 I(1,0,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2); 14286 I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1); I(1,1,0,2) = (float)ref(nxi,nyi,zi,2); 14287 I(0,1,0,0) = (float)ref(xi,nyi,zi,0); I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,yi,zi,2); 14288 I(0,0,0,1) = (float)ref(xi,yi,nzi,0); I(0,0,0,1) = (float)ref(xi,yi,nzi,1); I(0,0,0,2) = (float)ref(xi,yi,nzi,2); 14289 I(1,0,0,1) = (float)ref(nxi,yi,nzi,0); I(1,0,0,1) = (float)ref(nxi,yi,nzi,1); I(1,0,0,2) = (float)ref(nxi,yi,nzi,2); 14290 I(1,1,0,1) = (float)ref(nxi,nyi,nzi,0); I(1,1,0,1) = (float)ref(nxi,nyi,nzi,1); I(1,1,0,2) = (float)ref(nxi,nyi,nzi,2); 14291 I(0,1,0,1) = (float)ref(xi,nyi,nzi,0); I(0,1,0,1) = (float)ref(xi,nyi,nzi,1); I(0,1,0,2) = (float)ref(xi,yi,nzi,2); 14292 _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0); 14293 _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1); 14294 } 14295 return (float)pI->_linear_atXYZ(dx,dy,dz,c); 14296 } 14297 }; 14298 14299 struct _functor4d_streamline_expr { 14300 _cimg_math_parser *mp; 14301 ~_functor4d_streamline_expr() { if (mp) delete mp; } 14302 _functor4d_streamline_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,"streamline"); } 14303 float operator()(const float x, const float y, const float z, const unsigned int c) const { 14304 return (float)mp->eval(x,y,z,c); 14305 } 14306 }; 14307 14308 //! Return a vector with specified coefficients. 14309 static CImg<T> vector(const T& a0) { 14310 static CImg<T> r(1,1); r[0] = a0; 14311 return r; 14312 } 14313 14314 //! Return a vector with specified coefficients. 14315 static CImg<T> vector(const T& a0, const T& a1) { 14316 static CImg<T> r(1,2); T *ptr = r._data; 14317 *(ptr++) = a0; *(ptr++) = a1; 14318 return r; 14319 } 14320 14321 //! Return a vector with specified coefficients. 14322 static CImg<T> vector(const T& a0, const T& a1, const T& a2) { 14323 static CImg<T> r(1,3); T *ptr = r._data; 14324 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; 14325 return r; 14326 } 14327 14328 //! Return a vector with specified coefficients. 14329 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) { 14330 static CImg<T> r(1,4); T *ptr = r._data; 14331 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14332 return r; 14333 } 14334 14335 //! Return a vector with specified coefficients. 14336 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { 14337 static CImg<T> r(1,5); T *ptr = r._data; 14338 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; 14339 return r; 14340 } 14341 14342 //! Return a vector with specified coefficients. 14343 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { 14344 static CImg<T> r(1,6); T *ptr = r._data; 14345 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; 14346 return r; 14347 } 14348 14349 //! Return a vector with specified coefficients. 14350 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14351 const T& a4, const T& a5, const T& a6) { 14352 static CImg<T> r(1,7); T *ptr = r._data; 14353 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14354 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; 14355 return r; 14356 } 14357 14358 //! Return a vector with specified coefficients. 14359 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14360 const T& a4, const T& a5, const T& a6, const T& a7) { 14361 static CImg<T> r(1,8); T *ptr = r._data; 14362 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14363 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14364 return r; 14365 } 14366 14367 //! Return a vector with specified coefficients. 14368 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14369 const T& a4, const T& a5, const T& a6, const T& a7, 14370 const T& a8) { 14371 static CImg<T> r(1,9); T *ptr = r._data; 14372 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14373 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14374 *(ptr++) = a8; 14375 return r; 14376 } 14377 14378 //! Return a vector with specified coefficients. 14379 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14380 const T& a4, const T& a5, const T& a6, const T& a7, 14381 const T& a8, const T& a9) { 14382 static CImg<T> r(1,10); T *ptr = r._data; 14383 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14384 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14385 *(ptr++) = a8; *(ptr++) = a9; 14386 return r; 14387 } 14388 14389 //! Return a vector with specified coefficients. 14390 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14391 const T& a4, const T& a5, const T& a6, const T& a7, 14392 const T& a8, const T& a9, const T& a10) { 14393 static CImg<T> r(1,11); T *ptr = r._data; 14394 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14395 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14396 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; 14397 return r; 14398 } 14399 14400 //! Return a vector with specified coefficients. 14401 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14402 const T& a4, const T& a5, const T& a6, const T& a7, 14403 const T& a8, const T& a9, const T& a10, const T& a11) { 14404 static CImg<T> r(1,12); T *ptr = r._data; 14405 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14406 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14407 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14408 return r; 14409 } 14410 14411 //! Return a vector with specified coefficients. 14412 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14413 const T& a4, const T& a5, const T& a6, const T& a7, 14414 const T& a8, const T& a9, const T& a10, const T& a11, 14415 const T& a12) { 14416 static CImg<T> r(1,13); T *ptr = r._data; 14417 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14418 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14419 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14420 *(ptr++) = a12; 14421 return r; 14422 } 14423 14424 //! Return a vector with specified coefficients. 14425 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14426 const T& a4, const T& a5, const T& a6, const T& a7, 14427 const T& a8, const T& a9, const T& a10, const T& a11, 14428 const T& a12, const T& a13) { 14429 static CImg<T> r(1,14); T *ptr = r._data; 14430 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14431 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14432 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14433 *(ptr++) = a12; *(ptr++) = a13; 14434 return r; 14435 } 14436 14437 //! Return a vector with specified coefficients. 14438 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14439 const T& a4, const T& a5, const T& a6, const T& a7, 14440 const T& a8, const T& a9, const T& a10, const T& a11, 14441 const T& a12, const T& a13, const T& a14) { 14442 static CImg<T> r(1,15); T *ptr = r._data; 14443 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14444 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14445 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14446 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; 14447 return r; 14448 } 14449 14450 //! Return a vector with specified coefficients. 14451 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, 14452 const T& a4, const T& a5, const T& a6, const T& a7, 14453 const T& a8, const T& a9, const T& a10, const T& a11, 14454 const T& a12, const T& a13, const T& a14, const T& a15) { 14455 static CImg<T> r(1,16); T *ptr = r._data; 14456 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14457 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14458 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14459 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; 14460 return r; 14461 } 14462 14463 //! Return a 1x1 square matrix with specified coefficients. 14464 static CImg<T> matrix(const T& a0) { 14465 return vector(a0); 14466 } 14467 14468 //! Return a 2x2 square matrix with specified coefficients. 14469 static CImg<T> matrix(const T& a0, const T& a1, 14470 const T& a2, const T& a3) { 14471 static CImg<T> r(2,2); T *ptr = r._data; 14472 *(ptr++) = a0; *(ptr++) = a1; 14473 *(ptr++) = a2; *(ptr++) = a3; 14474 return r; 14475 } 14476 14477 //! Return a 3x3 square matrix with specified coefficients. 14478 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, 14479 const T& a3, const T& a4, const T& a5, 14480 const T& a6, const T& a7, const T& a8) { 14481 static CImg<T> r(3,3); T *ptr = r._data; 14482 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; 14483 *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; 14484 *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; 14485 return r; 14486 } 14487 14488 //! Return a 4x4 square matrix with specified coefficients. 14489 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, 14490 const T& a4, const T& a5, const T& a6, const T& a7, 14491 const T& a8, const T& a9, const T& a10, const T& a11, 14492 const T& a12, const T& a13, const T& a14, const T& a15) { 14493 static CImg<T> r(4,4); T *ptr = r._data; 14494 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; 14495 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; 14496 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; 14497 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; 14498 return r; 14499 } 14500 14501 //! Return a 5x5 square matrix with specified coefficients. 14502 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, 14503 const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, 14504 const T& a10, const T& a11, const T& a12, const T& a13, const T& a14, 14505 const T& a15, const T& a16, const T& a17, const T& a18, const T& a19, 14506 const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) { 14507 static CImg<T> r(5,5); T *ptr = r._data; 14508 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; 14509 *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; 14510 *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; 14511 *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19; 14512 *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24; 14513 return r; 14514 } 14515 14516 //! Return a 1x1 symmetric matrix with specified coefficients. 14517 static CImg<T> tensor(const T& a1) { 14518 return matrix(a1); 14519 } 14520 14521 //! Return a 2x2 symmetric matrix tensor with specified coefficients. 14522 static CImg<T> tensor(const T& a1, const T& a2, const T& a3) { 14523 return matrix(a1,a2,a2,a3); 14524 } 14525 14526 //! Return a 3x3 symmetric matrix with specified coefficients. 14527 static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) { 14528 return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6); 14529 } 14530 14531 //! Return a 1x1 diagonal matrix with specified coefficients. 14532 static CImg<T> diagonal(const T& a0) { 14533 return matrix(a0); 14534 } 14535 14536 //! Return a 2x2 diagonal matrix with specified coefficients. 14537 static CImg<T> diagonal(const T& a0, const T& a1) { 14538 return matrix(a0,0,0,a1); 14539 } 14540 14541 //! Return a 3x3 diagonal matrix with specified coefficients. 14542 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) { 14543 return matrix(a0,0,0,0,a1,0,0,0,a2); 14544 } 14545 14546 //! Return a 4x4 diagonal matrix with specified coefficients. 14547 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) { 14548 return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3); 14549 } 14550 14551 //! Return a 5x5 diagonal matrix with specified coefficients. 14552 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { 14553 return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4); 14554 } 14555 14556 //! Return a NxN identity matrix. 14557 static CImg<T> identity_matrix(const unsigned int N) { 14558 CImg<T> res(N,N,1,1,0); 14559 cimg_forX(res,x) res(x,x) = 1; 14560 return res; 14561 } 14562 14563 //! Return a N-numbered sequence vector from \p a0 to \p a1. 14564 static CImg<T> sequence(const unsigned int N, const T a0, const T a1) { 14565 if (N) return CImg<T>(1,N).sequence(a0,a1); 14566 return CImg<T>(); 14567 } 14568 14569 //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w. 14570 static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) { 14571 float X,Y,Z,W; 14572 if (!quaternion_data) { 14573 const float norm = (float)std::sqrt(x*x + y*y + z*z), 14574 nx = norm>0?x/norm:0, 14575 ny = norm>0?y/norm:0, 14576 nz = norm>0?z/norm:1, 14577 nw = norm>0?w:0, 14578 sina = (float)std::sin(nw/2), 14579 cosa = (float)std::cos(nw/2); 14580 X = nx*sina; 14581 Y = ny*sina; 14582 Z = nz*sina; 14583 W = cosa; 14584 } else { 14585 const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w); 14586 if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; } 14587 else { X = Y = Z = 0; W = 1; } 14588 } 14589 const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W; 14590 return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)), 14591 (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)), 14592 (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy))); 14593 } 14594 14595 //@} 14596 //----------------------------------- 14597 // 14598 //! \name Value Manipulation 14599 //@{ 14600 //----------------------------------- 14601 14602 //! Fill an image by a value \p val. 14603 /** 14604 \param val = fill value 14605 \note All pixel values of the instance image will be initialized by \p val. 14606 **/ 14607 CImg<T>& fill(const T val) { 14608 if (is_empty()) return *this; 14609 if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val; 14610 else std::memset(_data,(int)val,size()*sizeof(T)); 14611 return *this; 14612 } 14613 14614 CImg<T> get_fill(const T val) const { 14615 return CImg<T>(_width,_height,_depth,_spectrum).fill(val); 14616 } 14617 14618 //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively. 14619 CImg<T>& fill(const T val0, const T val1) { 14620 if (is_empty()) return *this; 14621 T *ptrd, *ptre = end()-1; 14622 for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; } 14623 if (ptrd!=ptre+1) *(ptrd++) = val0; 14624 return *this; 14625 } 14626 14627 CImg<T> get_fill(const T val0, const T val1) const { 14628 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1); 14629 } 14630 14631 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2. 14632 CImg<T>& fill(const T val0, const T val1, const T val2) { 14633 if (is_empty()) return *this; 14634 T *ptrd, *ptre = end()-2; 14635 for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; } 14636 ptre+=2; 14637 switch (ptre - ptrd) { 14638 case 2 : *(--ptre) = val1; 14639 case 1 : *(--ptre) = val0; 14640 } 14641 return *this; 14642 } 14643 14644 CImg<T> get_fill(const T val0, const T val1, const T val2) const { 14645 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2); 14646 } 14647 14648 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3. 14649 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) { 14650 if (is_empty()) return *this; 14651 T *ptrd, *ptre = end()-3; 14652 for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; } 14653 ptre+=3; 14654 switch (ptre - ptrd) { 14655 case 3 : *(--ptre) = val2; 14656 case 2 : *(--ptre) = val1; 14657 case 1 : *(--ptre) = val0; 14658 } 14659 return *this; 14660 } 14661 14662 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const { 14663 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3); 14664 } 14665 14666 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4. 14667 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) { 14668 if (is_empty()) return *this; 14669 T *ptrd, *ptre = end()-4; 14670 for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; } 14671 ptre+=4; 14672 switch (ptre - ptrd) { 14673 case 4 : *(--ptre) = val3; 14674 case 3 : *(--ptre) = val2; 14675 case 2 : *(--ptre) = val1; 14676 case 1 : *(--ptre) = val0; 14677 } 14678 return *this; 14679 } 14680 14681 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const { 14682 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4); 14683 } 14684 14685 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5. 14686 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) { 14687 if (is_empty()) return *this; 14688 T *ptrd, *ptre = end()-5; 14689 for (ptrd = _data; ptrd<ptre; ) { 14690 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14691 } 14692 ptre+=5; 14693 switch (ptre - ptrd) { 14694 case 5 : *(--ptre) = val4; 14695 case 4 : *(--ptre) = val3; 14696 case 3 : *(--ptre) = val2; 14697 case 2 : *(--ptre) = val1; 14698 case 1 : *(--ptre) = val0; 14699 } 14700 return *this; 14701 } 14702 14703 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const { 14704 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5); 14705 } 14706 14707 //! Fill sequentially pixel values. 14708 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) { 14709 if (is_empty()) return *this; 14710 T *ptrd, *ptre = end()-6; 14711 for (ptrd = _data; ptrd<ptre; ) { 14712 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6; 14713 } 14714 ptre+=6; 14715 switch (ptre - ptrd) { 14716 case 6 : *(--ptre) = val5; 14717 case 5 : *(--ptre) = val4; 14718 case 4 : *(--ptre) = val3; 14719 case 3 : *(--ptre) = val2; 14720 case 2 : *(--ptre) = val1; 14721 case 1 : *(--ptre) = val0; 14722 } 14723 return *this; 14724 } 14725 14726 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) const { 14727 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6); 14728 } 14729 14730 //! Fill sequentially pixel values. 14731 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14732 const T val7) { 14733 if (is_empty()) return *this; 14734 T *ptrd, *ptre = end()-7; 14735 for (ptrd = _data; ptrd<ptre; ) { 14736 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; 14737 *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; 14738 } 14739 ptre+=7; 14740 switch (ptre - ptrd) { 14741 case 7 : *(--ptre) = val6; 14742 case 6 : *(--ptre) = val5; 14743 case 5 : *(--ptre) = val4; 14744 case 4 : *(--ptre) = val3; 14745 case 3 : *(--ptre) = val2; 14746 case 2 : *(--ptre) = val1; 14747 case 1 : *(--ptre) = val0; 14748 } 14749 return *this; 14750 } 14751 14752 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14753 const T val7) const { 14754 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7); 14755 } 14756 14757 //! Fill sequentially pixel values. 14758 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14759 const T val7, const T val8) { 14760 if (is_empty()) return *this; 14761 T *ptrd, *ptre = end()-8; 14762 for (ptrd = _data; ptrd<ptre; ) { 14763 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; 14764 *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14765 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; 14766 } 14767 ptre+=8; 14768 switch (ptre - ptrd) { 14769 case 8 : *(--ptre) = val7; 14770 case 7 : *(--ptre) = val6; 14771 case 6 : *(--ptre) = val5; 14772 case 5 : *(--ptre) = val4; 14773 case 4 : *(--ptre) = val3; 14774 case 3 : *(--ptre) = val2; 14775 case 2 : *(--ptre) = val1; 14776 case 1 : *(--ptre) = val0; 14777 } 14778 return *this; 14779 } 14780 14781 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14782 const T val7, const T val8) const { 14783 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8); 14784 } 14785 14786 //! Fill sequentially pixel values. 14787 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14788 const T val7, const T val8, const T val9) { 14789 if (is_empty()) return *this; 14790 T *ptrd, *ptre = end()-9; 14791 for (ptrd = _data; ptrd<ptre; ) { 14792 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; 14793 *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; 14794 } 14795 ptre+=9; 14796 switch (ptre - ptrd) { 14797 case 9 : *(--ptre) = val8; 14798 case 8 : *(--ptre) = val7; 14799 case 7 : *(--ptre) = val6; 14800 case 6 : *(--ptre) = val5; 14801 case 5 : *(--ptre) = val4; 14802 case 4 : *(--ptre) = val3; 14803 case 3 : *(--ptre) = val2; 14804 case 2 : *(--ptre) = val1; 14805 case 1 : *(--ptre) = val0; 14806 } 14807 return *this; 14808 } 14809 14810 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14811 const T val7, const T val8, const T val9) const { 14812 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9); 14813 } 14814 14815 //! Fill sequentially pixel values. 14816 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14817 const T val7, const T val8, const T val9, const T val10) { 14818 if (is_empty()) return *this; 14819 T *ptrd, *ptre = end()-10; 14820 for (ptrd = _data; ptrd<ptre; ) { 14821 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; 14822 *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; 14823 *(ptrd++) = val10; 14824 } 14825 ptre+=10; 14826 switch (ptre - ptrd) { 14827 case 10 : *(--ptre) = val9; 14828 case 9 : *(--ptre) = val8; 14829 case 8 : *(--ptre) = val7; 14830 case 7 : *(--ptre) = val6; 14831 case 6 : *(--ptre) = val5; 14832 case 5 : *(--ptre) = val4; 14833 case 4 : *(--ptre) = val3; 14834 case 3 : *(--ptre) = val2; 14835 case 2 : *(--ptre) = val1; 14836 case 1 : *(--ptre) = val0; 14837 } 14838 return *this; 14839 } 14840 14841 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14842 const T val7, const T val8, const T val9, const T val10) const { 14843 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10); 14844 } 14845 14846 //! Fill sequentially pixel values. 14847 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14848 const T val7, const T val8, const T val9, const T val10, const T val11) { 14849 if (is_empty()) return *this; 14850 T *ptrd, *ptre = end()-11; 14851 for (ptrd = _data; ptrd<ptre; ) { 14852 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14853 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11; 14854 } 14855 ptre+=11; 14856 switch (ptre - ptrd) { 14857 case 11 : *(--ptre) = val10; 14858 case 10 : *(--ptre) = val9; 14859 case 9 : *(--ptre) = val8; 14860 case 8 : *(--ptre) = val7; 14861 case 7 : *(--ptre) = val6; 14862 case 6 : *(--ptre) = val5; 14863 case 5 : *(--ptre) = val4; 14864 case 4 : *(--ptre) = val3; 14865 case 3 : *(--ptre) = val2; 14866 case 2 : *(--ptre) = val1; 14867 case 1 : *(--ptre) = val0; 14868 } 14869 return *this; 14870 } 14871 14872 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14873 const T val7, const T val8, const T val9, const T val10, const T val11) const { 14874 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11); 14875 } 14876 14877 //! Fill sequentially pixel values. 14878 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14879 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) { 14880 if (is_empty()) return *this; 14881 T *ptrd, *ptre = end()-12; 14882 for (ptrd = _data; ptrd<ptre; ) { 14883 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14884 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11; 14885 *(ptrd++) = val12; 14886 } 14887 ptre+=12; 14888 switch (ptre - ptrd) { 14889 case 12 : *(--ptre) = val11; 14890 case 11 : *(--ptre) = val10; 14891 case 10 : *(--ptre) = val9; 14892 case 9 : *(--ptre) = val8; 14893 case 8 : *(--ptre) = val7; 14894 case 7 : *(--ptre) = val6; 14895 case 6 : *(--ptre) = val5; 14896 case 5 : *(--ptre) = val4; 14897 case 4 : *(--ptre) = val3; 14898 case 3 : *(--ptre) = val2; 14899 case 2 : *(--ptre) = val1; 14900 case 1 : *(--ptre) = val0; 14901 } 14902 return *this; 14903 } 14904 14905 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14906 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const { 14907 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12); 14908 } 14909 14910 //! Fill sequentially pixel values. 14911 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14912 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 14913 const T val13) { 14914 if (is_empty()) return *this; 14915 T *ptrd, *ptre = end()-13; 14916 for (ptrd = _data; ptrd<ptre; ) { 14917 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14918 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11; 14919 *(ptrd++) = val12; *(ptrd++) = val13; 14920 } 14921 ptre+=13; 14922 switch (ptre - ptrd) { 14923 case 13 : *(--ptre) = val12; 14924 case 12 : *(--ptre) = val11; 14925 case 11 : *(--ptre) = val10; 14926 case 10 : *(--ptre) = val9; 14927 case 9 : *(--ptre) = val8; 14928 case 8 : *(--ptre) = val7; 14929 case 7 : *(--ptre) = val6; 14930 case 6 : *(--ptre) = val5; 14931 case 5 : *(--ptre) = val4; 14932 case 4 : *(--ptre) = val3; 14933 case 3 : *(--ptre) = val2; 14934 case 2 : *(--ptre) = val1; 14935 case 1 : *(--ptre) = val0; 14936 } 14937 return *this; 14938 } 14939 14940 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14941 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 14942 const T val13) const { 14943 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12, 14944 val13); 14945 } 14946 14947 //! Fill sequentially pixel values. 14948 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14949 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 14950 const T val13, const T val14) { 14951 if (is_empty()) return *this; 14952 T *ptrd, *ptre = end()-14; 14953 for (ptrd = _data; ptrd<ptre; ) { 14954 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14955 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11; 14956 *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14; 14957 } 14958 ptre+=14; 14959 switch (ptre - ptrd) { 14960 case 14 : *(--ptre) = val13; 14961 case 13 : *(--ptre) = val12; 14962 case 12 : *(--ptre) = val11; 14963 case 11 : *(--ptre) = val10; 14964 case 10 : *(--ptre) = val9; 14965 case 9 : *(--ptre) = val8; 14966 case 8 : *(--ptre) = val7; 14967 case 7 : *(--ptre) = val6; 14968 case 6 : *(--ptre) = val5; 14969 case 5 : *(--ptre) = val4; 14970 case 4 : *(--ptre) = val3; 14971 case 3 : *(--ptre) = val2; 14972 case 2 : *(--ptre) = val1; 14973 case 1 : *(--ptre) = val0; 14974 } 14975 return *this; 14976 } 14977 14978 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14979 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 14980 const T val13, const T val14) const { 14981 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12, 14982 val13,val14); 14983 } 14984 14985 //! Fill sequentially pixel values. 14986 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 14987 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 14988 const T val13, const T val14, const T val15) { 14989 if (is_empty()) return *this; 14990 T *ptrd, *ptre = end()-15; 14991 for (ptrd = _data; ptrd<ptre; ) { 14992 *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; 14993 *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11; 14994 *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14; *(ptrd++) = val15; 14995 } 14996 ptre+=15; 14997 switch (ptre - ptrd) { 14998 case 15 : *(--ptre) = val14; 14999 case 14 : *(--ptre) = val13; 15000 case 13 : *(--ptre) = val12; 15001 case 12 : *(--ptre) = val11; 15002 case 11 : *(--ptre) = val10; 15003 case 10 : *(--ptre) = val9; 15004 case 9 : *(--ptre) = val8; 15005 case 8 : *(--ptre) = val7; 15006 case 7 : *(--ptre) = val6; 15007 case 6 : *(--ptre) = val5; 15008 case 5 : *(--ptre) = val4; 15009 case 4 : *(--ptre) = val3; 15010 case 3 : *(--ptre) = val2; 15011 case 2 : *(--ptre) = val1; 15012 case 1 : *(--ptre) = val0; 15013 } 15014 return *this; 15015 } 15016 15017 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, 15018 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, 15019 const T val13, const T val14, const T val15) const { 15020 return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12, 15021 val13,val14,val15); 15022 } 15023 15024 //! Fill image values according to the given expression, which can be a formula or a list of values. 15025 CImg<T>& fill(const char *const expression, const bool repeat_flag) { 15026 if (is_empty() || !expression || !*expression) return *this; 15027 const unsigned int omode = cimg::exception_mode(); 15028 cimg::exception_mode() = 0; 15029 try { // Try to fill values according to a formula. 15030 const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this; 15031 _cimg_math_parser mp(base,expression,"fill"); 15032 T *ptrd = _data; 15033 cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp.eval((double)x,(double)y,(double)z,(double)c); 15034 } catch (CImgException& e) { // If failed, try to recognize a list of values. 15035 char item[16384] = { 0 }, sep = 0; const char *nexpression = expression; 15036 unsigned int nb = 0; const unsigned int siz = size(); 15037 T *ptrd = _data; 15038 for (double val = 0; *nexpression && nb<siz; ++nb) { 15039 const int err = std::sscanf(nexpression,"%4095[ \n\t0-9.e+-]%c",item,&sep); 15040 if (err>0 && std::sscanf(item,"%lf",&val)==1) { 15041 nexpression+=std::strlen(item) + (err>1?1:0); 15042 *(ptrd++) = (T)val; 15043 } else break; 15044 } 15045 cimg::exception_mode() = omode; 15046 if (*nexpression && nb<siz) 15047 throw CImgArgumentException(e.what(),pixel_type(),expression); 15048 if (repeat_flag && nb && nb<siz) for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs; 15049 } 15050 cimg::exception_mode() = omode; 15051 return *this; 15052 } 15053 15054 CImg<T> get_fill(const char *const values, const bool repeat_values) const { 15055 return (+*this).fill(values,repeat_values); 15056 } 15057 15058 //! Fill image values according to the values found in the specified image. 15059 template<typename t> 15060 CImg<T>& fill(const CImg<t>& values, const bool repeat_values=true) { 15061 if (is_empty() || !values) return *this; 15062 T *ptrd = _data, *ptre = ptrd + size(); 15063 for (t *ptrs = values._data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptre; ++ptrs) *(ptrd++) = (T)*ptrs; 15064 if (repeat_values && ptrd<ptre) for (T *ptrs = _data; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs; 15065 return *this; 15066 } 15067 15068 template<typename t> 15069 CImg<T> get_fill(const CImg<t>& values, const bool repeat_values=true) const { 15070 return repeat_values?CImg<T>(_width,_height,_depth,_spectrum).fill(values,repeat_values):(+*this).fill(values,repeat_values); 15071 } 15072 15073 //! Fill image values along the X-axis at the specified pixel position (y,z,c). 15074 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) { 15075 #define _cimg_fill1(x,y,z,c,off,siz,t) { \ 15076 va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \ 15077 for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \ 15078 va_end(ap); } 15079 if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,int); 15080 return *this; 15081 } 15082 15083 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) { 15084 if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double); 15085 return *this; 15086 } 15087 15088 //! Fill image values along the Y-axis at the specified pixel position (x,z,c). 15089 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const int a0, ...) { 15090 if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,int); 15091 return *this; 15092 } 15093 15094 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) { 15095 if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double); 15096 return *this; 15097 } 15098 15099 //! Fill image values along the Z-axis at the specified pixel position (x,y,c). 15100 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const int a0, ...) { 15101 const unsigned int wh = _width*_height; 15102 if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,int); 15103 return *this; 15104 } 15105 15106 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const double a0, ...) { 15107 const unsigned int wh = _width*_height; 15108 if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,double); 15109 return *this; 15110 } 15111 15112 //! Fill image values along the C-axis at the specified pixel position (x,y,z). 15113 CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) { 15114 const unsigned int whd = _width*_height*_depth; 15115 if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,int); 15116 return *this; 15117 } 15118 15119 CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) { 15120 const unsigned int whd = _width*_height*_depth; 15121 if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,double); 15122 return *this; 15123 } 15124 15125 //! Invert endianness of the image buffer. 15126 CImg<T>& invert_endianness() { 15127 cimg::invert_endianness(_data,size()); 15128 return *this; 15129 } 15130 15131 CImg<T> get_invert_endianness() const { 15132 return (+*this).invert_endianness(); 15133 } 15134 15135 //! Fill the instance image with random values between specified range. 15136 CImg<T>& rand(const T val_min, const T val_max) { 15137 const float delta = (float)val_max - (float)val_min; 15138 cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta); 15139 return *this; 15140 } 15141 15142 CImg<T> get_rand(const T val_min, const T val_max) const { 15143 return (+*this).rand(val_min,val_max); 15144 } 15145 15146 //! Compute image with rounded pixel values. 15147 /** 15148 \param x Rounding precision. 15149 \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward). 15150 **/ 15151 CImg<T>& round(const float x, const int rounding_type=0) { 15152 if (x>0) cimg_for(*this,ptrd,T) *ptrd = (T)cimg::round(*ptrd,x,rounding_type); 15153 return *this; 15154 } 15155 15156 CImg<T> get_round(const float x, const unsigned int rounding_type=0) const { 15157 return (+*this).round(x,rounding_type); 15158 } 15159 15160 //! Add random noise to the values of the instance image. 15161 /** 15162 \param sigma Amplitude of the random additive noise. If \p sigma<0, it stands for a percentage of the global value range. 15163 \param noise_type Type of additive noise (can be \p 0=gaussian, \p 1=uniform, \p 2=Salt and Pepper, \p 3=Poisson or \p 4=Rician). 15164 \return A reference to the modified instance image. 15165 \note 15166 - For Poisson noise (\p noise_type=3), parameter \p sigma is ignored, as Poisson noise only depends on the image value itself. 15167 - Function \p CImg<T>::get_noise() is also defined. It returns a non-shared modified copy of the instance image. 15168 \par Sample code : 15169 \code 15170 const CImg<float> img("reference.jpg"), res = img.get_noise(40); 15171 (img,res.normalize(0,255)).display(); 15172 \endcode 15173 \image html ref_noise.jpg 15174 **/ 15175 CImg<T>& noise(const double sigma, const unsigned int noise_type=0) { 15176 if (!is_empty()) { 15177 double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min(); 15178 Tfloat m = 0, M = 0; 15179 if (nsigma==0 && noise_type!=3) return *this; 15180 if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M); 15181 if (nsigma<0) nsigma = -nsigma*(M-m)/100.0; 15182 switch (noise_type) { 15183 case 0 : { // Gaussian noise 15184 cimg_for(*this,ptrd,T) { 15185 double val = *ptrd + nsigma*cimg::grand(); 15186 if (val>max) val = max; 15187 if (val<min) val = min; 15188 *ptrd = (T)val; 15189 } 15190 } break; 15191 case 1 : { // Uniform noise 15192 cimg_for(*this,ptrd,T) { 15193 double val = *ptrd + nsigma*cimg::crand(); 15194 if (val>max) val = max; 15195 if (val<min) val = min; 15196 *ptrd = (T)val; 15197 } 15198 } break; 15199 case 2 : { // Salt & Pepper noise 15200 if (nsigma<0) nsigma = -nsigma; 15201 if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); } 15202 cimg_for(*this,ptrd,T) if (cimg::rand()*100<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m); 15203 } break; 15204 15205 case 3 : { // Poisson Noise 15206 cimg_for(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd); 15207 } break; 15208 15209 case 4 : { // Rice noise 15210 const double sqrt2 = (double)std::sqrt(2.0); 15211 cimg_for(*this,ptrd,T) { 15212 const double 15213 val0 = (double)*ptrd/sqrt2, 15214 re = val0 + nsigma*cimg::grand(), 15215 im = val0 + nsigma*cimg::grand(); 15216 double val = std::sqrt(re*re + im*im); 15217 if (val>max) val = max; 15218 if (val<min) val = min; 15219 *ptrd = (T)val; 15220 } 15221 } break; 15222 default : 15223 throw CImgArgumentException(_cimg_instance 15224 "noise() : Invalid specified noise type %d " 15225 "(should be { 0=gaussian | 1=uniform | 2=salt&Pepper | 3=poisson }).", 15226 cimg_instance, 15227 noise_type); 15228 } 15229 } 15230 return *this; 15231 } 15232 15233 CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const { 15234 return (+*this).noise(sigma,noise_type); 15235 } 15236 15237 //! Linearly normalize values of the instance image between \p value_min and \p value_max. 15238 /** 15239 \param value_min Minimum desired value of the resulting image. 15240 \param value_max Maximum desired value of the resulting image. 15241 \return A reference to the modified instance image. 15242 \note 15243 - Function \p CImg<T>::get_normalize() is also defined. It returns a non-shared modified copy of the instance image. 15244 \par Sample code : 15245 \code 15246 const CImg<float> img("reference.jpg"), res = img.get_normalize(160,220); 15247 (img,res).display(); 15248 \endcode 15249 \image html ref_normalize2.jpg 15250 **/ 15251 CImg<T>& normalize(const T value_min, const T value_max) { 15252 if (is_empty()) return *this; 15253 const T a = value_min<value_max?value_min:value_max, b = value_min<value_max?value_max:value_min; 15254 T m, M = max_min(m); 15255 const Tfloat fm = (Tfloat)m, fM = (Tfloat)M; 15256 if (m==M) return fill(0); 15257 if (m!=a || M!=b) cimg_for(*this,ptrd,T) *ptrd = (T)((*ptrd-fm)/(fM-fm)*(b-a)+a); 15258 return *this; 15259 } 15260 15261 CImg<Tfloat> get_normalize(const T value_min, const T value_max) const { 15262 return CImg<Tfloat>(*this,false).normalize((Tfloat)value_min,(Tfloat)value_max); 15263 } 15264 15265 //! Normalize multi-valued pixels of the instance image, with respect to their L2-norm. 15266 /** 15267 \return A reference to the modified instance image. 15268 \note 15269 - Function \p CImg<T>::get_normalize() is also defined. It returns a non-shared modified copy of the instance image. 15270 \par Sample code : 15271 \code 15272 const CImg<float> img("reference.jpg"), res = img.get_normalize(); 15273 (img,res.normalize(0,255)).display(); 15274 \endcode 15275 \image html ref_normalize.jpg 15276 **/ 15277 CImg<T>& normalize() { 15278 T *ptrd = _data; 15279 const unsigned int whd = _width*_height*_depth; 15280 cimg_forXYZ(*this,x,y,z) { 15281 const T *ptrs = ptrd; 15282 float n = 0; 15283 cimg_forC(*this,c) { n+=cimg::sqr((float)*ptrs); ptrs+=whd; } 15284 n = (float)std::sqrt(n); 15285 T *_ptrd = ptrd++; 15286 if (n>0) cimg_forC(*this,c) { *_ptrd = (T)(*_ptrd/n); _ptrd+=whd; } 15287 else cimg_forC(*this,c) { *_ptrd = (T)0; _ptrd+=whd; } 15288 } 15289 return *this; 15290 } 15291 15292 CImg<Tfloat> get_normalize() const { 15293 return CImg<Tfloat>(*this,false).normalize(); 15294 } 15295 15296 //! Compute L2-norm of each multi-valued pixel of the instance image. 15297 /** 15298 \param norm_type Type of computed vector norm (can be \p 0=Linf, \p 1=L1 or \p 2=L2). 15299 \return A reference to the modified instance image. 15300 \note 15301 - Function \p CImg<T>::get_norm() is also defined. It returns a non-shared modified copy of the instance image. 15302 \par Sample code : 15303 \code 15304 const CImg<float> img("reference.jpg"), res = img.get_norm(); 15305 (img,res.normalize(0,255)).display(); 15306 \endcode 15307 \image html ref_norm.jpg 15308 **/ 15309 CImg<T>& norm(const int norm_type=2) { 15310 if (_spectrum==1) return abs(); 15311 return get_norm(norm_type).move_to(*this); 15312 } 15313 15314 CImg<Tfloat> get_norm(const int norm_type=2) const { 15315 if (is_empty()) return *this; 15316 if (_spectrum==1) return get_abs(); 15317 const T *ptrs = _data; 15318 const unsigned int whd = _width*_height*_depth; 15319 CImg<Tfloat> res(_width,_height,_depth); 15320 Tfloat *ptrd = res._data; 15321 switch (norm_type) { 15322 case -1 : { // Linf norm 15323 cimg_forXYZ(*this,x,y,z) { 15324 Tfloat n = 0; 15325 const T *_ptrs = ptrs++; 15326 cimg_forC(*this,c) { const Tfloat val = (Tfloat)cimg::abs(*_ptrs); if (val>n) n = val; _ptrs+=whd; } 15327 *(ptrd++) = n; 15328 } 15329 } break; 15330 case 1 : { // L1 norm 15331 cimg_forXYZ(*this,x,y,z) { 15332 Tfloat n = 0; 15333 const T *_ptrs = ptrs++; 15334 cimg_forC(*this,c) { n+=cimg::abs(*_ptrs); _ptrs+=whd; } 15335 *(ptrd++) = n; 15336 } 15337 } break; 15338 default : { // L2 norm 15339 cimg_forXYZ(*this,x,y,z) { 15340 Tfloat n = 0; 15341 const T *_ptrs = ptrs++; 15342 cimg_forC(*this,c) { n+=cimg::sqr((Tfloat)*_ptrs); _ptrs+=whd; } 15343 *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n); 15344 } 15345 } 15346 } 15347 return res; 15348 } 15349 15350 //! Cut values of the instance image between \p value_min and \p value_max. 15351 /** 15352 \param value_min Minimum desired value of the resulting image. 15353 \param value_max Maximum desired value of the resulting image. 15354 \return A reference to the modified instance image. 15355 \note 15356 - Function \p CImg<T>::get_cut() is also defined. It returns a non-shared modified copy of the instance image. 15357 \par Sample code : 15358 \code 15359 const CImg<float> img("reference.jpg"), res = img.get_cut(160,220); 15360 (img,res).display(); 15361 \endcode 15362 \image html ref_cut.jpg 15363 **/ 15364 CImg<T>& cut(const T value_min, const T value_max) { 15365 if (is_empty()) return *this; 15366 const T a = value_min<value_max?value_min:value_max, b = value_min<value_max?value_max:value_min; 15367 cimg_for(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd); 15368 return *this; 15369 } 15370 15371 CImg<T> get_cut(const T value_min, const T value_max) const { 15372 return (+*this).cut(value_min,value_max); 15373 } 15374 15375 //! Uniformly quantize values of the instance image into \p nb_levels levels. 15376 /** 15377 \param nb_levels Number of quantization levels. 15378 \param keep_range Tells if resulting values keep the same range as the original ones. 15379 \return A reference to the modified instance image. 15380 \note 15381 - Function \p CImg<T>::get_quantize() is also defined. It returns a non-shared modified copy of the instance image. 15382 \par Sample code : 15383 \code 15384 const CImg<float> img("reference.jpg"), res = img.get_quantize(4); 15385 (img,res).display(); 15386 \endcode 15387 \image html ref_quantize.jpg 15388 **/ 15389 CImg<T>& quantize(const unsigned int nb_levels, const bool keep_range=true) { 15390 if (!nb_levels) 15391 throw CImgArgumentException(_cimg_instance 15392 "quantize() : Invalid quantization request with 0 values.", 15393 cimg_instance); 15394 15395 if (is_empty()) return *this; 15396 Tfloat m, M = (Tfloat)max_min(m), range = M - m; 15397 if (range>0) { 15398 if (keep_range) cimg_for(*this,ptrd,T) { 15399 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); 15400 *ptrd = (T)(m + cimg::min(val,nb_levels-1)*range/nb_levels); 15401 } else cimg_for(*this,ptrd,T) { 15402 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); 15403 *ptrd = (T)cimg::min(val,nb_levels-1); 15404 } 15405 } 15406 return *this; 15407 } 15408 15409 CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const { 15410 return (+*this).quantize(n,keep_range); 15411 } 15412 15413 //! Threshold values of the instance image. 15414 /** 15415 \param value Threshold value 15416 \param soft_threshold Tells if soft thresholding must be applied (instead of hard one). 15417 \param strict_threshold Tells if threshold value is strict. 15418 \return A reference to the modified instance image. Resulting pixel values are either equal to 0 or 1. 15419 \note 15420 - Function \p CImg<T>::get_threshold() is also defined. It returns a non-shared modified copy of the instance image. 15421 \par Sample code : 15422 \code 15423 const CImg<float> img("reference.jpg"), res = img.get_threshold(128); 15424 (img,res.normalize(0,255)).display(); 15425 \endcode 15426 \image html ref_threshold.jpg 15427 **/ 15428 CImg<T>& threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) { 15429 if (is_empty()) return *this; 15430 if (strict_threshold) { 15431 if (soft_threshold) cimg_for(*this,ptrd,T) { const T v = *ptrd; *ptrd = v>value?(T)(v-value):v<-(float)value?(T)(v+value):(T)0; } 15432 else cimg_for(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0; 15433 } else { 15434 if (soft_threshold) cimg_for(*this,ptrd,T) { const T v = *ptrd; *ptrd = v>=value?(T)(v-value):v<=-(float)value?(T)(v+value):(T)0; } 15435 else cimg_for(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0; 15436 } 15437 return *this; 15438 } 15439 15440 CImg<T> get_threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) const { 15441 return (+*this).threshold(value,soft_threshold,strict_threshold); 15442 } 15443 15444 //! Compute the histogram of the instance image. 15445 /** 15446 \param nb_levels Number of desired histogram levels. 15447 \param value_min Minimum pixel value considered for the histogram computation. All pixel values lower than \p value_min will not be counted. 15448 \param value_max Maximum pixel value considered for the histogram computation. All pixel values higher than \p value_max will not be counted. 15449 \return Instance image is replaced by its histogram, defined as a \p CImg<T>(nb_levels) image. 15450 \note 15451 - The histogram H of an image I is the 1d function where H(x) counts the number of occurences of the value x in the image I. 15452 - If \p value_min==value_max==0 (default behavior), the function first estimates the whole range of pixel values 15453 then uses it to compute the histogram. 15454 - The resulting histogram is always defined in 1d. Histograms of multi-valued images are not multi-dimensional. 15455 - Function \p CImg<T>::get_histogram() is also defined. It returns a non-shared modified copy of the instance image. 15456 \par Sample code : 15457 \code 15458 const CImg<float> img = CImg<float>("reference.jpg").histogram(256); 15459 img.display_graph(0,3); 15460 \endcode 15461 \image html ref_histogram.jpg 15462 **/ 15463 CImg<T>& histogram(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) { 15464 return get_histogram(nb_levels,value_min,value_max).move_to(*this); 15465 } 15466 15467 CImg<floatT> get_histogram(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) const { 15468 if (!nb_levels) 15469 throw CImgArgumentException(_cimg_instance 15470 "histogram() : Invalid histogram request with 0 levels.", 15471 cimg_instance); 15472 15473 if (is_empty()) return CImg<floatT>(); 15474 T vmin = value_min, vmax = value_max; 15475 CImg<floatT> res(nb_levels,1,1,1,0); 15476 if (vmin>=vmax && vmin==0) vmin = min_max(vmax); 15477 if (vmin<vmax) cimg_for(*this,ptrs,T) { 15478 const T val = *ptrs; 15479 if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels-1:(int)((val-vmin)*nb_levels/(vmax-vmin))]; 15480 } else res[0]+=size(); 15481 return res; 15482 } 15483 15484 //! Compute the histogram-equalized version of the instance image. 15485 /** 15486 \param nb_levels Number of histogram levels used for the equalization. 15487 \param value_min Minimum pixel value considered for the histogram computation. All pixel values lower than \p value_min will not be counted. 15488 \param value_max Maximum pixel value considered for the histogram computation. All pixel values higher than \p value_max will not be counted. 15489 \return A reference to the modified instance image. 15490 \note 15491 - If \p value_min==value_max==0 (default behavior), the function first estimates the whole range of pixel values 15492 then uses it to equalize the histogram. 15493 - Function \p CImg<T>::get_equalize() is also defined. It returns a non-shared modified copy of the instance image. 15494 \par Sample code : 15495 \code 15496 const CImg<float> img("reference.jpg"), res = img.get_equalize(256); 15497 (img,res).display(); 15498 \endcode 15499 \image html ref_equalize.jpg 15500 **/ 15501 CImg<T>& equalize(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) { 15502 if (is_empty()) return *this; 15503 T vmin = value_min, vmax = value_max; 15504 if (vmin==vmax && vmin==0) vmin = min_max(vmax); 15505 if (vmin<vmax) { 15506 CImg<floatT> hist = get_histogram(nb_levels,vmin,vmax); 15507 float cumul = 0; 15508 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } 15509 cimg_for(*this,ptrd,T) { 15510 const int pos = (unsigned int)((*ptrd-vmin)*(nb_levels-1)/(vmax-vmin)); 15511 if (pos>=0 && pos<(int)nb_levels) *ptrd = (T)(vmin + (vmax-vmin)*hist[pos]/size()); 15512 } 15513 } 15514 return *this; 15515 } 15516 15517 CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const { 15518 return (+*this).equalize(nblevels,val_min,val_max); 15519 } 15520 15521 //! Index multi-valued pixels of the instance image, regarding to a predefined palette. 15522 /** 15523 \param palette Multi-valued palette used as the basis for multi-valued pixel indexing. 15524 \param dithering Tells if Floyd-Steinberg dithering is activated or not. 15525 \param map_indexes Tell if the values of the resulting image are the palette indices or the palette vectors. 15526 \return A reference to the modified instance image. 15527 \note 15528 - \p img.index(palette,dithering,1) is equivalent to <tt>img.index(palette,dithering,0).map(palette)</tt>. 15529 - Function \p CImg<T>::get_index() is also defined. It returns a non-shared modified copy of the instance image. 15530 \par Sample code : 15531 \code 15532 const CImg<float> img("reference.jpg"), palette(3,1,1,3, 0,128,255, 0,128,255, 0,128,255); 15533 const CImg<float> res = img.get_index(palette,true,true); 15534 (img,res).display(); 15535 \endcode 15536 \image html ref_index.jpg 15537 **/ 15538 template<typename t> 15539 CImg<T>& index(const CImg<t>& palette, const bool dithering=false, const bool map_indexes=false) { 15540 return get_index(palette,dithering,map_indexes).move_to(*this); 15541 } 15542 15543 template<typename t> 15544 CImg<typename CImg<t>::Tuint> 15545 get_index(const CImg<t>& palette, const bool dithering=false, const bool map_indexes=true) const { 15546 if (palette._spectrum!=_spectrum) 15547 throw CImgArgumentException(_cimg_instance 15548 "index() : Instance and specified palette (%u,%u,%u,%u,%p) " 15549 "have incompatible dimensions.", 15550 cimg_instance, 15551 palette._width,palette._height,palette._depth,palette._spectrum,palette._data); 15552 15553 typedef typename CImg<t>::Tuint tuint; 15554 if (is_empty()) return CImg<tuint>(); 15555 const unsigned int whd = _width*_height*_depth, pwhd = palette._width*palette._height*palette._depth; 15556 CImg<tuint> res(_width,_height,_depth,map_indexes?_spectrum:1); 15557 tuint *ptrd = res._data; 15558 if (dithering) { // Dithered versions. 15559 Tfloat valm = 0, valM = (Tfloat)max_min(valm); 15560 if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; } 15561 CImg<Tfloat> cache = get_crop(-1,0,0,0,_width,1,0,_spectrum-1); 15562 Tfloat *cache_current = cache.data(1,0,0,0), *cache_next = cache.data(1,1,0,0); 15563 const unsigned int cwhd = cache._width*cache._height*cache._depth; 15564 switch (_spectrum) { 15565 case 1 : { // Optimized for scalars. 15566 cimg_forYZ(*this,y,z) { 15567 if (y<height()-2) { 15568 Tfloat *ptrc0 = cache_next; const T *ptrs0 = data(0,y+1,z,0); 15569 cimg_forX(*this,x) *(ptrc0++) = (Tfloat)*(ptrs0++); 15570 } 15571 Tfloat *ptrs0 = cache_current, *ptrsn0 = cache_next; 15572 cimg_forX(*this,x) { 15573 const Tfloat _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0; 15574 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15575 for (const t *ptrp0 = palette._data, *ptrp_end = ptrp0 + pwhd; ptrp0<ptrp_end; ) { 15576 const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0; 15577 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15578 } 15579 const Tfloat err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16; 15580 *ptrs0+=7*err0; *(ptrsn0-1)+=3*err0; *(ptrsn0++)+=5*err0; *ptrsn0+=err0; 15581 if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15582 } 15583 cimg::swap(cache_current,cache_next); 15584 } 15585 } break; 15586 case 2 : { // Optimized for 2d vectors. 15587 tuint *ptrd1 = ptrd + whd; 15588 cimg_forYZ(*this,y,z) { 15589 if (y<height()-2) { 15590 Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhd; 15591 const T *ptrs0 = data(0,y+1,z,0), *ptrs1 = ptrs0 + whd; 15592 cimg_forX(*this,x) { *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); } 15593 } 15594 Tfloat 15595 *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhd, 15596 *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhd; 15597 cimg_forX(*this,x) { 15598 const Tfloat 15599 _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0, 15600 _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1; 15601 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15602 for (const t *ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) { 15603 const Tfloat 15604 pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, 15605 dist = pval0*pval0 + pval1*pval1; 15606 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15607 } 15608 const t *const ptrmin1 = ptrmin0 + pwhd; 15609 const Tfloat 15610 err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16, 15611 err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)/16; 15612 *ptrs0+=7*err0; *ptrs1+=7*err1; 15613 *(ptrsn0-1)+=3*err0; *(ptrsn1-1)+=3*err1; 15614 *(ptrsn0++)+=5*err0; *(ptrsn1++)+=5*err1; 15615 *ptrsn0+=err0; *ptrsn1+=err1; 15616 if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; } 15617 else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15618 } 15619 cimg::swap(cache_current,cache_next); 15620 } 15621 } break; 15622 case 3 : { // Optimized for 3d vectors (colors). 15623 tuint *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd; 15624 cimg_forYZ(*this,y,z) { 15625 if (y<height()-2) { 15626 Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhd, *ptrc2 = ptrc1 + cwhd; 15627 const T *ptrs0 = data(0,y+1,z,0), *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd; 15628 cimg_forX(*this,x) { *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); *(ptrc2++) = (Tfloat)*(ptrs2++); } 15629 } 15630 Tfloat 15631 *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhd, *ptrs2 = ptrs1 + cwhd, 15632 *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhd, *ptrsn2 = ptrsn1 + cwhd; 15633 cimg_forX(*this,x) { 15634 const Tfloat 15635 _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0, 15636 _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1, 15637 _val2 = (Tfloat)*ptrs2, val2 = _val2<valm?valm:_val2>valM?valM:_val2; 15638 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15639 for (const t *ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) { 15640 const Tfloat 15641 pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, pval2 = (Tfloat)*(ptrp2++) - val2, 15642 dist = pval0*pval0 + pval1*pval1 + pval2*pval2; 15643 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15644 } 15645 const t *const ptrmin1 = ptrmin0 + pwhd, *const ptrmin2 = ptrmin1 + pwhd; 15646 const Tfloat 15647 err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16, 15648 err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)/16, 15649 err2 = ((*(ptrs2++)=val2) - (Tfloat)*ptrmin2)/16; 15650 *ptrs0+=7*err0; *ptrs1+=7*err1; *ptrs2+=7*err2; 15651 *(ptrsn0-1)+=3*err0; *(ptrsn1-1)+=3*err1; *(ptrsn2-1)+=3*err2; 15652 *(ptrsn0++)+=5*err0; *(ptrsn1++)+=5*err1; *(ptrsn2++)+=5*err2; 15653 *ptrsn0+=err0; *ptrsn1+=err1; *ptrsn2+=err2; 15654 if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; *(ptrd2++) = (tuint)*ptrmin2; } 15655 else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15656 } 15657 cimg::swap(cache_current,cache_next); 15658 } 15659 } break; 15660 default : // Generic version 15661 cimg_forYZ(*this,y,z) { 15662 if (y<height()-2) { 15663 Tfloat *ptrc = cache_next; 15664 cimg_forC(*this,c) { 15665 Tfloat *_ptrc = ptrc; const T *_ptrs = data(0,y+1,z,c); 15666 cimg_forX(*this,x) *(_ptrc++) = (Tfloat)*(_ptrs++); 15667 ptrc+=cwhd; 15668 } 15669 } 15670 Tfloat *ptrs = cache_current, *ptrsn = cache_next; 15671 cimg_forX(*this,x) { 15672 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = palette._data; 15673 for (const t *ptrp = palette._data, *ptrp_end = ptrp + pwhd; ptrp<ptrp_end; ++ptrp) { 15674 Tfloat dist = 0; Tfloat *_ptrs = ptrs; const t *_ptrp = ptrp; 15675 cimg_forC(*this,c) { 15676 const Tfloat _val = *_ptrs, val = _val<valm?valm:_val>valM?valM:_val; 15677 dist+=cimg::sqr((*_ptrs=val) - (Tfloat)*_ptrp); _ptrs+=cwhd; _ptrp+=pwhd; 15678 } 15679 if (dist<distmin) { ptrmin = ptrp; distmin = dist; } 15680 } 15681 const t *_ptrmin = ptrmin; Tfloat *_ptrs = ptrs++, *_ptrsn = (ptrsn++)-1; 15682 cimg_forC(*this,c) { 15683 const Tfloat err = (*(_ptrs++) - (Tfloat)*_ptrmin)/16; 15684 *_ptrs+=7*err; *(_ptrsn++)+=3*err; *(_ptrsn++)+=5*err; *_ptrsn+=err; 15685 _ptrmin+=pwhd; _ptrs+=cwhd-1; _ptrsn+=cwhd-2; 15686 } 15687 if (map_indexes) { 15688 tuint *_ptrd = ptrd++; 15689 cimg_forC(*this,c) { *_ptrd = (tuint)*ptrmin; _ptrd+=whd; ptrmin+=pwhd; } 15690 } 15691 else *(ptrd++) = (tuint)(ptrmin - palette._data); 15692 } 15693 cimg::swap(cache_current,cache_next); 15694 } 15695 } 15696 } else { // Non-dithered versions 15697 switch (_spectrum) { 15698 case 1 : { // Optimized for scalars. 15699 for (const T *ptrs0 = _data, *ptrs_end = ptrs0 + whd; ptrs0<ptrs_end; ) { 15700 const Tfloat val0 = (Tfloat)*(ptrs0++); 15701 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15702 for (const t *ptrp0 = palette._data, *ptrp_end = ptrp0 + pwhd; ptrp0<ptrp_end; ) { 15703 const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0; 15704 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15705 } 15706 if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15707 } 15708 } break; 15709 case 2 : { // Optimized for 2d vectors. 15710 tuint *ptrd1 = ptrd + whd; 15711 for (const T *ptrs0 = _data, *ptrs1 = ptrs0 + whd, *ptrs_end = ptrs1; ptrs0<ptrs_end; ) { 15712 const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++); 15713 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15714 for (const t *ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) { 15715 const Tfloat 15716 pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, 15717 dist = pval0*pval0 + pval1*pval1; 15718 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15719 } 15720 if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*(ptrmin0 + pwhd); } 15721 else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15722 } 15723 } break; 15724 case 3 : { // Optimized for 3d vectors (colors). 15725 tuint *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd; 15726 for (const T *ptrs0 = _data, *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd, *ptrs_end = ptrs1; ptrs0<ptrs_end; ) { 15727 const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++), val2 = (Tfloat)*(ptrs2++); 15728 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette._data; 15729 for (const t *ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) { 15730 const Tfloat 15731 pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, pval2 = (Tfloat)*(ptrp2++) - val2, 15732 dist = pval0*pval0 + pval1*pval1 + pval2*pval2; 15733 if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; } 15734 } 15735 if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*(ptrmin0 + pwhd); *(ptrd2++) = (tuint)*(ptrmin0 + 2*pwhd); } 15736 else *(ptrd++) = (tuint)(ptrmin0 - palette._data); 15737 } 15738 } break; 15739 default : // Generic version. 15740 for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ++ptrs) { 15741 Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = palette._data; 15742 for (const t *ptrp = palette._data, *ptrp_end = ptrp + pwhd; ptrp<ptrp_end; ++ptrp) { 15743 Tfloat dist = 0; const T *_ptrs = ptrs; const t *_ptrp = ptrp; 15744 cimg_forC(*this,c) { dist+=cimg::sqr((Tfloat)*_ptrs - (Tfloat)*_ptrp); _ptrs+=whd; _ptrp+=pwhd; } 15745 if (dist<distmin) { ptrmin = ptrp; distmin = dist; } 15746 } 15747 if (map_indexes) { 15748 tuint *_ptrd = ptrd++; 15749 cimg_forC(*this,c) { *_ptrd = (tuint)*ptrmin; _ptrd+=whd; ptrmin+=pwhd; } 15750 } 15751 else *(ptrd++) = (tuint)(ptrmin - palette._data); 15752 } 15753 } 15754 } 15755 return res; 15756 } 15757 15758 //! Map predefined palette on the scalar (indexed) instance image. 15759 /** 15760 \param palette Multi-valued palette used for mapping the indexes. 15761 \return A reference to the modified instance image. 15762 \note 15763 - Function \p CImg<T>::get_map() is also defined. It returns a non-shared modified copy of the instance image. 15764 \par Sample code : 15765 \code 15766 const CImg<float> img("reference.jpg"), 15767 palette1(3,1,1,3, 0,128,255, 0,128,255, 0,128,255), 15768 palette2(3,1,1,3, 255,0,0, 0,255,0, 0,0,255), 15769 res = img.get_index(palette1,false).map(palette2); 15770 (img,res).display(); 15771 \endcode 15772 \image html ref_map.jpg 15773 **/ 15774 template<typename t> 15775 CImg<T>& map(const CImg<t>& palette) { 15776 return get_map(palette).move_to(*this); 15777 } 15778 15779 template<typename t> 15780 CImg<t> get_map(const CImg<t>& palette) const { 15781 if (_spectrum!=1 && palette._spectrum!=1) 15782 throw CImgArgumentException(_cimg_instance 15783 "map() : Instance and specified palette (%u,%u,%u,%u,%p) " 15784 "have incompatible dimensions.", 15785 cimg_instance, 15786 palette._width,palette._height,palette._depth,palette._spectrum,palette._data); 15787 15788 const unsigned int whd = _width*_height*_depth, pwhd = palette._width*palette._height*palette._depth; 15789 CImg<t> res(_width,_height,_depth,palette._spectrum==1?_spectrum:palette._spectrum); 15790 switch (palette._spectrum) { 15791 case 1 : { // Optimized for scalars. 15792 const T *ptrs = _data + whd*_spectrum; 15793 cimg_for(res,ptrd,t) { 15794 const unsigned int _ind = (unsigned int)*(--ptrs), ind = _ind<pwhd?_ind:0; 15795 *ptrd = palette[ind]; 15796 } 15797 } break; 15798 case 2 : { // Optimized for 2d vectors. 15799 const t *const ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd; 15800 t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd; 15801 for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) { 15802 const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhd?_ind:0; 15803 *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; 15804 } 15805 } break; 15806 case 3 : { // Optimized for 3d vectors (colors). 15807 const t *const ptrp0 = palette._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd; 15808 t *ptrd0 = res._data, *ptrd1 = ptrd0 + whd, *ptrd2 = ptrd1 + whd; 15809 for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) { 15810 const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhd?_ind:0; 15811 *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind]; 15812 } 15813 } break; 15814 default : { // Generic version. 15815 t *ptrd = res._data; 15816 for (const T *ptrs = _data, *ptrs_end = ptrs + whd; ptrs<ptrs_end; ) { 15817 const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhd?_ind:0; 15818 const t *ptrp = palette._data + ind; 15819 t *_ptrd = ptrd++; cimg_forC(res,c) { *_ptrd = *ptrp; _ptrd+=whd; ptrp+=pwhd; } 15820 } 15821 } 15822 } 15823 return res; 15824 } 15825 15826 //! Create a map of indexed labels counting disconnected regions with same intensities. 15827 /** 15828 \return A reference to the modified instance image. 15829 \note 15830 - Function \p CImg<T>::get_label_regions() is also defined. It returns a non-shared modified copy of the instance image. 15831 \par Sample code : 15832 \code 15833 const CImg<float> img = CImg<float>("reference.jpg").norm().quantize(4), 15834 palette = CImg<float>::default_LUT256(), 15835 res = img.get_label_regions().normalize(0,255).map(palette); 15836 (img,res).display(); 15837 \endcode 15838 \image html ref_label_regions.jpg 15839 **/ 15840 CImg<T>& label_regions() { 15841 return get_label_regions().move_to(*this); 15842 } 15843 15844 CImg<uintT> get_label_regions() const { 15845 #define _cimg_get_label_test(p,q) { \ 15846 flag = true; \ 15847 const T *ptr1 = data(x,y) + siz, *ptr2 = data(p,q) + siz; \ 15848 for (unsigned int i = _spectrum; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \ 15849 } 15850 if (_depth>1) 15851 throw CImgInstanceException(_cimg_instance 15852 "label_regions() : Instance is not a 2d image.", 15853 cimg_instance); 15854 15855 CImg<uintT> res(_width,_height,_depth,1,0); 15856 unsigned int label = 1; 15857 const unsigned int wh = _width*_height, siz = _width*_height*_spectrum; 15858 const int W1 = width()-1, H1 = height()-1; 15859 bool flag; 15860 cimg_forXY(*this,x,y) { 15861 bool done = false; 15862 if (y) { 15863 _cimg_get_label_test(x,y-1); 15864 if (flag) { 15865 const unsigned int lab = (res(x,y) = res(x,y-1)); 15866 done = true; 15867 if (x && res(x-1,y)!=lab) { 15868 _cimg_get_label_test(x-1,y); 15869 if (flag) { 15870 const unsigned int lold = res(x-1,y), *const cptr = res.data(x,y); 15871 for (unsigned int *ptr = res._data; ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab; 15872 } 15873 } 15874 } 15875 } 15876 if (x && !done) { 15877 _cimg_get_label_test(x-1,y); 15878 if (flag) { res(x,y) = res(x-1,y); done = true; } 15879 } 15880 if (!done) res(x,y) = label++; 15881 } 15882 for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) { 15883 bool done = false; 15884 if (y<H1) { 15885 _cimg_get_label_test(x,y+1); 15886 if (flag) { 15887 const unsigned int lab = (res(x,y) = res(x,y+1)); 15888 done = true; 15889 if (x<W1 && res(x+1,y)!=lab) { 15890 _cimg_get_label_test(x+1,y); 15891 if (flag) { 15892 const unsigned int lold = res(x+1,y), *const cptr = res.data(x,y); 15893 for (unsigned int *ptr = res._data+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab; 15894 } 15895 } 15896 } 15897 } 15898 if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; } 15899 } 15900 const unsigned int lab0 = res.max()+1; 15901 label = lab0; 15902 cimg_foroff(res,off) { // Relabel regions 15903 const unsigned int lab = res[off]; 15904 if (lab<lab0) { cimg_for(res,ptrd,unsigned int) if (*ptrd==lab) *ptrd = label; ++label; } 15905 } 15906 return (res-=lab0); 15907 } 15908 15909 //@} 15910 //--------------------------------- 15911 // 15912 //! \name Color Base Management 15913 //@{ 15914 //--------------------------------- 15915 15916 //! Return a default indexed color palette with 256 (R,G,B) entries. 15917 /** 15918 \return An instance of a default color palette with 256 (R,G,B) colors. 15919 \note This color palette is particularly used by %CImg when displaying images on 256 colors displays. 15920 It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding 15921 (i.e 8 levels for the Red and Green and 4 levels for the Blue). 15922 \code 15923 CImg<float>::default_LUT256().display(); 15924 \endcode 15925 \image html ref_default_LUT256.jpg 15926 **/ 15927 static CImg<Tuchar> default_LUT256() { 15928 static CImg<Tuchar> palette; 15929 if (!palette) { 15930 palette.assign(1,256,1,3); 15931 for (unsigned int index = 0, r = 16; r<256; r+=32) 15932 for (unsigned int g = 16; g<256; g+=32) 15933 for (unsigned int b = 32; b<256; b+=64) { 15934 palette(0,index,0) = (Tuchar)r; 15935 palette(0,index,1) = (Tuchar)g; 15936 palette(0,index++,2) = (Tuchar)b; 15937 } 15938 } 15939 return palette; 15940 } 15941 15942 //! Return a rainbow indexed color palette with 256 (R,G,B) entries. 15943 /** 15944 \return An instance of a rainbow color palette with 256 (R,G,B) colors. 15945 \code 15946 CImg<float>::rainbow_LUT256().display(); 15947 \endcode 15948 \image html ref_rainbow_LUT256.jpg 15949 **/ 15950 static CImg<Tuchar> rainbow_LUT256() { 15951 static CImg<Tuchar> palette; 15952 if (!palette) { 15953 CImg<Tint> tmp(1,256,1,3,1); 15954 tmp.get_shared_channel(0).sequence(0,359); 15955 palette = tmp.HSVtoRGB(); 15956 } 15957 return palette; 15958 } 15959 15960 //! Return a contrasted indexed color palette with 256 (R,G,B) entries. 15961 /** 15962 \return An instance of a contrasted color palette with 256 (R,G,B) colors. 15963 \code 15964 CImg<float>::contrast_LUT256().display(); 15965 \endcode 15966 \image html ref_contrast_LUT256.jpg 15967 **/ 15968 static CImg<Tuchar> contrast_LUT256() { 15969 static const unsigned char pal[] = { 15970 217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226, 15971 17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119, 15972 238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20, 15973 233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74, 15974 81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219, 15975 1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12, 15976 87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0, 15977 223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32, 15978 233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4, 15979 137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224, 15980 4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247, 15981 11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246, 15982 0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10, 15983 141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143, 15984 116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244, 15985 255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0, 15986 235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251, 15987 129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30, 15988 243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215, 15989 95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3, 15990 141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174, 15991 154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87, 15992 33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21, 15993 23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 }; 15994 static const CImg<Tuchar> palette(pal,1,256,1,3,false); 15995 return palette; 15996 } 15997 15998 //! Convert color pixels from (R,G,B) to (H,S,V). 15999 CImg<T>& RGBtoHSV() { 16000 if (_spectrum!=3) 16001 throw CImgInstanceException(_cimg_instance 16002 "RGBtoHSV() : Instance is not a RGB image.", 16003 cimg_instance); 16004 16005 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16006 for (unsigned int N = _width*_height*_depth; N; --N) { 16007 const Tfloat 16008 R = (Tfloat)*p1, 16009 G = (Tfloat)*p2, 16010 B = (Tfloat)*p3, 16011 nR = (R<0?0:(R>255?255:R))/255, 16012 nG = (G<0?0:(G>255?255:G))/255, 16013 nB = (B<0?0:(B>255?255:B))/255, 16014 m = cimg::min(nR,nG,nB), 16015 M = cimg::max(nR,nG,nB); 16016 Tfloat H = 0, S = 0; 16017 if (M!=m) { 16018 const Tfloat 16019 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)), 16020 i = (Tfloat)((nR==m)?3:((nG==m)?5:1)); 16021 H = (i-f/(M-m)); 16022 if (H>=6) H-=6; 16023 H*=60; 16024 S = (M-m)/M; 16025 } 16026 *(p1++) = (T)H; 16027 *(p2++) = (T)S; 16028 *(p3++) = (T)M; 16029 } 16030 return *this; 16031 } 16032 16033 CImg<Tfloat> get_RGBtoHSV() const { 16034 return CImg<Tfloat>(*this,false).RGBtoHSV(); 16035 } 16036 16037 //! Convert color pixels from (H,S,V) to (R,G,B). 16038 CImg<T>& HSVtoRGB() { 16039 if (_spectrum!=3) 16040 throw CImgInstanceException(_cimg_instance 16041 "HSVtoRGB() : Instance is not a HSV image.", 16042 cimg_instance); 16043 16044 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16045 for (unsigned int N = _width*_height*_depth; N; --N) { 16046 Tfloat 16047 H = (Tfloat)*p1, 16048 S = (Tfloat)*p2, 16049 V = (Tfloat)*p3, 16050 R = 0, G = 0, B = 0; 16051 if (H==0 && S==0) R = G = B = V; 16052 else { 16053 H/=60; 16054 const int i = (int)std::floor(H); 16055 const Tfloat 16056 f = (i&1)?(H - i):(1 - H + i), 16057 m = V*(1 - S), 16058 n = V*(1 - S*f); 16059 switch (i) { 16060 case 6 : 16061 case 0 : R = V; G = n; B = m; break; 16062 case 1 : R = n; G = V; B = m; break; 16063 case 2 : R = m; G = V; B = n; break; 16064 case 3 : R = m; G = n; B = V; break; 16065 case 4 : R = n; G = m; B = V; break; 16066 case 5 : R = V; G = m; B = n; break; 16067 } 16068 } 16069 R*=255; G*=255; B*=255; 16070 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16071 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16072 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16073 } 16074 return *this; 16075 } 16076 16077 CImg<Tuchar> get_HSVtoRGB() const { 16078 return CImg<Tuchar>(*this,false).HSVtoRGB(); 16079 } 16080 16081 //! Convert color pixels from (R,G,B) to (H,S,L). 16082 CImg<T>& RGBtoHSL() { 16083 if (_spectrum!=3) 16084 throw CImgInstanceException(_cimg_instance 16085 "RGBtoHSL() : Instance is not a RGB image.", 16086 cimg_instance); 16087 16088 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16089 for (unsigned int N = _width*_height*_depth; N; --N) { 16090 const Tfloat 16091 R = (Tfloat)*p1, 16092 G = (Tfloat)*p2, 16093 B = (Tfloat)*p3, 16094 nR = (R<0?0:(R>255?255:R))/255, 16095 nG = (G<0?0:(G>255?255:G))/255, 16096 nB = (B<0?0:(B>255?255:B))/255, 16097 m = cimg::min(nR,nG,nB), 16098 M = cimg::max(nR,nG,nB), 16099 L = (m + M)/2; 16100 Tfloat H = 0, S = 0; 16101 if (M==m) H = S = 0; 16102 else { 16103 const Tfloat 16104 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)), 16105 i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f); 16106 H = (i-f/(M-m)); 16107 if (H>=6) H-=6; 16108 H*=60; 16109 S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m)); 16110 } 16111 *(p1++) = (T)H; 16112 *(p2++) = (T)S; 16113 *(p3++) = (T)L; 16114 } 16115 return *this; 16116 } 16117 16118 CImg<Tfloat> get_RGBtoHSL() const { 16119 return CImg< Tfloat>(*this,false).RGBtoHSL(); 16120 } 16121 16122 //! Convert color pixels from (H,S,L) to (R,G,B). 16123 CImg<T>& HSLtoRGB() { 16124 if (_spectrum!=3) 16125 throw CImgInstanceException(_cimg_instance 16126 "HSLtoRGB() : Instance is not a HSL image.", 16127 cimg_instance); 16128 16129 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16130 for (unsigned int N = _width*_height*_depth; N; --N) { 16131 const Tfloat 16132 H = (Tfloat)*p1, 16133 S = (Tfloat)*p2, 16134 L = (Tfloat)*p3, 16135 q = 2*L<1?L*(1+S):(L+S-L*S), 16136 p = 2*L-q, 16137 h = H/360, 16138 tr = h + 1.0f/3, 16139 tg = h, 16140 tb = h - 1.0f/3, 16141 ntr = tr<0?tr+1:(tr>1?tr-1:tr), 16142 ntg = tg<0?tg+1:(tg>1?tg-1:tg), 16143 ntb = tb<0?tb+1:(tb>1?tb-1:tb), 16144 R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p))), 16145 G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p))), 16146 B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p))); 16147 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16148 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16149 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16150 } 16151 return *this; 16152 } 16153 16154 CImg<Tuchar> get_HSLtoRGB() const { 16155 return CImg<Tuchar>(*this,false).HSLtoRGB(); 16156 } 16157 16158 //! Convert color pixels from (R,G,B) to (H,S,I). 16159 //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. 16160 CImg<T>& RGBtoHSI() { 16161 if (_spectrum!=3) 16162 throw CImgInstanceException(_cimg_instance 16163 "RGBtoHSI() : Instance is not a RGB image.", 16164 cimg_instance); 16165 16166 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16167 for (unsigned int N = _width*_height*_depth; N; --N) { 16168 const Tfloat 16169 R = (Tfloat)*p1, 16170 G = (Tfloat)*p2, 16171 B = (Tfloat)*p3, 16172 nR = (R<0?0:(R>255?255:R))/255, 16173 nG = (G<0?0:(G>255?255:G))/255, 16174 nB = (B<0?0:(B>255?255:B))/255, 16175 m = cimg::min(nR,nG,nB), 16176 theta = (Tfloat)(std::acos(0.5f*((nR-nG)+(nR-nB))/std::sqrt(std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::PI), 16177 sum = nR + nG + nB; 16178 Tfloat H = 0, S = 0, I = 0; 16179 if (theta>0) H = (nB<=nG)?theta:360-theta; 16180 if (sum>0) S = 1 - 3/sum*m; 16181 I = sum/3; 16182 *(p1++) = (T)H; 16183 *(p2++) = (T)S; 16184 *(p3++) = (T)I; 16185 } 16186 return *this; 16187 } 16188 16189 CImg<Tfloat> get_RGBtoHSI() const { 16190 return CImg<Tfloat>(*this,false).RGBtoHSI(); 16191 } 16192 16193 //! Convert color pixels from (H,S,I) to (R,G,B). 16194 CImg<T>& HSItoRGB() { 16195 if (_spectrum!=3) 16196 throw CImgInstanceException(_cimg_instance 16197 "HSItoRGB() : Instance is not a HSI image.", 16198 cimg_instance); 16199 16200 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16201 for (unsigned int N = _width*_height*_depth; N; --N) { 16202 Tfloat 16203 H = (Tfloat)*p1, 16204 S = (Tfloat)*p2, 16205 I = (Tfloat)*p3, 16206 a = I*(1-S), 16207 R = 0, G = 0, B = 0; 16208 if (H<120) { 16209 B = a; 16210 R = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); 16211 G = 3*I-(R+B); 16212 } else if (H<240) { 16213 H-=120; 16214 R = a; 16215 G = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); 16216 B = 3*I-(R+G); 16217 } else { 16218 H-=240; 16219 G = a; 16220 B = (Tfloat)(I*(1+S*std::cos(H*cimg::PI/180)/std::cos((60-H)*cimg::PI/180))); 16221 R = 3*I-(G+B); 16222 } 16223 R*=255; G*=255; B*=255; 16224 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16225 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16226 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16227 } 16228 return *this; 16229 } 16230 16231 CImg<Tfloat> get_HSItoRGB() const { 16232 return CImg< Tuchar>(*this,false).HSItoRGB(); 16233 } 16234 16235 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr). 16236 CImg<T>& RGBtoYCbCr() { 16237 if (_spectrum!=3) 16238 throw CImgInstanceException(_cimg_instance 16239 "RGBtoYCbCr() : Instance is not a RGB image.", 16240 cimg_instance); 16241 16242 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16243 for (unsigned int N = _width*_height*_depth; N; --N) { 16244 const Tfloat 16245 R = (Tfloat)*p1, 16246 G = (Tfloat)*p2, 16247 B = (Tfloat)*p3, 16248 Y = (66*R + 129*G + 25*B + 128)/256 + 16, 16249 Cb = (-38*R - 74*G + 112*B + 128)/256 + 128, 16250 Cr = (112*R - 94*G - 18*B + 128)/256 + 128; 16251 *(p1++) = (T)(Y<0?0:(Y>255?255:Y)); 16252 *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb)); 16253 *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr)); 16254 } 16255 return *this; 16256 } 16257 16258 CImg<Tuchar> get_RGBtoYCbCr() const { 16259 return CImg<Tuchar>(*this,false).RGBtoYCbCr(); 16260 } 16261 16262 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr). 16263 CImg<T>& YCbCrtoRGB() { 16264 if (_spectrum!=3) 16265 throw CImgInstanceException(_cimg_instance 16266 "YCbCrtoRGB() : Instance is not a YCbCr image.", 16267 cimg_instance); 16268 16269 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16270 for (unsigned int N = _width*_height*_depth; N; --N) { 16271 const Tfloat 16272 Y = (Tfloat)*p1 - 16, 16273 Cb = (Tfloat)*p2 - 128, 16274 Cr = (Tfloat)*p3 - 128, 16275 R = (298*Y + 409*Cr + 128)/256, 16276 G = (298*Y - 100*Cb - 208*Cr + 128)/256, 16277 B = (298*Y + 516*Cb + 128)/256; 16278 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16279 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16280 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16281 } 16282 return *this; 16283 } 16284 16285 CImg<Tuchar> get_YCbCrtoRGB() const { 16286 return CImg<Tuchar>(*this,false).YCbCrtoRGB(); 16287 } 16288 16289 //! Convert color pixels from (R,G,B) to (Y,U,V). 16290 CImg<T>& RGBtoYUV() { 16291 if (_spectrum!=3) 16292 throw CImgInstanceException(_cimg_instance 16293 "RGBtoYUV() : Instance is not a RGB image.", 16294 cimg_instance); 16295 16296 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16297 for (unsigned int N = _width*_height*_depth; N; --N) { 16298 const Tfloat 16299 R = (Tfloat)*p1/255, 16300 G = (Tfloat)*p2/255, 16301 B = (Tfloat)*p3/255, 16302 Y = 0.299f*R + 0.587f*G + 0.114f*B; 16303 *(p1++) = (T)Y; 16304 *(p2++) = (T)(0.492f*(B-Y)); 16305 *(p3++) = (T)(0.877*(R-Y)); 16306 } 16307 return *this; 16308 } 16309 16310 CImg<Tfloat> get_RGBtoYUV() const { 16311 return CImg<Tfloat>(*this,false).RGBtoYUV(); 16312 } 16313 16314 //! Convert color pixels from (Y,U,V) to (R,G,B). 16315 CImg<T>& YUVtoRGB() { 16316 if (_spectrum!=3) 16317 throw CImgInstanceException(_cimg_instance 16318 "YUVtoRGB() : Instance is not a YUV image.", 16319 cimg_instance); 16320 16321 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16322 for (unsigned int N = _width*_height*_depth; N; --N) { 16323 const Tfloat 16324 Y = (Tfloat)*p1, 16325 U = (Tfloat)*p2, 16326 V = (Tfloat)*p3, 16327 R = (Y + 1.140f*V)*255, 16328 G = (Y - 0.395f*U - 0.581f*V)*255, 16329 B = (Y + 2.032f*U)*255; 16330 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16331 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16332 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16333 } 16334 return *this; 16335 } 16336 16337 CImg<Tuchar> get_YUVtoRGB() const { 16338 return CImg< Tuchar>(*this,false).YUVtoRGB(); 16339 } 16340 16341 //! Convert color pixels from (R,G,B) to (C,M,Y). 16342 CImg<T>& RGBtoCMY() { 16343 if (_spectrum!=3) 16344 throw CImgInstanceException(_cimg_instance 16345 "RGBtoCMY() : Instance is not a RGB image.", 16346 cimg_instance); 16347 16348 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16349 for (unsigned int N = _width*_height*_depth; N; --N) { 16350 const Tfloat 16351 R = (Tfloat)*p1, 16352 G = (Tfloat)*p2, 16353 B = (Tfloat)*p3, 16354 C = 255 - R, 16355 M = 255 - G, 16356 Y = 255 - B; 16357 *(p1++) = (T)(C<0?0:(C>255?255:C)); 16358 *(p2++) = (T)(M<0?0:(M>255?255:M)); 16359 *(p3++) = (T)(Y<0?0:(Y>255?255:Y)); 16360 } 16361 return *this; 16362 } 16363 16364 CImg<Tuchar> get_RGBtoCMY() const { 16365 return CImg<Tfloat>(*this,false).RGBtoCMY(); 16366 } 16367 16368 //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space. 16369 CImg<T>& CMYtoRGB() { 16370 if (_spectrum!=3) 16371 throw CImgInstanceException(_cimg_instance 16372 "CMYtoRGB() : Instance is not a CMY image.", 16373 cimg_instance); 16374 16375 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16376 for (unsigned int N = _width*_height*_depth; N; --N) { 16377 const Tfloat 16378 C = (Tfloat)*p1, 16379 M = (Tfloat)*p2, 16380 Y = (Tfloat)*p3, 16381 R = 255 - C, 16382 G = 255 - M, 16383 B = 255 - Y; 16384 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16385 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16386 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16387 } 16388 return *this; 16389 } 16390 16391 CImg<Tuchar> get_CMYtoRGB() const { 16392 return CImg<Tuchar>(*this,false).CMYtoRGB(); 16393 } 16394 16395 //! Convert color pixels from (C,M,Y) to (C,M,Y,K). 16396 CImg<T>& CMYtoCMYK() { 16397 return get_CMYtoCMYK().move_to(*this); 16398 } 16399 16400 CImg<Tuchar> get_CMYtoCMYK() const { 16401 if (_spectrum!=3) 16402 throw CImgInstanceException(_cimg_instance 16403 "CMYtoCMYK() : Instance is not a CMY image.", 16404 cimg_instance); 16405 16406 CImg<Tfloat> res(_width,_height,_depth,4); 16407 const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2); 16408 Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3); 16409 for (unsigned int N = _width*_height*_depth; N; --N) { 16410 Tfloat 16411 C = (Tfloat)*(ps1++), 16412 M = (Tfloat)*(ps2++), 16413 Y = (Tfloat)*(ps3++), 16414 K = cimg::min(C,M,Y); 16415 if (K>=255) C = M = Y = 0; 16416 else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; } 16417 *(pd1++) = (Tfloat)(C<0?0:(C>255?255:C)); 16418 *(pd2++) = (Tfloat)(M<0?0:(M>255?255:M)); 16419 *(pd3++) = (Tfloat)(Y<0?0:(Y>255?255:Y)); 16420 *(pd4++) = (Tfloat)(K<0?0:(K>255?255:K)); 16421 } 16422 return res; 16423 } 16424 16425 //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space. 16426 CImg<T>& CMYKtoCMY() { 16427 return get_CMYKtoCMY().move_to(*this); 16428 } 16429 16430 CImg<Tfloat> get_CMYKtoCMY() const { 16431 if (_spectrum!=4) 16432 throw CImgInstanceException(_cimg_instance 16433 "CMYKtoCMY() : Instance is not a CMYK image.", 16434 cimg_instance); 16435 16436 CImg<Tfloat> res(_width,_height,_depth,3); 16437 const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3); 16438 Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2); 16439 for (unsigned int N = _width*_height*_depth; N; --N) { 16440 const Tfloat 16441 C = (Tfloat)*(ps1++), 16442 M = (Tfloat)*(ps2++), 16443 Y = (Tfloat)*(ps3++), 16444 K = (Tfloat)*(ps4++), 16445 K1 = 1 - K/255, 16446 nC = C*K1 + K, 16447 nM = M*K1 + K, 16448 nY = Y*K1 + K; 16449 *(pd1++) = (Tfloat)(nC<0?0:(nC>255?255:nC)); 16450 *(pd2++) = (Tfloat)(nM<0?0:(nM>255?255:nM)); 16451 *(pd3++) = (Tfloat)(nY<0?0:(nY>255?255:nY)); 16452 } 16453 return res; 16454 } 16455 16456 //! Convert color pixels from (R,G,B) to (X,Y,Z)_709. 16457 CImg<T>& RGBtoXYZ() { 16458 if (_spectrum!=3) 16459 throw CImgInstanceException(_cimg_instance 16460 "RGBtoXYZ() : Instance is not a RGB image.", 16461 cimg_instance); 16462 16463 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16464 for (unsigned int N = _width*_height*_depth; N; --N) { 16465 const Tfloat 16466 R = (Tfloat)*p1/255, 16467 G = (Tfloat)*p2/255, 16468 B = (Tfloat)*p3/255; 16469 *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B); 16470 *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B); 16471 *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B); 16472 } 16473 return *this; 16474 } 16475 16476 CImg<Tfloat> get_RGBtoXYZ() const { 16477 return CImg<Tfloat>(*this,false).RGBtoXYZ(); 16478 } 16479 16480 //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space. 16481 CImg<T>& XYZtoRGB() { 16482 if (_spectrum!=3) 16483 throw CImgInstanceException(_cimg_instance 16484 "XYZtoRGB() : Instance is not a XYZ image.", 16485 cimg_instance); 16486 16487 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16488 for (unsigned int N = _width*_height*_depth; N; --N) { 16489 const Tfloat 16490 X = (Tfloat)*p1*255, 16491 Y = (Tfloat)*p2*255, 16492 Z = (Tfloat)*p3*255, 16493 R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z, 16494 G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z, 16495 B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z; 16496 *(p1++) = (T)(R<0?0:(R>255?255:R)); 16497 *(p2++) = (T)(G<0?0:(G>255?255:G)); 16498 *(p3++) = (T)(B<0?0:(B>255?255:B)); 16499 } 16500 return *this; 16501 } 16502 16503 CImg<Tuchar> get_XYZtoRGB() const { 16504 return CImg<Tuchar>(*this,false).XYZtoRGB(); 16505 } 16506 16507 //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space. 16508 CImg<T>& XYZtoLab() { 16509 #define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116)) 16510 16511 if (_spectrum!=3) 16512 throw CImgInstanceException(_cimg_instance 16513 "XYZtoLab() : Instance is not a XYZ image.", 16514 cimg_instance); 16515 16516 const Tfloat 16517 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f), 16518 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f), 16519 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f); 16520 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16521 for (unsigned int N = _width*_height*_depth; N; --N) { 16522 const Tfloat 16523 X = (Tfloat)*p1, 16524 Y = (Tfloat)*p2, 16525 Z = (Tfloat)*p3, 16526 XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn, 16527 fX = (Tfloat)_cimg_Labf(XXn), 16528 fY = (Tfloat)_cimg_Labf(YYn), 16529 fZ = (Tfloat)_cimg_Labf(ZZn); 16530 *(p1++) = (T)(116*fY - 16); 16531 *(p2++) = (T)(500*(fX - fY)); 16532 *(p3++) = (T)(200*(fY - fZ)); 16533 } 16534 return *this; 16535 } 16536 16537 CImg<Tfloat> get_XYZtoLab() const { 16538 return CImg<Tfloat>(*this,false).XYZtoLab(); 16539 } 16540 16541 //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space. 16542 CImg<T>& LabtoXYZ() { 16543 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f)) 16544 16545 if (_spectrum!=3) 16546 throw CImgInstanceException(_cimg_instance 16547 "LabtoXYZ() : Instance is not a Lab image.", 16548 cimg_instance); 16549 16550 const Tfloat 16551 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f), 16552 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f), 16553 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f); 16554 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16555 for (unsigned int N = _width*_height*_depth; N; --N) { 16556 const Tfloat 16557 L = (Tfloat)*p1, 16558 a = (Tfloat)*p2, 16559 b = (Tfloat)*p3, 16560 cY = (L + 16)/116, 16561 Y = (Tfloat)(Yn*_cimg_Labfi(cY)), 16562 pY = (Tfloat)std::pow(Y/Yn,(Tfloat)1/3), 16563 cX = a/500 + pY, 16564 X = Xn*cX*cX*cX, 16565 cZ = pY - b/200, 16566 Z = Zn*cZ*cZ*cZ; 16567 *(p1++) = (T)(X); 16568 *(p2++) = (T)(Y); 16569 *(p3++) = (T)(Z); 16570 } 16571 return *this; 16572 } 16573 16574 CImg<Tfloat> get_LabtoXYZ() const { 16575 return CImg<Tfloat>(*this,false).LabtoXYZ(); 16576 } 16577 16578 //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space. 16579 CImg<T>& XYZtoxyY() { 16580 if (_spectrum!=3) 16581 throw CImgInstanceException(_cimg_instance 16582 "XYZtoxyY() : Instance is not a XYZ image.", 16583 cimg_instance); 16584 16585 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16586 for (unsigned int N = _width*_height*_depth; N; --N) { 16587 const Tfloat 16588 X = (Tfloat)*p1, 16589 Y = (Tfloat)*p2, 16590 Z = (Tfloat)*p3, 16591 sum = (X+Y+Z), 16592 nsum = sum>0?sum:1; 16593 *(p1++) = (T)(X/nsum); 16594 *(p2++) = (T)(Y/nsum); 16595 *(p3++) = (T)Y; 16596 } 16597 return *this; 16598 } 16599 16600 CImg<Tfloat> get_XYZtoxyY() const { 16601 return CImg<Tfloat>(*this,false).XYZtoxyY(); 16602 } 16603 16604 //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space. 16605 CImg<T>& xyYtoXYZ() { 16606 if (_spectrum!=3) 16607 throw CImgInstanceException(_cimg_instance 16608 "xyYtoXYZ() : Instance is not a xyY image.", 16609 cimg_instance); 16610 16611 T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); 16612 for (unsigned int N = _width*_height*_depth; N; --N) { 16613 const Tfloat 16614 px = (Tfloat)*p1, 16615 py = (Tfloat)*p2, 16616 Y = (Tfloat)*p3, 16617 ny = py>0?py:1; 16618 *(p1++) = (T)(px*Y/ny); 16619 *(p2++) = (T)Y; 16620 *(p3++) = (T)((1-px-py)*Y/ny); 16621 } 16622 return *this; 16623 } 16624 16625 CImg<Tfloat> get_xyYtoXYZ() const { 16626 return CImg<Tfloat>(*this,false).xyYtoXYZ(); 16627 } 16628 16629 //! Convert a (R,G,B) image to a (L,a,b) one. 16630 CImg<T>& RGBtoLab() { 16631 return RGBtoXYZ().XYZtoLab(); 16632 } 16633 16634 CImg<Tfloat> get_RGBtoLab() const { 16635 return CImg<Tfloat>(*this,false).RGBtoLab(); 16636 } 16637 16638 //! Convert a (L,a,b) image to a (R,G,B) one. 16639 CImg<T>& LabtoRGB() { 16640 return LabtoXYZ().XYZtoRGB(); 16641 } 16642 16643 CImg<Tuchar> get_LabtoRGB() const { 16644 return CImg<Tuchar>(*this,false).LabtoRGB(); 16645 } 16646 16647 //! Convert a (R,G,B) image to a (x,y,Y) one. 16648 CImg<T>& RGBtoxyY() { 16649 return RGBtoXYZ().XYZtoxyY(); 16650 } 16651 16652 CImg<Tfloat> get_RGBtoxyY() const { 16653 return CImg<Tfloat>(*this,false).RGBtoxyY(); 16654 } 16655 16656 //! Convert a (x,y,Y) image to a (R,G,B) one. 16657 CImg<T>& xyYtoRGB() { 16658 return xyYtoXYZ().XYZtoRGB(); 16659 } 16660 16661 CImg<Tuchar> get_xyYtoRGB() const { 16662 return CImg<Tuchar>(*this,false).xyYtoRGB(); 16663 } 16664 16665 //! Convert a (R,G,B) image to a (C,M,Y,K) one. 16666 CImg<T>& RGBtoCMYK() { 16667 return RGBtoCMY().CMYtoCMYK(); 16668 } 16669 16670 CImg<Tfloat> get_RGBtoCMYK() const { 16671 return CImg<Tfloat>(*this,false).RGBtoCMYK(); 16672 } 16673 16674 //! Convert a (C,M,Y,K) image to a (R,G,B) one. 16675 CImg<T>& CMYKtoRGB() { 16676 return CMYKtoCMY().CMYtoRGB(); 16677 } 16678 16679 CImg<Tuchar> get_CMYKtoRGB() const { 16680 return CImg<Tuchar>(*this,false).CMYKtoRGB(); 16681 } 16682 16683 //! Convert a (R,G,B) image to a Bayer-coded representation. 16684 /** 16685 \note First (upper-left) pixel if the red component of the pixel color. 16686 **/ 16687 CImg<T>& RGBtoBayer() { 16688 return get_RGBtoBayer().move_to(*this); 16689 } 16690 16691 CImg<T> get_RGBtoBayer() const { 16692 if (_spectrum!=3) 16693 throw CImgInstanceException(_cimg_instance 16694 "RGBtoBayer() : Instance is not a RGB image.", 16695 cimg_instance); 16696 16697 CImg<T> res(_width,_height,_depth,1); 16698 const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); 16699 T *ptrd = res._data; 16700 cimg_forXYZ(*this,x,y,z) { 16701 if (y%2) { 16702 if (x%2) *(ptrd++) = *ptr_b; 16703 else *(ptrd++) = *ptr_g; 16704 } else { 16705 if (x%2) *(ptrd++) = *ptr_g; 16706 else *(ptrd++) = *ptr_r; 16707 } 16708 ++ptr_r; ++ptr_g; ++ptr_b; 16709 } 16710 return res; 16711 } 16712 16713 //! Convert a Bayer-coded image to a (R,G,B) color image. 16714 CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) { 16715 return get_BayertoRGB(interpolation_type).move_to(*this); 16716 } 16717 16718 CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const { 16719 if (_spectrum!=1) 16720 throw CImgInstanceException(_cimg_instance 16721 "BayertoRGB() : Instance is not a Bayer image.", 16722 cimg_instance); 16723 16724 CImg<Tuchar> res(_width,_height,_depth,3); 16725 CImg_3x3(I,T); 16726 Tuchar *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2); 16727 switch (interpolation_type) { 16728 case 3 : { // Edge-directed 16729 CImg_3x3(R,T); 16730 CImg_3x3(G,T); 16731 CImg_3x3(B,T); 16732 cimg_forXYZ(*this,x,y,z) { 16733 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<width()-1?x+1:x-1, _n1y = y<height()-1?y+1:y-1; 16734 cimg_get3x3(*this,x,y,z,0,I,T); 16735 if (y%2) { 16736 if (x%2) { 16737 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta); 16738 *ptr_g = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy))); 16739 } else *ptr_g = (Tuchar)Icc; 16740 } else { 16741 if (x%2) *ptr_g = (Tuchar)Icc; 16742 else { 16743 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta); 16744 *ptr_g = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy))); 16745 } 16746 } 16747 ++ptr_g; 16748 } 16749 cimg_forXYZ(*this,x,y,z) { 16750 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<width()-1?x+1:x-1, _n1y = y<height()-1?y+1:y-1; 16751 cimg_get3x3(*this,x,y,z,0,I,T); 16752 cimg_get3x3(res,x,y,z,1,G,T); 16753 if (y%2) { 16754 if (x%2) *ptr_b = (Tuchar)Icc; 16755 else { *ptr_r = (Tuchar)((Icn+Icp)/2); *ptr_b = (Tuchar)((Inc+Ipc)/2); } 16756 } else { 16757 if (x%2) { *ptr_r = (Tuchar)((Inc+Ipc)/2); *ptr_b = (Tuchar)((Icn+Icp)/2); } 16758 else *ptr_r = (Tuchar)Icc; 16759 } 16760 ++ptr_r; ++ptr_b; 16761 } 16762 ptr_r = res.data(0,0,0,0); 16763 ptr_g = res.data(0,0,0,1); 16764 ptr_b = res.data(0,0,0,2); 16765 cimg_forXYZ(*this,x,y,z) { 16766 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<width()-1?x+1:x-1, _n1y = y<height()-1?y+1:y-1; 16767 cimg_get3x3(res,x,y,z,0,R,T); 16768 cimg_get3x3(res,x,y,z,1,G,T); 16769 cimg_get3x3(res,x,y,z,2,B,T); 16770 if (y%2) { 16771 if (x%2) { 16772 const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta); 16773 *ptr_r = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy))); 16774 } 16775 } else { 16776 if (!(x%2)) { 16777 const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta); 16778 *ptr_b = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy))); 16779 } 16780 } 16781 ++ptr_r; ++ptr_g; ++ptr_b; 16782 } 16783 } break; 16784 case 2 : { // Linear interpolation 16785 cimg_forXYZ(*this,x,y,z) { 16786 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<width()-1?x+1:x-1, _n1y = y<height()-1?y+1:y-1; 16787 cimg_get3x3(*this,x,y,z,0,I,T); 16788 if (y%2) { 16789 if (x%2) { *ptr_r = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *ptr_g = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *ptr_b = (Tuchar)Icc; } 16790 else { *ptr_r = (Tuchar)((Icp+Icn)/2); *ptr_g = (Tuchar)Icc; *ptr_b = (Tuchar)((Inc+Ipc)/2); } 16791 } else { 16792 if (x%2) { *ptr_r = (Tuchar)((Ipc+Inc)/2); *ptr_g = (Tuchar)Icc; *ptr_b = (Tuchar)((Icn+Icp)/2); } 16793 else { *ptr_r = (Tuchar)Icc; *ptr_g = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *ptr_b = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); } 16794 } 16795 ++ptr_r; ++ptr_g; ++ptr_b; 16796 } 16797 } break; 16798 case 1 : { // Nearest neighbor interpolation 16799 cimg_forXYZ(*this,x,y,z) { 16800 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<width()-1?x+1:x-1, _n1y = y<height()-1?y+1:y-1; 16801 cimg_get3x3(*this,x,y,z,0,I,T); 16802 if (y%2) { 16803 if (x%2) { *ptr_r = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *ptr_g = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *ptr_b = (Tuchar)Icc; } 16804 else { *ptr_r = (Tuchar)cimg::min(Icn,Icp); *ptr_g = (Tuchar)Icc; *ptr_b = (Tuchar)cimg::min(Inc,Ipc); } 16805 } else { 16806 if (x%2) { *ptr_r = (Tuchar)cimg::min(Inc,Ipc); *ptr_g = (Tuchar)Icc; *ptr_b = (Tuchar)cimg::min(Icn,Icp); } 16807 else { *ptr_r = (Tuchar)Icc; *ptr_g = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *ptr_b = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); } 16808 } 16809 ++ptr_r; ++ptr_g; ++ptr_b; 16810 } 16811 } break; 16812 default : { // 0-filling interpolation 16813 const T *ptrs = _data; 16814 res.fill(0); 16815 cimg_forXYZ(*this,x,y,z) { 16816 const T val = *(ptrs++); 16817 if (y%2) { if (x%2) *ptr_b = val; else *ptr_g = val; } else { if (x%2) *ptr_g = val; else *ptr_r = val; } 16818 ++ptr_r; ++ptr_g; ++ptr_b; 16819 } 16820 } 16821 } 16822 return res; 16823 } 16824 16825 //@} 16826 //------------------------------------------ 16827 // 16828 //! \name Geometric / Spatial Manipulation 16829 //@{ 16830 //------------------------------------------ 16831 16832 static float _cimg_lanczos(const float x) { 16833 if (x<=-2 || x>=2) return 0; 16834 const float a = (float)cimg::PI*x, b = 0.5f*a; 16835 return (float)(x?std::sin(a)*std::sin(b)/(a*b):1); 16836 } 16837 16838 //! Resize an image. 16839 /** 16840 \param size_x Number of columns (new size along the X-axis). 16841 \param size_y Number of rows (new size along the Y-axis). 16842 \param size_z Number of slices (new size along the Z-axis). 16843 \param size_c Number of vector-channels (new size along the C-axis). 16844 \param interpolation_type Method of interpolation : 16845 - -1 = no interpolation : raw memory resizing. 16846 - 0 = no interpolation : additional space is filled according to \p border_condition. 16847 - 1 = nearest-neighbor interpolation. 16848 - 2 = moving average interpolation. 16849 - 3 = linear interpolation. 16850 - 4 = grid interpolation. 16851 - 5 = bicubic interpolation. 16852 - 6 = lanczos interpolation. 16853 \param border_conditions Border condition type. 16854 \param centering_x Set centering type (only if \p interpolation_type=0). 16855 \param centering_y Set centering type (only if \p interpolation_type=0). 16856 \param centering_z Set centering type (only if \p interpolation_type=0). 16857 \param centering_c Set centering type (only if \p interpolation_type=0). 16858 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). 16859 **/ 16860 CImg<T>& resize(const int size_x, const int size_y=-100, 16861 const int size_z=-100, const int size_c=-100, 16862 const int interpolation_type=1, const unsigned int border_conditions=0, 16863 const float centering_x = 0, const float centering_y = 0, 16864 const float centering_z = 0, const float centering_c = 0) { 16865 if (!size_x || !size_y || !size_z || !size_c) return assign(); 16866 const unsigned int 16867 _sx = (unsigned int)(size_x<0?-size_x*_width/100:size_x), 16868 _sy = (unsigned int)(size_y<0?-size_y*_height/100:size_y), 16869 _sz = (unsigned int)(size_z<0?-size_z*_depth/100:size_z), 16870 _sc = (unsigned int)(size_c<0?-size_c*_spectrum/100:size_c), 16871 sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1; 16872 if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return *this; 16873 if (is_empty()) return assign(sx,sy,sz,sc,0); 16874 if (interpolation_type==-1 && sx*sy*sz*sc==size()) { 16875 _width = sx; _height = sy; _depth = sz; _spectrum = sc; 16876 return *this; 16877 } 16878 return get_resize(sx,sy,sz,sc,interpolation_type,border_conditions,centering_x,centering_y,centering_z,centering_c).move_to(*this); 16879 } 16880 16881 CImg<T> get_resize(const int size_x, const int size_y = -100, 16882 const int size_z = -100, const int size_c = -100, 16883 const int interpolation_type=1, const unsigned int border_conditions=0, 16884 const float centering_x = 0, const float centering_y = 0, 16885 const float centering_z = 0, const float centering_c = 0) const { 16886 if (centering_x<0 || centering_x>1 || centering_y<0 || centering_y>1 || 16887 centering_z<0 || centering_z>1 || centering_c<0 || centering_c>1) 16888 throw CImgArgumentException(_cimg_instance 16889 "resize() : Specified centering arguments (%g,%g,%g,%g) are outside range [0,1].", 16890 cimg_instance, 16891 centering_x,centering_y,centering_z,centering_c); 16892 16893 if (!size_x || !size_y || !size_z || !size_c) return CImg<T>(); 16894 const unsigned int 16895 _sx = (unsigned int)(size_x<0?-size_x*_width/100:size_x), 16896 _sy = (unsigned int)(size_y<0?-size_y*_height/100:size_y), 16897 _sz = (unsigned int)(size_z<0?-size_z*_depth/100:size_z), 16898 _sc = (unsigned int)(size_c<0?-size_c*_spectrum/100:size_c), 16899 sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1; 16900 if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return +*this; 16901 if (is_empty()) return CImg<T>(sx,sy,sz,sc,0); 16902 16903 CImg<T> res; 16904 switch (interpolation_type) { 16905 16906 // Raw resizing. 16907 // 16908 case -1 : 16909 std::memcpy(res.assign(sx,sy,sz,sc,0)._data,_data,sizeof(T)*cimg::min(size(),sx*sy*sz*sc)); 16910 break; 16911 16912 // No interpolation. 16913 // 16914 case 0 : { 16915 const int 16916 xc = (int)(centering_x*((int)sx - width())), 16917 yc = (int)(centering_y*((int)sy - height())), 16918 zc = (int)(centering_z*((int)sz - depth())), 16919 cc = (int)(centering_c*((int)sc - spectrum())); 16920 16921 switch (border_conditions) { 16922 case 2 : { // Cyclic borders. 16923 res.assign(sx,sy,sz,sc); 16924 const int 16925 x0 = ((int)xc%width()) - width(), 16926 y0 = ((int)yc%height()) - height(), 16927 z0 = ((int)zc%depth()) - depth(), 16928 c0 = ((int)cc%spectrum()) - spectrum(); 16929 for (int c = c0; c<(int)sc; c+=spectrum()) 16930 for (int z = z0; z<(int)sz; z+=depth()) 16931 for (int y = y0; y<(int)sy; y+=height()) 16932 for (int x = x0; x<(int)sx; x+=width()) 16933 res.draw_image(x,y,z,c,*this); 16934 } break; 16935 case 1 : { // Neumann borders. 16936 res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this); 16937 CImg<T> sprite; 16938 if (xc>0) { // X-backward 16939 res.get_crop(xc,yc,zc,cc,xc,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); 16940 for (int x = xc-1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite); 16941 } 16942 if (xc+width()<(int)sx) { // X-forward 16943 res.get_crop(xc+width()-1,yc,zc,cc,xc+width()-1,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); 16944 for (int x = xc+width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite); 16945 } 16946 if (yc>0) { // Y-backward 16947 res.get_crop(0,yc,zc,cc,sx-1,yc,zc+depth()-1,cc+spectrum()-1).move_to(sprite); 16948 for (int y = yc-1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite); 16949 } 16950 if (yc+height()<(int)sy) { // Y-forward 16951 res.get_crop(0,yc+height()-1,zc,cc,sx-1,yc+height()-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); 16952 for (int y = yc+height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite); 16953 } 16954 if (zc>0) { // Z-backward 16955 res.get_crop(0,0,zc,cc,sx-1,sy-1,zc,cc+spectrum()-1).move_to(sprite); 16956 for (int z = zc-1; z>=0; --z) res.draw_image(0,0,z,cc,sprite); 16957 } 16958 if (zc+depth()<(int)sz) { // Z-forward 16959 res.get_crop(0,0,zc+depth()-1,cc,sx-1,sy-1,zc+depth()-1,cc+spectrum()-1).move_to(sprite); 16960 for (int z = zc+depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite); 16961 } 16962 if (cc>0) { // C-backward 16963 res.get_crop(0,0,0,cc,sx-1,sy-1,sz-1,cc).move_to(sprite); 16964 for (int c = cc-1; c>=0; --c) res.draw_image(0,0,0,c,sprite); 16965 } 16966 if (cc+spectrum()<(int)sc) { // C-forward 16967 res.get_crop(0,0,0,cc+spectrum()-1,sx-1,sy-1,sz-1,cc+spectrum()-1).move_to(sprite); 16968 for (int c = cc+spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); 16969 } 16970 } break; 16971 default : // Dirichlet borders. 16972 res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this); 16973 } 16974 break; 16975 } break; 16976 16977 // Nearest neighbor interpolation. 16978 // 16979 case 1 : { 16980 res.assign(sx,sy,sz,sc); 16981 CImg<uintT> off_x(sx), off_y(sy+1), off_z(sz+1), off_c(sc+1); 16982 unsigned int *poff_x, *poff_y, *poff_z, *poff_c, curr, old; 16983 const unsigned int wh = _width*_height, whd = _width*_height*_depth, sxy = sx*sy, sxyz = sx*sy*sz; 16984 poff_x = off_x._data; curr = 0; 16985 cimg_forX(res,x) { old = curr; curr = (x+1)*_width/sx; *(poff_x++) = (unsigned int)curr - (unsigned int)old; } 16986 poff_y = off_y._data; curr = 0; 16987 cimg_forY(res,y) { old = curr; curr = (y+1)*_height/sy; *(poff_y++) = _width*((unsigned int)curr - (unsigned int)old); } *poff_y = 0; 16988 poff_z = off_z._data; curr = 0; 16989 cimg_forZ(res,z) { old = curr; curr = (z+1)*_depth/sz; *(poff_z++) = wh*((unsigned int)curr - (unsigned int)old); } *poff_z = 0; 16990 poff_c = off_c._data; curr = 0; 16991 cimg_forC(res,c) { old = curr; curr = (c+1)*_spectrum/sc; *(poff_c++) = whd*((unsigned int)curr - (unsigned int)old); } *poff_c = 0; 16992 T *ptrd = res._data; 16993 const T* ptrv = _data; 16994 poff_c = off_c._data; 16995 for (unsigned int c = 0; c<sc; ) { 16996 const T *ptrz = ptrv; 16997 poff_z = off_z._data; 16998 for (unsigned int z = 0; z<sz; ) { 16999 const T *ptry = ptrz; 17000 poff_y = off_y._data; 17001 for (unsigned int y = 0; y<sy; ) { 17002 const T *ptrx = ptry; 17003 poff_x = off_x._data; 17004 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); } 17005 ++y; 17006 unsigned int dy = *(poff_y++); 17007 for (;!dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {} 17008 ptry+=dy; 17009 } 17010 ++z; 17011 unsigned int dz = *(poff_z++); 17012 for (;!dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {} 17013 ptrz+=dz; 17014 } 17015 ++c; 17016 unsigned int dc = *(poff_c++); 17017 for (;!dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {} 17018 ptrv+=dc; 17019 } 17020 } break; 17021 17022 // Moving average. 17023 // 17024 case 2 : { 17025 bool instance_first = true; 17026 if (sx!=_width) { 17027 CImg<Tfloat> tmp(sx,_height,_depth,_spectrum,0); 17028 for (unsigned int a = _width*sx, b = _width, c = sx, s = 0, t = 0; a; ) { 17029 const unsigned int d = cimg::min(b,c); 17030 a-=d; b-=d; c-=d; 17031 cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d; 17032 if (!b) { cimg_forYZC(tmp,y,z,v) tmp(t,y,z,v)/=_width; ++t; b = _width; } 17033 if (!c) { ++s; c = sx; } 17034 } 17035 tmp.move_to(res); 17036 instance_first = false; 17037 } 17038 if (sy!=_height) { 17039 CImg<Tfloat> tmp(sx,sy,_depth,_spectrum,0); 17040 for (unsigned int a = _height*sy, b = _height, c = sy, s = 0, t = 0; a; ) { 17041 const unsigned int d = cimg::min(b,c); 17042 a-=d; b-=d; c-=d; 17043 if (instance_first) cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d; 17044 else cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d; 17045 if (!b) { cimg_forXZC(tmp,x,z,v) tmp(x,t,z,v)/=_height; ++t; b = _height; } 17046 if (!c) { ++s; c = sy; } 17047 } 17048 tmp.move_to(res); 17049 instance_first = false; 17050 } 17051 if (sz!=_depth) { 17052 CImg<Tfloat> tmp(sx,sy,sz,_spectrum,0); 17053 for (unsigned int a = _depth*sz, b = _depth, c = sz, s = 0, t = 0; a; ) { 17054 const unsigned int d = cimg::min(b,c); 17055 a-=d; b-=d; c-=d; 17056 if (instance_first) cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d; 17057 else cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d; 17058 if (!b) { cimg_forXYC(tmp,x,y,v) tmp(x,y,t,v)/=_depth; ++t; b = _depth; } 17059 if (!c) { ++s; c = sz; } 17060 } 17061 tmp.move_to(res); 17062 instance_first = false; 17063 } 17064 if (sc!=_spectrum) { 17065 CImg<Tfloat> tmp(sx,sy,sz,sc,0); 17066 for (unsigned int a = _spectrum*sc, b = _spectrum, c = sc, s = 0, t = 0; a; ) { 17067 const unsigned int d = cimg::min(b,c); 17068 a-=d; b-=d; c-=d; 17069 if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d; 17070 else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d; 17071 if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=_spectrum; ++t; b = _spectrum; } 17072 if (!c) { ++s; c = sc; } 17073 } 17074 tmp.move_to(res); 17075 instance_first = false; 17076 } 17077 } break; 17078 17079 // Linear interpolation. 17080 // 17081 case 3 : { 17082 CImg<uintT> off(cimg::max(sx,sy,sz,sc)); 17083 CImg<floatT> foff(off._width); 17084 unsigned int *poff; 17085 float *pfoff, old, curr; 17086 CImg<T> resx, resy, resz, resc; 17087 T *ptrd; 17088 17089 if (sx!=_width) { 17090 if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); 17091 else { 17092 const float fx = (!border_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; 17093 resx.assign(sx,_height,_depth,_spectrum); 17094 curr = old = 0; poff = off._data; pfoff = foff._data; 17095 cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } 17096 ptrd = resx._data; 17097 const T *ptrs0 = _data; 17098 cimg_forYZC(resx,y,z,c) { 17099 poff = off._data; pfoff = foff._data; 17100 const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (_width-1); 17101 cimg_forX(resx,x) { 17102 const float alpha = *(pfoff++); 17103 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):val1; 17104 *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2); 17105 ptrs+=*(poff++); 17106 } 17107 ptrs0+=_width; 17108 } 17109 } 17110 } else resx.assign(*this,true); 17111 17112 if (sy!=_height) { 17113 if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); 17114 else { 17115 const float fy = (!border_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; 17116 resy.assign(sx,sy,_depth,_spectrum); 17117 curr = old = 0; poff = off._data; pfoff = foff._data; 17118 cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr-(unsigned int)old); } 17119 cimg_forXZC(resy,x,z,c) { 17120 ptrd = resy.data(x,0,z,c); 17121 const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height-1)*sx; 17122 poff = off._data; pfoff = foff._data; 17123 cimg_forY(resy,y) { 17124 const float alpha = *(pfoff++); 17125 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+sx):val1; 17126 *ptrd = (T)((1-alpha)*val1 + alpha*val2); 17127 ptrd+=sx; 17128 ptrs+=*(poff++); 17129 } 17130 } 17131 } 17132 resx.assign(); 17133 } else resy.assign(resx,true); 17134 17135 if (sz!=_depth) { 17136 if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); 17137 else { 17138 const float fz = (!border_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; 17139 const unsigned int sxy = sx*sy; 17140 resz.assign(sx,sy,sz,_spectrum); 17141 curr = old = 0; poff = off._data; pfoff = foff._data; 17142 cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } 17143 cimg_forXYC(resz,x,y,c) { 17144 ptrd = resz.data(x,y,0,c); 17145 const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth-1)*sxy; 17146 poff = off._data; pfoff = foff._data; 17147 cimg_forZ(resz,z) { 17148 const float alpha = *(pfoff++); 17149 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+sxy):val1; 17150 *ptrd = (T)((1-alpha)*val1 + alpha*val2); 17151 ptrd+=sxy; 17152 ptrs+=*(poff++); 17153 } 17154 } 17155 } 17156 resy.assign(); 17157 } else resz.assign(resy,true); 17158 17159 if (sc!=_spectrum) { 17160 if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); 17161 else { 17162 const float fc = (!border_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0):(float)_spectrum/sc; 17163 const unsigned int sxyz = sx*sy*sz; 17164 resc.assign(sx,sy,sz,sc); 17165 curr = old = 0; poff = off._data; pfoff = foff._data; 17166 cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } 17167 cimg_forXYZ(resc,x,y,z) { 17168 ptrd = resc.data(x,y,z,0); 17169 const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum-1)*sxyz; 17170 poff = off._data; pfoff = foff._data; 17171 cimg_forC(resc,c) { 17172 const float alpha = *(pfoff++); 17173 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+sxyz):val1; 17174 *ptrd = (T)((1-alpha)*val1 + alpha*val2); 17175 ptrd+=sxyz; 17176 ptrs+=*(poff++); 17177 } 17178 } 17179 } 17180 resz.assign(); 17181 } else resc.assign(resz,true); 17182 return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; 17183 } break; 17184 17185 // Grid interpolation. 17186 // 17187 case 4 : { 17188 CImg<T> resx, resy, resz, resc; 17189 const unsigned int sxy = sx*sy, sxyz = sx*sy*sz; 17190 if (sx!=_width) { 17191 if (sx<_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); 17192 else { 17193 resx.assign(sx,_height,_depth,_spectrum,0); 17194 const T *ptrs = _data; 17195 T *ptrd = resx._data + (int)(centering_x*(sx-1)/_width); 17196 cimg_forYZC(*this,y,z,c) { 17197 cimg_forX(*this,x) ptrd[x*sx/_width] = *(ptrs++); 17198 ptrd+=sx; 17199 } 17200 } 17201 } else resx.assign(*this,true); 17202 17203 if (sy!=_height) { 17204 if (sy<_height) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); 17205 else { 17206 resy.assign(sx,sy,_depth,_spectrum,0); 17207 const T *ptrs = resx._data; 17208 T *ptrd = resy._data + (int)(centering_y*(sy-1)/_height)*sx; 17209 cimg_forZC(*this,z,c) { 17210 cimg_forY(*this,y) { std::memcpy(ptrd + (y*sy/_height)*sx,ptrs,sizeof(T)*sx); ptrs+=sx; } 17211 ptrd+=sxy; 17212 } 17213 } 17214 resx.assign(); 17215 } else resy.assign(resx,true); 17216 17217 if (sz!=_depth) { 17218 if (sz<_depth) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); 17219 else { 17220 resz.assign(sx,sy,sz,_spectrum,0); 17221 const T *ptrs = resy._data; 17222 T *ptrd = resz._data + (int)(centering_z*(sz-1)/_depth)*sxy; 17223 cimg_forC(*this,c) { 17224 cimg_forZ(*this,z) { std::memcpy(ptrd + (z*sz/_depth)*sxy,ptrs,sizeof(T)*sxy); ptrs+=sxy; } 17225 ptrd+=sxyz; 17226 } 17227 } 17228 resy.assign(); 17229 } else resz.assign(resy,true); 17230 17231 if (sc!=_spectrum) { 17232 if (sc<_spectrum) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); 17233 else { 17234 resc.assign(sx,sy,sz,sc,0); 17235 const T *ptrs = resz._data; 17236 T *ptrd = resc._data + (int)(centering_c*(sc-1)/_spectrum)*sxyz; 17237 cimg_forC(*this,c) { std::memcpy(ptrd + (c*sc/_spectrum)*sxyz,ptrs,sizeof(T)*sxyz); ptrs+=sxyz; } 17238 } 17239 resz.assign(); 17240 } else resc.assign(resz,true); 17241 17242 return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; 17243 } break; 17244 17245 // Bicubic interpolation. 17246 // 17247 case 5 : { 17248 CImg<uintT> off(cimg::max(sx,sy,sz,sc)); 17249 CImg<floatT> foff(off._width); 17250 unsigned int *poff; 17251 float *pfoff, old, curr; 17252 CImg<T> resx, resy, resz, resc; 17253 T *ptrd, m, M = max_min(m); 17254 17255 if (sx!=_width) { 17256 if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); 17257 else { 17258 const float fx = (!border_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; 17259 resx.assign(sx,_height,_depth,_spectrum); 17260 curr = old = 0; poff = off._data; pfoff = foff._data; 17261 cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } 17262 ptrd = resx._data; 17263 const T *ptrs0 = _data; 17264 cimg_forYZC(resx,y,z,c) { 17265 poff = off._data; pfoff = foff._data; 17266 const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (_width-2); 17267 cimg_forX(resx,x) { 17268 const float t = *(pfoff++); 17269 const Tfloat 17270 val1 = (Tfloat)*ptrs, 17271 val0 = ptrs>ptrs0?(Tfloat)*(ptrs-1):val1, 17272 val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+1):val1, 17273 val3 = ptrs<ptrsmax?(Tfloat)*(ptrs+2):val2, 17274 val = val1 + 0.5f*(t*(-val0+val2) + t*t*(2*val0-5*val1+4*val2-val3) + t*t*t*(-val0+3*val1-3*val2+val3)); 17275 *(ptrd++) = (T)(val<m?m:val>M?M:val); 17276 ptrs+=*(poff++); 17277 } 17278 ptrs0+=_width; 17279 } 17280 } 17281 } else resx.assign(*this,true); 17282 17283 if (sy!=_height) { 17284 if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); 17285 else { 17286 const float fy = (!border_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; 17287 resy.assign(sx,sy,_depth,_spectrum); 17288 curr = old = 0; poff = off._data; pfoff = foff._data; 17289 cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr-(unsigned int)old); } 17290 cimg_forXZC(resy,x,z,c) { 17291 ptrd = resy.data(x,0,z,c); 17292 const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs0 + (_height-2)*sx; 17293 poff = off._data; pfoff = foff._data; 17294 cimg_forY(resy,y) { 17295 const float t = *(pfoff++); 17296 const Tfloat 17297 val1 = (Tfloat)*ptrs, 17298 val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sx):val1, 17299 val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sx):val1, 17300 val3 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sx):val2, 17301 val = val1 + 0.5f*(t*(-val0+val2) + t*t*(2*val0-5*val1+4*val2-val3) + t*t*t*(-val0+3*val1-3*val2+val3)); 17302 *ptrd = (T)(val<m?m:val>M?M:val); 17303 ptrd+=sx; 17304 ptrs+=*(poff++); 17305 } 17306 } 17307 } 17308 resx.assign(); 17309 } else resy.assign(resx,true); 17310 17311 if (sz!=_depth) { 17312 if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); 17313 else { 17314 const float fz = (!border_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; 17315 const unsigned int sxy = sx*sy; 17316 resz.assign(sx,sy,sz,_spectrum); 17317 curr = old = 0; poff = off._data; pfoff = foff._data; 17318 cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } 17319 cimg_forXYC(resz,x,y,c) { 17320 ptrd = resz.data(x,y,0,c); 17321 const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs0 + (_depth-2)*sxy; 17322 poff = off._data; pfoff = foff._data; 17323 cimg_forZ(resz,z) { 17324 const float t = *(pfoff++); 17325 const Tfloat 17326 val1 = (Tfloat)*ptrs, 17327 val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sxy):val1, 17328 val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxy):val1, 17329 val3 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sxy):val2, 17330 val = val1 + 0.5f*(t*(-val0+val2) + t*t*(2*val0-5*val1+4*val2-val3) + t*t*t*(-val0+3*val1-3*val2+val3)); 17331 *ptrd = (T)(val<m?m:val>M?M:val); 17332 ptrd+=sxy; 17333 ptrs+=*(poff++); 17334 } 17335 } 17336 } 17337 resy.assign(); 17338 } else resz.assign(resy,true); 17339 17340 if (sc!=_spectrum) { 17341 if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); 17342 else { 17343 const float fc = (!border_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0):(float)_spectrum/sc; 17344 const unsigned int sxyz = sx*sy*sz; 17345 resc.assign(sx,sy,sz,sc); 17346 curr = old = 0; poff = off._data; pfoff = foff._data; 17347 cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } 17348 cimg_forXYZ(resc,x,y,z) { 17349 ptrd = resc.data(x,y,z,0); 17350 const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum-2)*sxyz; 17351 poff = off._data; pfoff = foff._data; 17352 cimg_forC(resc,c) { 17353 const float t = *(pfoff++); 17354 const Tfloat 17355 val1 = (Tfloat)*ptrs, 17356 val0 = ptrs>ptrs0?(Tfloat)*(ptrs-sxyz):val1, 17357 val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxyz):val1, 17358 val3 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sxyz):val2, 17359 val = val1 + 0.5f*(t*(-val0+val2) + t*t*(2*val0-5*val1+4*val2-val3) + t*t*t*(-val0+3*val1-3*val2+val3)); 17360 *ptrd = (T)(val<m?m:val>M?M:val); 17361 ptrd+=sxyz; 17362 ptrs+=*(poff++); 17363 } 17364 } 17365 } 17366 resz.assign(); 17367 } else resc.assign(resz,true); 17368 17369 return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; 17370 } break; 17371 17372 // Lanczos interpolation. 17373 // 17374 case 6 : { 17375 CImg<uintT> off(cimg::max(sx,sy,sz,sc)); 17376 CImg<floatT> foff(off._width); 17377 unsigned int *poff; 17378 float *pfoff, old, curr; 17379 CImg<T> resx, resy, resz, resc; 17380 T *ptrd, m, M = max_min(m); 17381 17382 if (sx!=_width) { 17383 if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); 17384 else { 17385 const float fx = (!border_conditions && sx>_width)?(sx>1?(_width-1.0f)/(sx-1):0):(float)_width/sx; 17386 resx.assign(sx,_height,_depth,_spectrum); 17387 curr = old = 0; poff = off._data; pfoff = foff._data; 17388 cimg_forX(resx,x) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fx; *(poff++) = (unsigned int)curr - (unsigned int)old; } 17389 ptrd = resx._data; 17390 const T *ptrs0 = _data; 17391 cimg_forYZC(resx,y,z,c) { 17392 poff = off._data; pfoff = foff._data; 17393 const T *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1, *const ptrsmax = ptrs0 + (_width-2); 17394 cimg_forX(resx,x) { 17395 const float 17396 t = *(pfoff++), 17397 w0 = _cimg_lanczos(t+2), 17398 w1 = _cimg_lanczos(t+1), 17399 w2 = _cimg_lanczos(t), 17400 w3 = _cimg_lanczos(t-1), 17401 w4 = _cimg_lanczos(t-2); 17402 const Tfloat 17403 val2 = (Tfloat)*ptrs, 17404 val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-1):val2, 17405 val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2):val1, 17406 val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+1):val2, 17407 val4 = ptrs<ptrsmax?(Tfloat)*(ptrs+2):val3, 17408 val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4); 17409 *(ptrd++) = (T)(val<m?m:val>M?M:val); 17410 ptrs+=*(poff++); 17411 } 17412 ptrs0+=_width; 17413 } 17414 } 17415 } else resx.assign(*this,true); 17416 17417 if (sy!=_height) { 17418 if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); 17419 else { 17420 const float fy = (!border_conditions && sy>_height)?(sy>1?(_height-1.0f)/(sy-1):0):(float)_height/sy; 17421 resy.assign(sx,sy,_depth,_spectrum); 17422 curr = old = 0; poff = off._data; pfoff = foff._data; 17423 cimg_forY(resy,y) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fy; *(poff++) = sx*((unsigned int)curr-(unsigned int)old); } 17424 cimg_forXZC(resy,x,z,c) { 17425 ptrd = resy.data(x,0,z,c); 17426 const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx, *const ptrsmax = ptrs0 + (_height-2)*sx; 17427 poff = off._data; pfoff = foff._data; 17428 cimg_forY(resy,y) { 17429 const float 17430 t = *(pfoff++), 17431 w0 = _cimg_lanczos(t+2), 17432 w1 = _cimg_lanczos(t+1), 17433 w2 = _cimg_lanczos(t), 17434 w3 = _cimg_lanczos(t-1), 17435 w4 = _cimg_lanczos(t-2); 17436 const Tfloat 17437 val2 = (Tfloat)*ptrs, 17438 val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sx):val2, 17439 val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sx):val1, 17440 val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sx):val2, 17441 val4 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sx):val3, 17442 val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4); 17443 *ptrd = (T)(val<m?m:val>M?M:val); 17444 ptrd+=sx; 17445 ptrs+=*(poff++); 17446 } 17447 } 17448 } 17449 resx.assign(); 17450 } else resy.assign(resx,true); 17451 17452 if (sz!=_depth) { 17453 if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); 17454 else { 17455 const float fz = (!border_conditions && sz>_depth)?(sz>1?(_depth-1.0f)/(sz-1):0):(float)_depth/sz; 17456 const unsigned int sxy = sx*sy; 17457 resz.assign(sx,sy,sz,_spectrum); 17458 curr = old = 0; poff = off._data; pfoff = foff._data; 17459 cimg_forZ(resz,z) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fz; *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); } 17460 cimg_forXYC(resz,x,y,c) { 17461 ptrd = resz.data(x,y,0,c); 17462 const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy, *const ptrsmax = ptrs0 + (_depth-2)*sxy; 17463 poff = off._data; pfoff = foff._data; 17464 cimg_forZ(resz,z) { 17465 const float 17466 t = *(pfoff++), 17467 w0 = _cimg_lanczos(t+2), 17468 w1 = _cimg_lanczos(t+1), 17469 w2 = _cimg_lanczos(t), 17470 w3 = _cimg_lanczos(t-1), 17471 w4 = _cimg_lanczos(t-2); 17472 const Tfloat 17473 val2 = (Tfloat)*ptrs, 17474 val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sxy):val2, 17475 val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sxy):val1, 17476 val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxy):val2, 17477 val4 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sxy):val3, 17478 val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4); 17479 *ptrd = (T)(val<m?m:val>M?M:val); 17480 ptrd+=sxy; 17481 ptrs+=*(poff++); 17482 } 17483 } 17484 } 17485 resy.assign(); 17486 } else resz.assign(resy,true); 17487 17488 if (sc!=_spectrum) { 17489 if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); 17490 else { 17491 const float fc = (!border_conditions && sc>_spectrum)?(sc>1?(_spectrum-1.0f)/(sc-1):0):(float)_spectrum/sc; 17492 const unsigned int sxyz = sx*sy*sz; 17493 resc.assign(sx,sy,sz,sc); 17494 curr = old = 0; poff = off._data; pfoff = foff._data; 17495 cimg_forC(resc,c) { *(pfoff++) = curr - (unsigned int)curr; old = curr; curr+=fc; *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); } 17496 cimg_forXYZ(resc,x,y,z) { 17497 ptrd = resc.data(x,y,z,0); 17498 const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz, *const ptrsmax = ptrs + (_spectrum-2)*sxyz; 17499 poff = off._data; pfoff = foff._data; 17500 cimg_forC(resc,c) { 17501 const float 17502 t = *(pfoff++), 17503 w0 = _cimg_lanczos(t+2), 17504 w1 = _cimg_lanczos(t+1), 17505 w2 = _cimg_lanczos(t), 17506 w3 = _cimg_lanczos(t-1), 17507 w4 = _cimg_lanczos(t-2); 17508 const Tfloat 17509 val2 = (Tfloat)*ptrs, 17510 val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs-sxyz):val2, 17511 val0 = ptrs>ptrsmin?(Tfloat)*(ptrs-2*sxyz):val1, 17512 val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs+sxyz):val2, 17513 val4 = ptrs<ptrsmax?(Tfloat)*(ptrs+2*sxyz):val3, 17514 val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4); 17515 *ptrd = (T)(val<m?m:val>M?M:val); 17516 ptrd+=sxyz; 17517 ptrs+=*(poff++); 17518 } 17519 } 17520 } 17521 resz.assign(); 17522 } else resc.assign(resz,true); 17523 17524 return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; 17525 } break; 17526 17527 // Unknow interpolation. 17528 // 17529 default : 17530 throw CImgArgumentException(_cimg_instance 17531 "resize() : Invalid specified interpolation %d " 17532 "(should be { -1=raw | 0=none | 1=nearest | 2=average | 3=linear | 4=grid | 5=bicubic | 6=lanczos }).", 17533 cimg_instance, 17534 interpolation_type); 17535 } 17536 return res; 17537 } 17538 17539 //! Resize an image. 17540 template<typename t> 17541 CImg<T>& resize(const CImg<t>& src, 17542 const int interpolation_type=1, const unsigned int border_conditions=0, 17543 const float centering_x = 0, const float centering_y = 0, 17544 const float centering_z = 0, const float centering_c = 0) { 17545 return resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,border_conditions, 17546 centering_x,centering_y,centering_z,centering_c); 17547 } 17548 17549 template<typename t> 17550 CImg<T> get_resize(const CImg<t>& src, 17551 const int interpolation_type=1, const unsigned int border_conditions=0, 17552 const float centering_x = 0, const float centering_y = 0, 17553 const float centering_z = 0, const float centering_c = 0) const { 17554 return get_resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,border_conditions, 17555 centering_x,centering_y,centering_z,centering_c); 17556 } 17557 17558 //! Resize an image. 17559 CImg<T>& resize(const CImgDisplay& disp, 17560 const int interpolation_type=1, const unsigned int border_conditions=0, 17561 const float centering_x = 0, const float centering_y = 0, 17562 const float centering_z = 0, const float centering_c = 0) { 17563 return resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,border_conditions, 17564 centering_x,centering_y,centering_z,centering_c); 17565 } 17566 17567 CImg<T> get_resize(const CImgDisplay& disp, 17568 const int interpolation_type=1, const unsigned int border_conditions=0, 17569 const float centering_x = 0, const float centering_y = 0, 17570 const float centering_z = 0, const float centering_c = 0) const { 17571 return get_resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,border_conditions, 17572 centering_x,centering_y,centering_z,centering_c); 17573 } 17574 17575 //! Half-resize an image, using a special optimized filter. 17576 CImg<T>& resize_halfXY() { 17577 return get_resize_halfXY().move_to(*this); 17578 } 17579 17580 CImg<T> get_resize_halfXY() const { 17581 if (is_empty()) return *this; 17582 const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f, 17583 0.1231940459f, 0.1935127547f, 0.1231940459f, 17584 0.07842776544f, 0.1231940459f, 0.07842776544f }; 17585 T I[9] = { 0 }; 17586 CImg<T> res(_width/2,_height/2,_depth,_spectrum); 17587 T *ptrd = res._data; 17588 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) 17589 if (x%2 && y%2) *(ptrd++) = (T) 17590 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] + 17591 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] + 17592 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]); 17593 return res; 17594 } 17595 17596 //! Upscale an image by a factor 2x. 17597 /** 17598 Use anisotropic upscaling algorithm described at 17599 http://scale2x.sourceforge.net/algorithm.html 17600 **/ 17601 CImg<T>& resize_doubleXY() { 17602 return get_resize_doubleXY().move_to(*this); 17603 } 17604 17605 CImg<T> get_resize_doubleXY() const { 17606 #define _cimg_gs2x_for3(bound,i) \ 17607 for (int i = 0, _p1##i = 0, \ 17608 _n1##i = 1>=(bound)?(int)(bound)-1:1; \ 17609 _n1##i<(int)(bound) || i==--_n1##i; \ 17610 _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width) 17611 17612 #define _cimg_gs2x_for3x3(img,x,y,z,c,I,T) \ 17613 _cimg_gs2x_for3((img)._height,y) for (int x = 0, \ 17614 _p1##x = 0, \ 17615 _n1##x = (int)( \ 17616 (I[1] = (T)(img)(0,_p1##y,z,c)), \ 17617 (I[3] = I[4] = (T)(img)(0,y,z,c)), \ 17618 (I[7] = (T)(img)(0,_n1##y,z,c)), \ 17619 1>=(img)._width?(img).width()-1:1); \ 17620 (_n1##x<(img).width() && ( \ 17621 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 17622 (I[5] = (T)(img)(_n1##x,y,z,c)), \ 17623 (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 17624 x==--_n1##x; \ 17625 I[1] = I[2], \ 17626 I[3] = I[4], I[4] = I[5], \ 17627 I[7] = I[8], \ 17628 _p1##x = x++, ++_n1##x) 17629 17630 if (is_empty()) return *this; 17631 CImg<T> res(_width<<1,_height<<1,_depth,_spectrum); 17632 CImg_3x3(I,T); 17633 cimg_forZC(*this,z,c) { 17634 T 17635 *ptrd1 = res.data(0,0,0,c), 17636 *ptrd2 = ptrd1 + res._width; 17637 _cimg_gs2x_for3x3(*this,x,y,0,c,I,T) { 17638 if (Icp!=Icn && Ipc!=Inc) { 17639 *(ptrd1++) = Ipc==Icp?Ipc:Icc; 17640 *(ptrd1++) = Icp==Inc?Inc:Icc; 17641 *(ptrd2++) = Ipc==Icn?Ipc:Icc; 17642 *(ptrd2++) = Icn==Inc?Inc:Icc; 17643 } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; } 17644 } 17645 } 17646 return res; 17647 } 17648 17649 //! Upscale an image by a factor 3x. 17650 /** 17651 Use anisotropic upscaling algorithm described at 17652 http://scale2x.sourceforge.net/algorithm.html 17653 **/ 17654 CImg<T>& resize_tripleXY() { 17655 return get_resize_tripleXY().move_to(*this); 17656 } 17657 17658 CImg<T> get_resize_tripleXY() const { 17659 #define _cimg_gs3x_for3(bound,i) \ 17660 for (int i = 0, _p1##i = 0, \ 17661 _n1##i = 1>=(bound)?(int)(bound)-1:1; \ 17662 _n1##i<(int)(bound) || i==--_n1##i; \ 17663 _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width) 17664 17665 #define _cimg_gs3x_for3x3(img,x,y,z,c,I,T) \ 17666 _cimg_gs3x_for3((img)._height,y) for (int x = 0, \ 17667 _p1##x = 0, \ 17668 _n1##x = (int)( \ 17669 (I[0] = I[1] = (T)(img)(0,_p1##y,z,c)), \ 17670 (I[3] = I[4] = (T)(img)(0,y,z,c)), \ 17671 (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ 17672 1>=(img)._width?(img).width()-1:1); \ 17673 (_n1##x<(img).width() && ( \ 17674 (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ 17675 (I[5] = (T)(img)(_n1##x,y,z,c)), \ 17676 (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ 17677 x==--_n1##x; \ 17678 I[0] = I[1], I[1] = I[2], \ 17679 I[3] = I[4], I[4] = I[5], \ 17680 I[6] = I[7], I[7] = I[8], \ 17681 _p1##x = x++, ++_n1##x) 17682 17683 if (is_empty()) return *this; 17684 CImg<T> res(3*_width,3*_height,_depth,_spectrum); 17685 CImg_3x3(I,T); 17686 cimg_forZC(*this,z,c) { 17687 T 17688 *ptrd1 = res.data(0,0,0,c), 17689 *ptrd2 = ptrd1 + res._width, 17690 *ptrd3 = ptrd2 + res._width; 17691 _cimg_gs3x_for3x3(*this,x,y,0,c,I,T) { 17692 if (Icp != Icn && Ipc != Inc) { 17693 *(ptrd1++) = Ipc==Icp?Ipc:Icc; 17694 *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc; 17695 *(ptrd1++) = Icp==Inc?Inc:Icc; 17696 *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc; 17697 *(ptrd2++) = Icc; 17698 *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc; 17699 *(ptrd3++) = Ipc==Icn?Ipc:Icc; 17700 *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc; 17701 *(ptrd3++) = Icn==Inc?Inc:Icc; 17702 } else { 17703 *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc; 17704 *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; 17705 *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc; 17706 } 17707 } 17708 } 17709 return res; 17710 } 17711 17712 //! Mirror an image along the specified axis. 17713 CImg<T>& mirror(const char axis) { 17714 if (is_empty()) return *this; 17715 T *pf, *pb, *buf = 0; 17716 switch (cimg::uncase(axis)) { 17717 case 'x' : { 17718 pf = _data; pb = data(_width-1); 17719 const unsigned int width2 = _width/2; 17720 for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) { 17721 for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; } 17722 pf+=_width - width2; 17723 pb+=_width + width2; 17724 } 17725 } break; 17726 case 'y' : { 17727 buf = new T[_width]; 17728 pf = _data; pb = data(0,_height-1); 17729 const unsigned int height2 = _height/2; 17730 for (unsigned int zv = 0; zv<_depth*_spectrum; ++zv) { 17731 for (unsigned int y = 0; y<height2; ++y) { 17732 std::memcpy(buf,pf,_width*sizeof(T)); 17733 std::memcpy(pf,pb,_width*sizeof(T)); 17734 std::memcpy(pb,buf,_width*sizeof(T)); 17735 pf+=_width; 17736 pb-=_width; 17737 } 17738 pf+=_width*(_height - height2); 17739 pb+=_width*(_height + height2); 17740 } 17741 } break; 17742 case 'z' : { 17743 buf = new T[_width*_height]; 17744 pf = _data; pb = data(0,0,_depth-1); 17745 const unsigned int depth2 = _depth/2; 17746 cimg_forC(*this,c) { 17747 for (unsigned int z = 0; z<depth2; ++z) { 17748 std::memcpy(buf,pf,_width*_height*sizeof(T)); 17749 std::memcpy(pf,pb,_width*_height*sizeof(T)); 17750 std::memcpy(pb,buf,_width*_height*sizeof(T)); 17751 pf+=_width*_height; 17752 pb-=_width*_height; 17753 } 17754 pf+=_width*_height*(_depth - depth2); 17755 pb+=_width*_height*(_depth + depth2); 17756 } 17757 } break; 17758 default : { 17759 buf = new T[_width*_height*_depth]; 17760 pf = _data; pb = data(0,0,0,_spectrum-1); 17761 const unsigned int _spectrum2 = _spectrum/2; 17762 for (unsigned int v = 0; v<_spectrum2; ++v) { 17763 std::memcpy(buf,pf,_width*_height*_depth*sizeof(T)); 17764 std::memcpy(pf,pb,_width*_height*_depth*sizeof(T)); 17765 std::memcpy(pb,buf,_width*_height*_depth*sizeof(T)); 17766 pf+=_width*_height*_depth; 17767 pb-=_width*_height*_depth; 17768 } 17769 } 17770 } 17771 if (buf) delete[] buf; 17772 return *this; 17773 } 17774 17775 CImg<T> get_mirror(const char axis) const { 17776 return (+*this).mirror(axis); 17777 } 17778 17779 //! Shift the image. 17780 /** 17781 \param deltax Amount of displacement along the X-axis. 17782 \param deltay Amount of displacement along the Y-axis. 17783 \param deltaz Amount of displacement along the Z-axis. 17784 \param deltac Amount of displacement along the C-axis. 17785 \param border_condition Border condition. 17786 17787 - \c border_condition can be : 17788 - 0 : Zero border condition (Dirichlet). 17789 - 1 : Nearest neighbors (Neumann). 17790 - 2 : Repeat Pattern (Fourier style). 17791 **/ 17792 CImg<T>& shift(const int deltax, const int deltay=0, const int deltaz=0, const int deltac=0, 17793 const int border_condition=0) { 17794 if (is_empty()) return *this; 17795 if (deltax) // Shift along X-axis 17796 switch (border_condition) { 17797 case 0 : 17798 if (cimg::abs(deltax)>=width()) return fill(0); 17799 if (deltax<0) cimg_forYZC(*this,y,z,c) { 17800 std::memmove(data(0,y,z,c),data(-deltax,y,z,c),(_width+deltax)*sizeof(T)); 17801 std::memset(data(_width+deltax,y,z,c),0,-deltax*sizeof(T)); 17802 } else cimg_forYZC(*this,y,z,c) { 17803 std::memmove(data(deltax,y,z,c),data(0,y,z,c),(_width-deltax)*sizeof(T)); 17804 std::memset(data(0,y,z,c),0,deltax*sizeof(T)); 17805 } 17806 break; 17807 case 1 : 17808 if (deltax<0) { 17809 const int ndeltax = (-deltax>=width())?_width-1:-deltax; 17810 if (!ndeltax) return *this; 17811 cimg_forYZC(*this,y,z,c) { 17812 std::memmove(data(0,y,z,c),data(ndeltax,y,z,c),(_width-ndeltax)*sizeof(T)); 17813 T *ptrd = data(_width-1,y,z,c); 17814 const T val = *ptrd; 17815 for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val; 17816 } 17817 } else { 17818 const int ndeltax = (deltax>=width())?_width-1:deltax; 17819 if (!ndeltax) return *this; 17820 cimg_forYZC(*this,y,z,c) { 17821 std::memmove(data(ndeltax,y,z,c),data(0,y,z,c),(_width-ndeltax)*sizeof(T)); 17822 T *ptrd = data(0,y,z,c); 17823 const T val = *ptrd; 17824 for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val; 17825 } 17826 } 17827 break; 17828 default : { 17829 const int ml = cimg::mod(-deltax,width()), ndeltax = (ml<=width()/2)?ml:(ml-width()); 17830 if (!ndeltax) return *this; 17831 T *const buf = new T[cimg::abs(ndeltax)]; 17832 if (ndeltax>0) cimg_forYZC(*this,y,z,c) { 17833 std::memcpy(buf,data(0,y,z,c),ndeltax*sizeof(T)); 17834 std::memmove(data(0,y,z,c),data(ndeltax,y,z,c),(_width-ndeltax)*sizeof(T)); 17835 std::memcpy(data(_width-ndeltax,y,z,c),buf,ndeltax*sizeof(T)); 17836 } else cimg_forYZC(*this,y,z,c) { 17837 std::memcpy(buf,data(_width+ndeltax,y,z,c),-ndeltax*sizeof(T)); 17838 std::memmove(data(-ndeltax,y,z,c),data(0,y,z,c),(_width+ndeltax)*sizeof(T)); 17839 std::memcpy(data(0,y,z,c),buf,-ndeltax*sizeof(T)); 17840 } 17841 delete[] buf; 17842 } 17843 } 17844 17845 if (deltay) // Shift along Y-axis 17846 switch (border_condition) { 17847 case 0 : 17848 if (cimg::abs(deltay)>=height()) return fill(0); 17849 if (deltay<0) cimg_forZC(*this,z,c) { 17850 std::memmove(data(0,0,z,c),data(0,-deltay,z,c),_width*(_height+deltay)*sizeof(T)); 17851 std::memset(data(0,_height+deltay,z,c),0,-deltay*_width*sizeof(T)); 17852 } else cimg_forZC(*this,z,c) { 17853 std::memmove(data(0,deltay,z,c),data(0,0,z,c),_width*(_height-deltay)*sizeof(T)); 17854 std::memset(data(0,0,z,c),0,deltay*_width*sizeof(T)); 17855 } 17856 break; 17857 case 1 : 17858 if (deltay<0) { 17859 const int ndeltay = (-deltay>=height())?_height-1:-deltay; 17860 if (!ndeltay) return *this; 17861 cimg_forZC(*this,z,c) { 17862 std::memmove(data(0,0,z,c),data(0,ndeltay,z,c),_width*(_height-ndeltay)*sizeof(T)); 17863 T *ptrd = data(0,_height-ndeltay,z,c), *ptrs = data(0,_height-1,z,c); 17864 for (int l = 0; l<ndeltay-1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; } 17865 } 17866 } else { 17867 const int ndeltay = (deltay>=height())?_height-1:deltay; 17868 if (!ndeltay) return *this; 17869 cimg_forZC(*this,z,c) { 17870 std::memmove(data(0,ndeltay,z,c),data(0,0,z,c),_width*(_height-ndeltay)*sizeof(T)); 17871 T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c); 17872 for (int l = 0; l<ndeltay-1; ++l) { std::memcpy(ptrd,ptrs,_width*sizeof(T)); ptrd+=_width; } 17873 } 17874 } 17875 break; 17876 default : { 17877 const int ml = cimg::mod(-deltay,height()), ndeltay = (ml<=height()/2)?ml:(ml-height()); 17878 if (!ndeltay) return *this; 17879 T *const buf = new T[_width*cimg::abs(ndeltay)]; 17880 if (ndeltay>0) cimg_forZC(*this,z,c) { 17881 std::memcpy(buf,data(0,0,z,c),_width*ndeltay*sizeof(T)); 17882 std::memmove(data(0,0,z,c),data(0,ndeltay,z,c),_width*(_height-ndeltay)*sizeof(T)); 17883 std::memcpy(data(0,_height-ndeltay,z,c),buf,_width*ndeltay*sizeof(T)); 17884 } else cimg_forZC(*this,z,c) { 17885 std::memcpy(buf,data(0,_height+ndeltay,z,c),-ndeltay*_width*sizeof(T)); 17886 std::memmove(data(0,-ndeltay,z,c),data(0,0,z,c),_width*(_height+ndeltay)*sizeof(T)); 17887 std::memcpy(data(0,0,z,c),buf,-ndeltay*_width*sizeof(T)); 17888 } 17889 delete[] buf; 17890 } 17891 } 17892 17893 if (deltaz) // Shift along Z-axis 17894 switch (border_condition) { 17895 case 0 : 17896 if (cimg::abs(deltaz)>=depth()) return fill(0); 17897 if (deltaz<0) cimg_forC(*this,c) { 17898 std::memmove(data(0,0,0,c),data(0,0,-deltaz,c),_width*_height*(_depth+deltaz)*sizeof(T)); 17899 std::memset(data(0,0,_depth+deltaz,c),0,_width*_height*(-deltaz)*sizeof(T)); 17900 } else cimg_forC(*this,c) { 17901 std::memmove(data(0,0,deltaz,c),data(0,0,0,c),_width*_height*(_depth-deltaz)*sizeof(T)); 17902 std::memset(data(0,0,0,c),0,deltaz*_width*_height*sizeof(T)); 17903 } 17904 break; 17905 case 1 : 17906 if (deltaz<0) { 17907 const int ndeltaz = (-deltaz>=depth())?_depth-1:-deltaz; 17908 if (!ndeltaz) return *this; 17909 cimg_forC(*this,c) { 17910 std::memmove(data(0,0,0,c),data(0,0,ndeltaz,c),_width*_height*(_depth-ndeltaz)*sizeof(T)); 17911 T *ptrd = data(0,0,_depth-ndeltaz,c), *ptrs = data(0,0,_depth-1,c); 17912 for (int l = 0; l<ndeltaz-1; ++l) { std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=_width*_height; } 17913 } 17914 } else { 17915 const int ndeltaz = (deltaz>=depth())?_depth-1:deltaz; 17916 if (!ndeltaz) return *this; 17917 cimg_forC(*this,c) { 17918 std::memmove(data(0,0,ndeltaz,c),data(0,0,0,c),_width*_height*(_depth-ndeltaz)*sizeof(T)); 17919 T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c); 17920 for (int l = 0; l<ndeltaz-1; ++l) { std::memcpy(ptrd,ptrs,_width*_height*sizeof(T)); ptrd+=_width*_height; } 17921 } 17922 } 17923 break; 17924 default : { 17925 const int ml = cimg::mod(-deltaz,depth()), ndeltaz = (ml<=depth()/2)?ml:(ml-depth()); 17926 if (!ndeltaz) return *this; 17927 T *const buf = new T[_width*_height*cimg::abs(ndeltaz)]; 17928 if (ndeltaz>0) cimg_forC(*this,c) { 17929 std::memcpy(buf,data(0,0,0,c),_width*_height*ndeltaz*sizeof(T)); 17930 std::memmove(data(0,0,0,c),data(0,0,ndeltaz,c),_width*_height*(_depth-ndeltaz)*sizeof(T)); 17931 std::memcpy(data(0,0,_depth-ndeltaz,c),buf,_width*_height*ndeltaz*sizeof(T)); 17932 } else cimg_forC(*this,c) { 17933 std::memcpy(buf,data(0,0,_depth+ndeltaz,c),-ndeltaz*_width*_height*sizeof(T)); 17934 std::memmove(data(0,0,-ndeltaz,c),data(0,0,0,c),_width*_height*(_depth+ndeltaz)*sizeof(T)); 17935 std::memcpy(data(0,0,0,c),buf,-ndeltaz*_width*_height*sizeof(T)); 17936 } 17937 delete[] buf; 17938 } 17939 } 17940 17941 if (deltac) // Shift along C-axis 17942 switch (border_condition) { 17943 case 0 : 17944 if (cimg::abs(deltac)>=spectrum()) return fill(0); 17945 if (-deltac>0) { 17946 std::memmove(_data,data(0,0,0,-deltac),_width*_height*_depth*(_spectrum+deltac)*sizeof(T)); 17947 std::memset(data(0,0,0,_spectrum+deltac),0,_width*_height*_depth*(-deltac)*sizeof(T)); 17948 } else cimg_forC(*this,c) { 17949 std::memmove(data(0,0,0,deltac),_data,_width*_height*_depth*(_spectrum-deltac)*sizeof(T)); 17950 std::memset(_data,0,deltac*_width*_height*_depth*sizeof(T)); 17951 } 17952 break; 17953 case 1 : 17954 if (deltac<0) { 17955 const int ndeltac = (-deltac>=spectrum())?_spectrum-1:-deltac; 17956 if (!ndeltac) return *this; 17957 std::memmove(_data,data(0,0,0,ndeltac),_width*_height*_depth*(_spectrum-ndeltac)*sizeof(T)); 17958 T *ptrd = data(0,0,0,_spectrum-ndeltac), *ptrs = data(0,0,0,_spectrum-1); 17959 for (int l = 0; l<ndeltac-1; ++l) { std::memcpy(ptrd,ptrs,_width*_height*_depth*sizeof(T)); ptrd+=_width*_height*_depth; } 17960 } else { 17961 const int ndeltac = (deltac>=spectrum())?_spectrum-1:deltac; 17962 if (!ndeltac) return *this; 17963 std::memmove(data(0,0,0,ndeltac),_data,_width*_height*_depth*(_spectrum-ndeltac)*sizeof(T)); 17964 T *ptrd = data(0,0,0,1); 17965 for (int l = 0; l<ndeltac-1; ++l) { std::memcpy(ptrd,_data,_width*_height*_depth*sizeof(T)); ptrd+=_width*_height*_depth; } 17966 } 17967 break; 17968 default : { 17969 const int ml = cimg::mod(-deltac,spectrum()), ndeltac = (ml<=spectrum()/2)?ml:(ml-spectrum()); 17970 if (!ndeltac) return *this; 17971 T *const buf = new T[_width*_height*_depth*cimg::abs(ndeltac)]; 17972 if (ndeltac>0) { 17973 std::memcpy(buf,_data,_width*_height*_depth*ndeltac*sizeof(T)); 17974 std::memmove(_data,data(0,0,0,ndeltac),_width*_height*_depth*(_spectrum-ndeltac)*sizeof(T)); 17975 std::memcpy(data(0,0,0,_spectrum-ndeltac),buf,_width*_height*_depth*ndeltac*sizeof(T)); 17976 } else { 17977 std::memcpy(buf,data(0,0,0,_spectrum+ndeltac),-ndeltac*_width*_height*_depth*sizeof(T)); 17978 std::memmove(data(0,0,0,-ndeltac),_data,_width*_height*_depth*(_spectrum+ndeltac)*sizeof(T)); 17979 std::memcpy(_data,buf,-ndeltac*_width*_height*_depth*sizeof(T)); 17980 } 17981 delete[] buf; 17982 } 17983 } 17984 return *this; 17985 } 17986 17987 CImg<T> get_shift(const int deltax, const int deltay=0, const int deltaz=0, const int deltac=0, 17988 const int border_condition=0) const { 17989 return (+*this).shift(deltax,deltay,deltaz,deltac,border_condition); 17990 } 17991 17992 // Permute axes order (internal). 17993 template<typename t> 17994 CImg<t> _get_permute_axes(const char *const permut, const t&) const { 17995 if (is_empty() || !permut) return CImg<t>(*this,false); 17996 CImg<t> res; 17997 const T* ptrs = _data; 17998 if (!cimg::strncasecmp(permut,"xyzc",4)) return (+*this); 17999 if (!cimg::strncasecmp(permut,"xycz",4)) { 18000 res.assign(_width,_height,_spectrum,_depth); 18001 cimg_forXYZC(*this,x,y,z,c) res(x,y,c,z) = (t)*(ptrs++); 18002 } 18003 if (!cimg::strncasecmp(permut,"xzyc",4)) { 18004 res.assign(_width,_depth,_height,_spectrum); 18005 cimg_forXYZC(*this,x,y,z,c) res(x,z,y,c) = (t)*(ptrs++); 18006 } 18007 if (!cimg::strncasecmp(permut,"xzcy",4)) { 18008 res.assign(_width,_depth,_spectrum,_height); 18009 cimg_forXYZC(*this,x,y,z,c) res(x,z,c,y) = (t)*(ptrs++); 18010 } 18011 if (!cimg::strncasecmp(permut,"xcyz",4)) { 18012 res.assign(_width,_spectrum,_height,_depth); 18013 cimg_forXYZC(*this,x,y,z,c) res(x,c,y,z) = (t)*(ptrs++); 18014 } 18015 if (!cimg::strncasecmp(permut,"xczy",4)) { 18016 res.assign(_width,_spectrum,_depth,_height); 18017 cimg_forXYZC(*this,x,y,z,c) res(x,c,z,y) = (t)*(ptrs++); 18018 } 18019 if (!cimg::strncasecmp(permut,"yxzc",4)) { 18020 res.assign(_height,_width,_depth,_spectrum); 18021 cimg_forXYZC(*this,x,y,z,c) res(y,x,z,c) = (t)*(ptrs++); 18022 } 18023 if (!cimg::strncasecmp(permut,"yxcz",4)) { 18024 res.assign(_height,_width,_spectrum,_depth); 18025 cimg_forXYZC(*this,x,y,z,c) res(y,x,c,z) = (t)*(ptrs++); 18026 } 18027 if (!cimg::strncasecmp(permut,"yzxc",4)) { 18028 res.assign(_height,_depth,_width,_spectrum); 18029 cimg_forXYZC(*this,x,y,z,c) res(y,z,x,c) = (t)*(ptrs++); 18030 } 18031 if (!cimg::strncasecmp(permut,"yzcx",4)) { 18032 res.assign(_height,_depth,_spectrum,_width); 18033 switch (_width) { 18034 case 1 : { 18035 t *ptr_r = res.data(0,0,0,0); 18036 for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { 18037 *(ptr_r++) = (t)*(ptrs++); 18038 } 18039 } break; 18040 case 2 : { 18041 t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1); 18042 for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { 18043 *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); 18044 } 18045 } break; 18046 case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB 18047 t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2); 18048 for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { 18049 *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++); 18050 } 18051 } break; 18052 case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA 18053 t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2), *ptr_a = res.data(0,0,0,3); 18054 for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { 18055 *(ptr_r++) = (t)*(ptrs++); *(ptr_g++) = (t)*(ptrs++); *(ptr_b++) = (t)*(ptrs++); *(ptr_a++) = (t)*(ptrs++); 18056 } 18057 } break; 18058 default : { 18059 cimg_forXYZC(*this,x,y,z,c) res(y,z,c,x) = *(ptrs++); 18060 return res; 18061 } 18062 } 18063 } 18064 if (!cimg::strncasecmp(permut,"ycxz",4)) { 18065 res.assign(_height,_spectrum,_width,_depth); 18066 cimg_forXYZC(*this,x,y,z,c) res(y,c,x,z) = (t)*(ptrs++); 18067 } 18068 if (!cimg::strncasecmp(permut,"yczx",4)) { 18069 res.assign(_height,_spectrum,_depth,_width); 18070 cimg_forXYZC(*this,x,y,z,c) res(y,c,z,x) = (t)*(ptrs++); 18071 } 18072 if (!cimg::strncasecmp(permut,"zxyc",4)) { 18073 res.assign(_depth,_width,_height,_spectrum); 18074 cimg_forXYZC(*this,x,y,z,c) res(z,x,y,c) = (t)*(ptrs++); 18075 } 18076 if (!cimg::strncasecmp(permut,"zxcy",4)) { 18077 res.assign(_depth,_width,_spectrum,_height); 18078 cimg_forXYZC(*this,x,y,z,c) res(z,x,c,y) = (t)*(ptrs++); 18079 } 18080 if (!cimg::strncasecmp(permut,"zyxc",4)) { 18081 res.assign(_depth,_height,_width,_spectrum); 18082 cimg_forXYZC(*this,x,y,z,c) res(z,y,x,c) = (t)*(ptrs++); 18083 } 18084 if (!cimg::strncasecmp(permut,"zycx",4)) { 18085 res.assign(_depth,_height,_spectrum,_width); 18086 cimg_forXYZC(*this,x,y,z,c) res(z,y,c,x) = (t)*(ptrs++); 18087 } 18088 if (!cimg::strncasecmp(permut,"zcxy",4)) { 18089 res.assign(_depth,_spectrum,_width,_height); 18090 cimg_forXYZC(*this,x,y,z,c) res(z,c,x,y) = (t)*(ptrs++); 18091 } 18092 if (!cimg::strncasecmp(permut,"zcyx",4)) { 18093 res.assign(_depth,_spectrum,_height,_width); 18094 cimg_forXYZC(*this,x,y,z,c) res(z,c,y,x) = (t)*(ptrs++); 18095 } 18096 if (!cimg::strncasecmp(permut,"cxyz",4)) { 18097 res.assign(_spectrum,_width,_height,_depth); 18098 switch (_spectrum) { 18099 case 1 : { 18100 const T *ptr_r = data(0,0,0,0); 18101 t *ptrd = res._data; 18102 for (unsigned int siz = _width*_height*_depth; siz; --siz) { 18103 *(ptrd++) = (t)*(ptr_r++); 18104 } 18105 } break; 18106 case 2 : { 18107 const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1); 18108 t *ptrd = res._data; 18109 for (unsigned int siz = _width*_height*_depth; siz; --siz) { 18110 *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); 18111 } 18112 } break; 18113 case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB 18114 const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); 18115 t *ptrd = res._data; 18116 for (unsigned int siz = _width*_height*_depth; siz; --siz) { 18117 *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++); 18118 } 18119 } break; 18120 case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA 18121 const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); 18122 t *ptrd = res._data; 18123 for (unsigned int siz = _width*_height*_depth; siz; --siz) { 18124 *(ptrd++) = (t)*(ptr_r++); *(ptrd++) = (t)*(ptr_g++); *(ptrd++) = (t)*(ptr_b++); *(ptrd++) = (t)*(ptr_a++); 18125 } 18126 } break; 18127 default : { 18128 cimg_forXYZC(*this,x,y,z,c) res(c,x,y,z) = (t)*(ptrs++); 18129 } 18130 } 18131 } 18132 if (!cimg::strncasecmp(permut,"cxzy",4)) { 18133 res.assign(_spectrum,_width,_depth,_height); 18134 cimg_forXYZC(*this,x,y,z,c) res(c,x,z,y) = (t)*(ptrs++); 18135 } 18136 if (!cimg::strncasecmp(permut,"cyxz",4)) { 18137 res.assign(_spectrum,_height,_width,_depth); 18138 cimg_forXYZC(*this,x,y,z,c) res(c,y,x,z) = (t)*(ptrs++); 18139 } 18140 if (!cimg::strncasecmp(permut,"cyzx",4)) { 18141 res.assign(_spectrum,_height,_depth,_width); 18142 cimg_forXYZC(*this,x,y,z,c) res(c,y,z,x) = (t)*(ptrs++); 18143 } 18144 if (!cimg::strncasecmp(permut,"czxy",4)) { 18145 res.assign(_spectrum,_depth,_width,_height); 18146 cimg_forXYZC(*this,x,y,z,c) res(c,z,x,y) = (t)*(ptrs++); 18147 } 18148 if (!cimg::strncasecmp(permut,"czyx",4)) { 18149 res.assign(_spectrum,_depth,_height,_width); 18150 cimg_forXYZC(*this,x,y,z,c) res(c,z,y,x) = (t)*(ptrs++); 18151 } 18152 if (!res) 18153 throw CImgArgumentException(_cimg_instance 18154 "permute_axes() : Invalid specified permutation '%s'.", 18155 cimg_instance, 18156 permut); 18157 return res; 18158 } 18159 18160 //! Permute axes order. 18161 /** 18162 This function permutes image axes. 18163 \param permut = String describing the permutation (4 characters). 18164 **/ 18165 CImg<T>& permute_axes(const char *const order) { 18166 return get_permute_axes(order).move_to(*this); 18167 } 18168 18169 CImg<T> get_permute_axes(const char *const order) const { 18170 const T foo = (T)0; 18171 return _get_permute_axes(order,foo); 18172 } 18173 18174 //! Unroll all images values into specified axis. 18175 CImg<T>& unroll(const char axis) { 18176 const unsigned int siz = size(); 18177 if (siz) switch (axis) { 18178 case 'x' : _width = siz; _height = _depth = _spectrum = 1; break; 18179 case 'y' : _height = siz; _width = _depth = _spectrum = 1; break; 18180 case 'z' : _depth = siz; _width = _height = _spectrum = 1; break; 18181 default : _spectrum = siz; _width = _height = _depth = 1; 18182 } 18183 return *this; 18184 } 18185 18186 CImg<T> get_unroll(const char axis) const { 18187 return (+*this).unroll(axis); 18188 } 18189 18190 //! Rotate an image. 18191 /** 18192 \param angle = rotation angle (in degrees). 18193 \param cond = rotation type. can be : 18194 - 0 = zero-value at borders 18195 - 1 = nearest pixel. 18196 - 2 = cyclic. 18197 \note Returned image will probably have a different size than the instance image *this. 18198 **/ 18199 CImg<T>& rotate(const float angle, const unsigned int border_conditions=0, const unsigned int interpolation=1) { 18200 return get_rotate(angle,border_conditions,interpolation).move_to(*this); 18201 } 18202 18203 CImg<T> get_rotate(const float angle, const unsigned int border_conditions=0, const unsigned int interpolation=1) const { 18204 if (is_empty()) return *this; 18205 CImg<T> res; 18206 const float nangle = cimg::mod(angle,360.0f); 18207 if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles 18208 const int wm1 = width() - 1, hm1 = height() - 1; 18209 const int iangle = (int)nangle/90; 18210 switch (iangle) { 18211 case 1 : { 18212 res.assign(_height,_width,_depth,_spectrum); 18213 T *ptrd = res._data; 18214 cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(y,hm1-x,z,c); 18215 } break; 18216 case 2 : { 18217 res.assign(_width,_height,_depth,_spectrum); 18218 T *ptrd = res._data; 18219 cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-x,hm1-y,z,c); 18220 } break; 18221 case 3 : { 18222 res.assign(_height,_width,_depth,_spectrum); 18223 T *ptrd = res._data; 18224 cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1-y,x,z,c); 18225 } break; 18226 default : 18227 return *this; 18228 } 18229 } else { // generic version 18230 const float 18231 rad = (float)(nangle*cimg::PI/180.0), 18232 ca = (float)std::cos(rad), 18233 sa = (float)std::sin(rad), 18234 ux = cimg::abs(_width*ca), uy = cimg::abs(_width*sa), 18235 vx = cimg::abs(_height*sa), vy = cimg::abs(_height*ca), 18236 w2 = 0.5f*_width, h2 = 0.5f*_height, 18237 dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy); 18238 res.assign((int)(ux+vx),(int)(uy+vy),_depth,_spectrum); 18239 switch (border_conditions) { 18240 case 0 : { 18241 switch (interpolation) { 18242 case 2 : { 18243 T m, M = max_min(m); 18244 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18245 const Tfloat val = cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0); 18246 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18247 } 18248 } break; 18249 case 1 : { 18250 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18251 res(x,y,z,c) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c,0); 18252 } break; 18253 default : { 18254 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18255 res(x,y,z,c) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c,0); 18256 } 18257 } 18258 } break; 18259 case 1 : { 18260 switch (interpolation) { 18261 case 2 : { 18262 T m, M = max_min(m); 18263 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18264 const Tfloat val = _cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c); 18265 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18266 } 18267 } break; 18268 case 1 : { 18269 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18270 res(x,y,z,c) = (T)_linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,c); 18271 } break; 18272 default : { 18273 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18274 res(x,y,z,c) = _atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,c); 18275 } 18276 } 18277 } break; 18278 case 2 : { 18279 switch (interpolation) { 18280 case 2 : { 18281 T m, M = max_min(m); 18282 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18283 const Tfloat val = _cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()), 18284 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c); 18285 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18286 } 18287 } break; 18288 case 1 : { 18289 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18290 res(x,y,z,c) = (T)_linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)width()), 18291 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)height()),z,c); 18292 } break; 18293 default : { 18294 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18295 res(x,y,z,c) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width()), 18296 cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height()),z,c); 18297 } 18298 } 18299 } break; 18300 default : 18301 throw CImgArgumentException(_cimg_instance 18302 "rotate() : Invalid specified border conditions %d " 18303 "(should be { 0=dirichlet | 1=neumann | 2=cyclic }).", 18304 cimg_instance, 18305 border_conditions); 18306 } 18307 } 18308 return res; 18309 } 18310 18311 //! Rotate an image around a center point (\c cx,\c cy). 18312 /** 18313 \param angle = rotation angle (in degrees). 18314 \param cx = X-coordinate of the rotation center. 18315 \param cy = Y-coordinate of the rotation center. 18316 \param zoom = zoom. 18317 \param cond = rotation type. can be : 18318 - 0 = zero-value at borders 18319 - 1 = repeat image at borders 18320 - 2 = zero-value at borders and linear interpolation 18321 **/ 18322 CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom, 18323 const unsigned int border_conditions=3, const unsigned int interpolation=1) { 18324 return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).move_to(*this); 18325 } 18326 18327 CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom, 18328 const unsigned int border_conditions=3, const unsigned int interpolation=1) const { 18329 if (interpolation>2) 18330 throw CImgArgumentException(_cimg_instance 18331 "rotate() : Invalid specified interpolation %d " 18332 "(should be { 0=none | 1=linear | 2=bicubic }).", 18333 cimg_instance, 18334 interpolation); 18335 18336 if (is_empty()) return *this; 18337 CImg<T> res(_width,_height,_depth,_spectrum); 18338 const float 18339 rad = (float)((angle*cimg::PI)/180.0), 18340 ca = (float)std::cos(rad)/zoom, 18341 sa = (float)std::sin(rad)/zoom; 18342 switch (border_conditions) { 18343 case 0 : { 18344 switch (interpolation) { 18345 case 2 : { 18346 T m, M = max_min(m); 18347 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18348 const Tfloat val = cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0); 18349 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18350 } 18351 } break; 18352 case 1 : { 18353 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18354 res(x,y,z,c) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c,0); 18355 } break; 18356 default : { 18357 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18358 res(x,y,z,c) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c,0); 18359 } 18360 } 18361 } break; 18362 case 1 : { 18363 switch (interpolation) { 18364 case 2 : { 18365 T m, M = max_min(m); 18366 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18367 const Tfloat val = _cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c); 18368 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18369 } 18370 } break; 18371 case 1 : { 18372 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18373 res(x,y,z,c) = (T)_linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,c); 18374 } break; 18375 default : { 18376 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18377 res(x,y,z,c) = _atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,c); 18378 } 18379 } 18380 } break; 18381 case 2 : { 18382 switch (interpolation) { 18383 case 2 : { 18384 T m, M = max_min(m); 18385 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) { 18386 const Tfloat val = _cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()), 18387 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c); 18388 res(x,y,z,c) = (T)(val<m?m:val>M?M:val); 18389 } 18390 } break; 18391 case 1 : { 18392 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18393 res(x,y,z,c) = (T)_linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)width()), 18394 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)height()),z,c); 18395 } break; 18396 default : { 18397 cimg_forXY(res,x,y) cimg_forZC(*this,z,c) 18398 res(x,y,z,c) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width()), 18399 cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height()),z,c); 18400 } 18401 } 18402 } break; 18403 default : 18404 throw CImgArgumentException(_cimg_instance 18405 "rotate() : Invalid specified border conditions %d " 18406 "(should be { 0=dirichlet | 1=neumann | 2=cyclic }).", 18407 cimg_instance, 18408 border_conditions); 18409 } 18410 return res; 18411 } 18412 18413 //! Warp an image. 18414 template<typename t> 18415 CImg<T>& warp(const CImg<t>& warp, const bool relative=false, 18416 const bool interpolation=true, const unsigned int border_conditions=0) { 18417 return get_warp(warp,relative,interpolation,border_conditions).move_to(*this); 18418 } 18419 18420 template<typename t> 18421 CImg<T> get_warp(const CImg<t>& warp, const bool relative=false, 18422 const bool interpolation=true, const unsigned int border_conditions=0) const { 18423 if (is_empty() || !warp) return *this; 18424 if (relative && !is_sameXYZ(warp)) 18425 throw CImgArgumentException(_cimg_instance 18426 "warp() : Instance and specified relative warping field (%u,%u,%u,%u,%p) " 18427 "have different XYZ dimensions.", 18428 cimg_instance, 18429 warp._width,warp._height,warp._depth,warp._spectrum,warp._data); 18430 18431 CImg<T> res(warp._width,warp._height,warp._depth,_spectrum); 18432 T *ptrd = res._data; 18433 switch (warp._spectrum) { 18434 case 1 : // 1d warping. 18435 if (relative) { // Relative warp coordinates 18436 if (interpolation) switch (border_conditions) { 18437 case 2 : { 18438 cimg_forC(res,c) { 18439 const t *ptrs0 = warp._data; 18440 cimg_forXYZ(res,x,y,z) 18441 *(ptrd++) = (T)_linear_atX(cimg::mod(x - (float)*(ptrs0++),(float)_width),y,z,c); 18442 } 18443 } break; 18444 case 1 : { 18445 cimg_forC(res,c) { 18446 const t *ptrs0 = warp._data; 18447 cimg_forXYZ(res,x,y,z) 18448 *(ptrd++) = (T)_linear_atX(x-(float)*(ptrs0++),y,z,c); 18449 } 18450 } break; 18451 default : { 18452 cimg_forC(res,c) { 18453 const t *ptrs0 = warp._data; 18454 cimg_forXYZ(res,x,y,z) 18455 *(ptrd++) = (T)linear_atX(x-(float)*(ptrs0++),y,z,c,0); 18456 } 18457 } 18458 } else switch (border_conditions) { 18459 case 2 : { 18460 cimg_forC(res,c) { 18461 const t *ptrs0 = warp._data; 18462 cimg_forXYZ(res,x,y,z) 18463 *(ptrd++) = (*this)(cimg::mod(x - (int)*(ptrs0++),(int)_width),y,z,c); 18464 } 18465 } break; 18466 case 1 : { 18467 cimg_forC(res,c) { 18468 const t *ptrs0 = warp._data; 18469 cimg_forXYZ(res,x,y,z) 18470 *(ptrd++) = _atX(x-(int)*(ptrs0++),y,z,c); 18471 } 18472 } break; 18473 default : { 18474 cimg_forC(res,c) { 18475 const t *ptrs0 = warp._data; 18476 cimg_forXYZ(res,x,y,z) 18477 *(ptrd++) = atX(x-(int)*(ptrs0++),y,z,c,0); 18478 } 18479 } 18480 } 18481 } else { // Absolute warp coordinates 18482 if (interpolation) switch (border_conditions) { 18483 case 2 : { 18484 cimg_forC(res,c) { 18485 const t *ptrs0 = warp._data; 18486 cimg_forXYZ(res,x,y,z) 18487 *(ptrd++) = (T)_linear_atX(cimg::mod((float)*(ptrs0++),(float)_width),y,z,c); 18488 } 18489 } break; 18490 case 1 : { 18491 cimg_forC(res,c) { 18492 const t *ptrs0 = warp._data; 18493 cimg_forXYZ(res,x,y,z) 18494 *(ptrd++) = (T)_linear_atX((float)*(ptrs0++),y,z,c); 18495 } 18496 } break; 18497 default : { 18498 cimg_forC(res,c) { 18499 const t *ptrs0 = warp._data; 18500 cimg_forXYZ(res,x,y,z) 18501 *(ptrd++) = (T)linear_atX((float)*(ptrs0++),y,z,c,0); 18502 } 18503 } 18504 } else switch (border_conditions) { 18505 case 2 : { 18506 cimg_forC(res,c) { 18507 const t *ptrs0 = warp._data; 18508 cimg_forXYZ(res,x,y,z) 18509 *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width),y,z,c); 18510 } 18511 } break; 18512 case 1 : { 18513 cimg_forC(res,c) { 18514 const t *ptrs0 = warp._data; 18515 cimg_forXYZ(res,x,y,z) 18516 *(ptrd++) = _atX((int)*(ptrs0++),y,z,c); 18517 } 18518 } break; 18519 default : { 18520 cimg_forC(res,c) { 18521 const t *ptrs0 = warp._data; 18522 cimg_forXYZ(res,x,y,z) 18523 *(ptrd++) = atX((int)*(ptrs0++),y,z,c,0); 18524 } 18525 } 18526 } 18527 } 18528 break; 18529 18530 case 2 : // 2d warping 18531 if (relative) { // Relative warp coordinates 18532 if (interpolation) switch (border_conditions) { 18533 case 2 : { 18534 cimg_forC(res,c) { 18535 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18536 cimg_forXYZ(res,x,y,z) 18537 *(ptrd++) = (T)_linear_atXY(cimg::mod(x-(float)*(ptrs0++),(float)_width), 18538 cimg::mod(y-(float)*(ptrs1++),(float)_height),z,c); 18539 } 18540 } break; 18541 case 1 : { 18542 cimg_forC(res,c) { 18543 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18544 cimg_forXYZ(res,x,y,z) 18545 *(ptrd++) = (T)_linear_atXY(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z,c); 18546 } 18547 } break; 18548 default : { 18549 cimg_forC(res,c) { 18550 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18551 cimg_forXYZ(res,x,y,z) 18552 *(ptrd++) = (T)linear_atXY(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z,c,0); 18553 } 18554 } 18555 } else switch (border_conditions) { 18556 case 2 : { 18557 cimg_forC(res,c) { 18558 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18559 cimg_forXYZ(res,x,y,z) 18560 *(ptrd++) = (*this)(cimg::mod(x-(int)*(ptrs0++),(int)_width), 18561 cimg::mod(y-(int)*(ptrs1++),(int)_height),z,c); 18562 } 18563 } break; 18564 case 1 : { 18565 cimg_forC(res,c) { 18566 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18567 cimg_forXYZ(res,x,y,z) 18568 *(ptrd++) = _atXY(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z,c); 18569 } 18570 } break; 18571 default : { 18572 cimg_forC(res,c) { 18573 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18574 cimg_forXYZ(res,x,y,z) 18575 *(ptrd++) = atXY(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z,c,0); 18576 } 18577 } 18578 } 18579 } else { // Absolute warp coordinates 18580 if (interpolation) switch (border_conditions) { 18581 case 2 : { 18582 cimg_forC(res,c) { 18583 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18584 cimg_forXYZ(res,x,y,z) 18585 *(ptrd++) = (T)_linear_atXY(cimg::mod((float)*(ptrs0++),(float)_width), 18586 cimg::mod((float)*(ptrs1++),(float)_height),z,c); 18587 } 18588 } break; 18589 case 1 : { 18590 cimg_forC(res,c) { 18591 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18592 cimg_forXYZ(res,x,y,z) 18593 *(ptrd++) = (T)_linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),z,c); 18594 } 18595 } break; 18596 default : { 18597 cimg_forC(res,c) { 18598 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18599 cimg_forXYZ(res,x,y,z) 18600 *(ptrd++) = (T)linear_atXY((float)*(ptrs0++),(float)*(ptrs1++),z,c,0); 18601 } 18602 } 18603 } else switch (border_conditions) { 18604 case 2 : { 18605 cimg_forC(res,c) { 18606 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18607 cimg_forXYZ(res,x,y,z) 18608 *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width), 18609 cimg::mod((int)*(ptrs1++),(int)_height),z,c); 18610 } 18611 } break; 18612 case 1 : { 18613 cimg_forC(res,c) { 18614 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18615 cimg_forXYZ(res,x,y,z) 18616 *(ptrd++) = _atXY((int)*(ptrs0++),(int)*(ptrs1++),z,c); 18617 } 18618 } break; 18619 default : { 18620 cimg_forC(res,c) { 18621 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1); 18622 cimg_forXYZ(res,x,y,z) 18623 *(ptrd++) = atXY((int)*(ptrs0++),(int)*(ptrs1++),z,c,0); 18624 } 18625 } 18626 } 18627 } 18628 break; 18629 18630 case 3 : // 3d warping 18631 if (relative) { // Relative warp coordinates 18632 if (interpolation) switch (border_conditions) { 18633 case 2 : { 18634 cimg_forC(res,c) { 18635 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18636 cimg_forXYZ(res,x,y,z) 18637 *(ptrd++) = (T)_linear_atXYZ(cimg::mod(x-(float)*(ptrs0++),(float)_width), 18638 cimg::mod(y-(float)*(ptrs1++),(float)_height), 18639 cimg::mod(z-(float)*(ptrs2++),(float)_depth),c); 18640 } 18641 } break; 18642 case 1 : { 18643 cimg_forC(res,c) { 18644 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18645 cimg_forXYZ(res,x,y,z) 18646 *(ptrd++) = (T)_linear_atXYZ(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z-(float)*(ptrs2++),c); 18647 } 18648 } break; 18649 default : { 18650 cimg_forC(res,c) { 18651 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18652 cimg_forXYZ(res,x,y,z) 18653 *(ptrd++) = (T)linear_atXYZ(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z-(float)*(ptrs2++),c,0); 18654 } 18655 } 18656 } else switch (border_conditions) { 18657 case 2 : { 18658 cimg_forC(res,c) { 18659 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18660 cimg_forXYZ(res,x,y,z) 18661 *(ptrd++) = (*this)(cimg::mod(x-(int)*(ptrs0++),(int)_width), 18662 cimg::mod(y-(int)*(ptrs1++),(int)_height), 18663 cimg::mod(z-(int)*(ptrs2++),(int)_depth),c); 18664 } 18665 } break; 18666 case 1 : { 18667 cimg_forC(res,c) { 18668 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18669 cimg_forXYZ(res,x,y,z) 18670 *(ptrd++) = _atXYZ(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z-(int)*(ptrs2++),c); 18671 } 18672 } break; 18673 default : { 18674 cimg_forC(res,c) { 18675 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18676 cimg_forXYZ(res,x,y,z) 18677 *(ptrd++) = atXYZ(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z-(int)*(ptrs2++),c,0); 18678 } 18679 } 18680 } 18681 } else { // Absolute warp coordinates 18682 if (interpolation) switch (border_conditions) { 18683 case 2 : { 18684 cimg_forC(res,c) { 18685 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18686 cimg_forXYZ(res,x,y,z) 18687 *(ptrd++) = (T)_linear_atXYZ(cimg::mod((float)*(ptrs0++),(float)_width), 18688 cimg::mod((float)*(ptrs1++),(float)_height), 18689 cimg::mod((float)*(ptrs2++),(float)_depth),c); 18690 } 18691 } break; 18692 case 1 : { 18693 cimg_forC(res,c) { 18694 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18695 cimg_forXYZ(res,x,y,z) 18696 *(ptrd++) = (T)_linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); 18697 } 18698 } break; 18699 default : { 18700 cimg_forC(res,c) { 18701 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18702 cimg_forXYZ(res,x,y,z) 18703 *(ptrd++) = (T)linear_atXYZ((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c,0); 18704 } 18705 } 18706 } else switch (border_conditions) { 18707 case 2 : { 18708 cimg_forC(res,c) { 18709 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18710 cimg_forXYZ(res,x,y,z) 18711 *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width), 18712 cimg::mod((int)*(ptrs1++),(int)_height), 18713 cimg::mod((int)*(ptrs2++),(int)_depth),c); 18714 } 18715 } break; 18716 case 1 : { 18717 cimg_forC(res,c) { 18718 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18719 cimg_forXYZ(res,x,y,z) 18720 *(ptrd++) = _atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c); 18721 } 18722 } break; 18723 default : { 18724 cimg_forC(res,c) { 18725 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2); 18726 cimg_forXYZ(res,x,y,z) 18727 *(ptrd++) = atXYZ((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),c,0); 18728 } 18729 } 18730 } 18731 } 18732 break; 18733 18734 default : // 4d warping 18735 if (relative) { // Relative warp coordinates 18736 if (interpolation) switch (border_conditions) { 18737 case 2 : { 18738 cimg_forC(res,c) { 18739 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18740 cimg_forXYZ(res,x,y,z) 18741 *(ptrd++) = (T)_linear_atXYZC(cimg::mod(x-(float)*(ptrs0++),(float)_width), 18742 cimg::mod(y-(float)*(ptrs1++),(float)_height), 18743 cimg::mod(z-(float)*(ptrs2++),(float)_depth), 18744 cimg::mod(c-(float)*(ptrs3++),(float)_spectrum)); 18745 } 18746 } break; 18747 case 1 : { 18748 cimg_forC(res,c) { 18749 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18750 cimg_forXYZ(res,x,y,z) 18751 *(ptrd++) = (T)_linear_atXYZC(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z-(float)*(ptrs2++),c-(float)*(ptrs3++)); 18752 } 18753 } break; 18754 default : { 18755 cimg_forC(res,c) { 18756 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18757 cimg_forXYZ(res,x,y,z) 18758 *(ptrd++) = (T)linear_atXYZC(x-(float)*(ptrs0++),y-(float)*(ptrs1++),z-(float)*(ptrs2++),c-(float)*(ptrs3++),0); 18759 } 18760 } 18761 } else switch (border_conditions) { 18762 case 2 : { 18763 cimg_forC(res,c) { 18764 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18765 cimg_forXYZ(res,x,y,z) 18766 *(ptrd++) = (*this)(cimg::mod(x-(int)*(ptrs0++),(int)_width), 18767 cimg::mod(y-(int)*(ptrs1++),(int)_height), 18768 cimg::mod(z-(int)*(ptrs2++),(int)_depth), 18769 cimg::mod(c-(int)*(ptrs3++),(int)_spectrum)); 18770 } 18771 } break; 18772 case 1 : { 18773 cimg_forC(res,c) { 18774 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18775 cimg_forXYZ(res,x,y,z) 18776 *(ptrd++) = _atXYZC(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z-(int)*(ptrs2++),c-(int)*(ptrs3++)); 18777 } 18778 } break; 18779 default : { 18780 cimg_forC(res,c) { 18781 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18782 cimg_forXYZ(res,x,y,z) 18783 *(ptrd++) = atXYZ(x-(int)*(ptrs0++),y-(int)*(ptrs1++),z-(int)*(ptrs2++),c-(int)*(ptrs3++),0); 18784 } 18785 } 18786 } 18787 } else { // Absolute warp coordinates 18788 if (interpolation) switch (border_conditions) { 18789 case 2 : { 18790 cimg_forC(res,c) { 18791 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18792 cimg_forXYZ(res,x,y,z) 18793 *(ptrd++) = (T)_linear_atXYZC(cimg::mod((float)*(ptrs0++),(float)_width), 18794 cimg::mod((float)*(ptrs1++),(float)_height), 18795 cimg::mod((float)*(ptrs2++),(float)_depth), 18796 cimg::mod((float)*(ptrs3++),(float)_spectrum)); 18797 } 18798 } break; 18799 case 1 : { 18800 cimg_forC(res,c) { 18801 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18802 cimg_forXYZ(res,x,y,z) 18803 *(ptrd++) = (T)_linear_atXYZC((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),(float)*(ptrs3++)); 18804 } 18805 } break; 18806 default : { 18807 cimg_forC(res,c) { 18808 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18809 cimg_forXYZ(res,x,y,z) 18810 *(ptrd++) = (T)linear_atXYZC((float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),(float)*(ptrs3++),0); 18811 } 18812 } 18813 } else switch (border_conditions) { 18814 case 2 : { 18815 cimg_forC(res,c) { 18816 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18817 cimg_forXYZ(res,x,y,z) 18818 *(ptrd++) = (*this)(cimg::mod((int)*(ptrs0++),(int)_width), 18819 cimg::mod((int)*(ptrs1++),(int)_height), 18820 cimg::mod((int)*(ptrs2++),(int)_depth), 18821 cimg::mod((int)*(ptrs3++),(int)_spectrum)); 18822 } 18823 } break; 18824 case 1 : { 18825 cimg_forC(res,c) { 18826 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18827 cimg_forXYZ(res,x,y,z) 18828 *(ptrd++) = _atXYZC((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),(int)*(ptrs3++)); 18829 } 18830 } break; 18831 default : { 18832 cimg_forC(res,c) { 18833 const t *ptrs0 = warp.data(0,0,0,0), *ptrs1 = warp.data(0,0,0,1), *ptrs2 = warp.data(0,0,0,2), *ptrs3 = warp.data(0,0,0,3); 18834 cimg_forXYZ(res,x,y,z) 18835 *(ptrd++) = atXYZC((int)*(ptrs0++),(int)*(ptrs1++),(int)*(ptrs2++),(int)*(ptrs3++),0); 18836 } 18837 } 18838 } 18839 } 18840 } 18841 return res; 18842 } 18843 18844 //! Return a 2d representation of a 3d image, with three slices. 18845 CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0, 18846 const int dx=-100, const int dy=-100, const int dz=-100) { 18847 return get_projections2d(x0,y0,z0,dx,dy,dz).move_to(*this); 18848 } 18849 18850 CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0, 18851 const int dx=-100, const int dy=-100, const int dz=-100) const { 18852 if (is_empty()) return *this; 18853 const unsigned int 18854 nx0 = (x0>=_width)?_width - 1:x0, 18855 ny0 = (y0>=_height)?_height - 1:y0, 18856 nz0 = (z0>=_depth)?_depth - 1:z0; 18857 CImg<T> 18858 imgxy(_width,_height,1,_spectrum), 18859 imgzy(_depth,_height,1,_spectrum), 18860 imgxz(_width,_depth,1,_spectrum); 18861 cimg_forXYC(*this,x,y,c) imgxy(x,y,c) = (*this)(x,y,nz0,c); 18862 cimg_forYZC(*this,y,z,c) imgzy(z,y,c) = (*this)(nx0,y,z,c); 18863 cimg_forXZC(*this,x,z,c) imgxz(x,z,c) = (*this)(x,ny0,z,c); 18864 imgxy.resize(dx,dy,1,_spectrum,1); 18865 imgzy.resize(dz,dy,1,_spectrum,1); 18866 imgxz.resize(dx,dz,1,_spectrum,1); 18867 return CImg<T>(imgxy._width + imgzy._width,imgxy._height + imgxz._height,1,_spectrum,cimg::min(imgxy.min(),imgzy.min(),imgxz.min())). 18868 draw_image(imgxy).draw_image(imgxy._width,imgzy).draw_image(0,imgxy._height,imgxz); 18869 } 18870 18871 //! Get a square region of the image. 18872 /** 18873 \param x0 = X-coordinate of the upper-left crop rectangle corner. 18874 \param y0 = Y-coordinate of the upper-left crop rectangle corner. 18875 \param z0 = Z-coordinate of the upper-left crop rectangle corner. 18876 \param c0 = C-coordinate of the upper-left crop rectangle corner. 18877 \param x1 = X-coordinate of the lower-right crop rectangle corner. 18878 \param y1 = Y-coordinate of the lower-right crop rectangle corner. 18879 \param z1 = Z-coordinate of the lower-right crop rectangle corner. 18880 \param c1 = C-coordinate of the lower-right crop rectangle corner. 18881 \param border_condition = Dirichlet (false) or Neumann border conditions. 18882 **/ 18883 CImg<T>& crop(const int x0, const int y0, const int z0, const int c0, 18884 const int x1, const int y1, const int z1, const int c1, 18885 const bool border_condition=false) { 18886 return get_crop(x0,y0,z0,c0,x1,y1,z1,c1,border_condition).move_to(*this); 18887 } 18888 18889 CImg<T> get_crop(const int x0, const int y0, const int z0, const int c0, 18890 const int x1, const int y1, const int z1, const int c1, 18891 const bool border_condition=false) const { 18892 if (is_empty()) return *this; 18893 const int 18894 nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0, 18895 ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0, 18896 nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0, 18897 nc0 = c0<c1?c0:c1, nc1 = c0^c1^nc0; 18898 CImg<T> res(1U + nx1 - nx0,1U + ny1 - ny0,1U + nz1 - nz0,1U + nc1 - nc0); 18899 if (nx0<0 || nx1>=width() || ny0<0 || ny1>=height() || nz0<0 || nz1>=depth() || nc0<0 || nc1>=spectrum()) { 18900 if (border_condition) cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0+x,ny0+y,nz0+z,nc0+c); 18901 else res.fill(0).draw_image(-nx0,-ny0,-nz0,-nc0,*this); 18902 } else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this); 18903 return res; 18904 } 18905 18906 //! Get a rectangular part of the instance image. 18907 /** 18908 \param x0 = X-coordinate of the upper-left crop rectangle corner. 18909 \param y0 = Y-coordinate of the upper-left crop rectangle corner. 18910 \param z0 = Z-coordinate of the upper-left crop rectangle corner. 18911 \param x1 = X-coordinate of the lower-right crop rectangle corner. 18912 \param y1 = Y-coordinate of the lower-right crop rectangle corner. 18913 \param z1 = Z-coordinate of the lower-right crop rectangle corner. 18914 \param border_condition = determine the type of border condition if 18915 some of the desired region is outside the image. 18916 **/ 18917 CImg<T>& crop(const int x0, const int y0, const int z0, 18918 const int x1, const int y1, const int z1, 18919 const bool border_condition=false) { 18920 return crop(x0,y0,z0,0,x1,y1,z1,_spectrum-1,border_condition); 18921 } 18922 18923 CImg<T> get_crop(const int x0, const int y0, const int z0, 18924 const int x1, const int y1, const int z1, 18925 const bool border_condition=false) const { 18926 return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum-1,border_condition); 18927 } 18928 18929 //! Get a rectangular part of the instance image. 18930 /** 18931 \param x0 = X-coordinate of the upper-left crop rectangle corner. 18932 \param y0 = Y-coordinate of the upper-left crop rectangle corner. 18933 \param x1 = X-coordinate of the lower-right crop rectangle corner. 18934 \param y1 = Y-coordinate of the lower-right crop rectangle corner. 18935 \param border_condition = determine the type of border condition if 18936 some of the desired region is outside the image. 18937 **/ 18938 CImg<T>& crop(const int x0, const int y0, 18939 const int x1, const int y1, 18940 const bool border_condition=false) { 18941 return crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,border_condition); 18942 } 18943 18944 CImg<T> get_crop(const int x0, const int y0, 18945 const int x1, const int y1, 18946 const bool border_condition=false) const { 18947 return get_crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,border_condition); 18948 } 18949 18950 //! Get a rectangular part of the instance image. 18951 /** 18952 \param x0 = X-coordinate of the upper-left crop rectangle corner. 18953 \param x1 = X-coordinate of the lower-right crop rectangle corner. 18954 \param border_condition = determine the type of border condition if 18955 some of the desired region is outside the image. 18956 **/ 18957 CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) { 18958 return crop(x0,0,0,0,x1,_height-1,_depth-1,_spectrum-1,border_condition); 18959 } 18960 18961 CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const { 18962 return get_crop(x0,0,0,0,x1,_height-1,_depth-1,_spectrum-1,border_condition); 18963 } 18964 18965 //! Autocrop an image, regarding of the specified backround value. 18966 CImg<T>& autocrop(const T value, const char *const axes="czyx") { 18967 if (is_empty()) return *this; 18968 for (const char *s = axes; *s; ++s) { 18969 const char axis = cimg::uncase(*s); 18970 const CImg<intT> coords = _autocrop(value,axis); 18971 switch (axis) { 18972 case 'x' : { 18973 const int x0 = coords[0], x1 = coords[1]; 18974 if (x0>=0 && x1>=0) crop(x0,x1); 18975 } break; 18976 case 'y' : { 18977 const int y0 = coords[0], y1 = coords[1]; 18978 if (y0>=0 && y1>=0) crop(0,y0,_width-1,y1); 18979 } break; 18980 case 'z' : { 18981 const int z0 = coords[0], z1 = coords[1]; 18982 if (z0>=0 && z1>=0) crop(0,0,z0,_width-1,_height-1,z1); 18983 } break; 18984 default : { 18985 const int c0 = coords[0], c1 = coords[1]; 18986 if (c0>=0 && c1>=0) crop(0,0,0,c0,_width-1,_height-1,_depth-1,c1); 18987 } 18988 } 18989 } 18990 return *this; 18991 } 18992 18993 CImg<T> get_autocrop(const T value, const char *const axes="czyx") const { 18994 return (+*this).autocrop(value,axes); 18995 } 18996 18997 //! Autocrop an image, regarding of the specified backround color. 18998 CImg<T>& autocrop(const T *const color, const char *const axes="zyx") { 18999 if (is_empty()) return *this; 19000 for (const char *s = axes; *s; ++s) { 19001 const char axis = cimg::uncase(*s); 19002 switch (axis) { 19003 case 'x' : { 19004 int x0 = _width, x1 = -1; 19005 cimg_forC(*this,c) { 19006 const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'x'); 19007 const int nx0 = coords[0], nx1 = coords[1]; 19008 if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); } 19009 } 19010 if (x0<=x1) crop(x0,x1); 19011 } break; 19012 case 'y' : { 19013 int y0 = _height, y1 = -1; 19014 cimg_forC(*this,c) { 19015 const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'y'); 19016 const int ny0 = coords[0], ny1 = coords[1]; 19017 if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); } 19018 } 19019 if (y0<=y1) crop(0,y0,_width-1,y1); 19020 } break; 19021 default : { 19022 int z0 = _depth, z1 = -1; 19023 cimg_forC(*this,c) { 19024 const CImg<intT> coords = get_shared_channel(c)._autocrop(color[c],'z'); 19025 const int nz0 = coords[0], nz1 = coords[1]; 19026 if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); } 19027 } 19028 if (z0<=z1) crop(0,0,z0,_width-1,_height-1,z1); 19029 } 19030 } 19031 } 19032 return *this; 19033 } 19034 19035 CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const { 19036 return (+*this).autocrop(color,axes); 19037 } 19038 19039 //! Autocrop an image, regarding of the specified backround color. 19040 template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") { 19041 return get_autocrop(color,axes).move_to(*this); 19042 } 19043 19044 template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const { 19045 return get_autocrop(color._data,axes); 19046 } 19047 19048 CImg<intT> _autocrop(const T value, const char axis) const { 19049 CImg<intT> res; 19050 int x0 = -1, y0 = -1, z0 = -1, c0 = -1, x1 = -1, y1 = -1, z1 = -1, c1 = -1; 19051 switch (cimg::uncase(axis)) { 19052 case 'x' : { 19053 cimg_forX(*this,x) cimg_forYZC(*this,y,z,c) 19054 if ((*this)(x,y,z,c)!=value) { x0 = x; x = width(); y = height(); z = depth(); c = spectrum(); } 19055 if (x0>=0) { 19056 for (int x = width()-1; x>=0; --x) cimg_forYZC(*this,y,z,c) 19057 if ((*this)(x,y,z,c)!=value) { x1 = x; x = 0; y = height(); z = depth(); c = spectrum(); } 19058 } 19059 res = CImg<intT>::vector(x0,x1); 19060 } break; 19061 case 'y' : { 19062 cimg_forY(*this,y) cimg_forXZC(*this,x,z,c) 19063 if ((*this)(x,y,z,c)!=value) { y0 = y; x = width(); y = height(); z = depth(); c = spectrum(); } 19064 if (y0>=0) { 19065 for (int y = height()-1; y>=0; --y) cimg_forXZC(*this,x,z,c) 19066 if ((*this)(x,y,z,c)!=value) { y1 = y; x = width(); y = 0; z = depth(); c = spectrum(); } 19067 } 19068 res = CImg<intT>::vector(y0,y1); 19069 } break; 19070 case 'z' : { 19071 cimg_forZ(*this,z) cimg_forXYC(*this,x,y,c) 19072 if ((*this)(x,y,z,c)!=value) { z0 = z; x = width(); y = height(); z = depth(); c = spectrum(); } 19073 if (z0>=0) { 19074 for (int z = depth()-1; z>=0; --z) cimg_forXYC(*this,x,y,c) 19075 if ((*this)(x,y,z,c)!=value) { z1 = z; x = width(); y = height(); z = 0; c = spectrum(); } 19076 } 19077 res = CImg<intT>::vector(z0,z1); 19078 } break; 19079 default : { 19080 cimg_forC(*this,c) cimg_forXYZ(*this,x,y,z) 19081 if ((*this)(x,y,z,c)!=value) { c0 = c; x = width(); y = height(); z = depth(); c = spectrum(); } 19082 if (c0>=0) { 19083 for (int c = spectrum()-1; c>=0; --c) cimg_forXYZ(*this,x,y,z) 19084 if ((*this)(x,y,z,c)!=value) { c1 = c; x = width(); y = height(); z = depth(); c = 0; } 19085 } 19086 res = CImg<intT>::vector(c0,c1); 19087 } 19088 } 19089 return res; 19090 } 19091 19092 //! Get one column. 19093 CImg<T>& column(const unsigned int x0) { 19094 return columns(x0,x0); 19095 } 19096 19097 CImg<T> get_column(const unsigned int x0) const { 19098 return get_columns(x0,x0); 19099 } 19100 19101 //! Get a set of columns. 19102 CImg<T>& columns(const unsigned int x0, const unsigned int x1) { 19103 return get_columns(x0,x1).move_to(*this); 19104 } 19105 19106 CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const { 19107 return get_crop((int)x0,0,0,0,(int)x1,height()-1,depth()-1,spectrum()-1); 19108 } 19109 19110 //! Get a line. 19111 CImg<T>& line(const unsigned int y0) { 19112 return lines(y0,y0); 19113 } 19114 19115 CImg<T> get_line(const unsigned int y0) const { 19116 return get_lines(y0,y0); 19117 } 19118 19119 //! Get a set of lines. 19120 CImg<T>& lines(const unsigned int y0, const unsigned int y1) { 19121 return get_lines(y0,y1).move_to(*this); 19122 } 19123 19124 CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const { 19125 return get_crop(0,(int)y0,0,0,width()-1,(int)y1,depth()-1,spectrum()-1); 19126 } 19127 19128 //! Get a slice. 19129 CImg<T>& slice(const unsigned int z0) { 19130 return slices(z0,z0); 19131 } 19132 19133 CImg<T> get_slice(const unsigned int z0) const { 19134 return get_slices(z0,z0); 19135 } 19136 19137 //! Get a set of slices. 19138 CImg<T>& slices(const unsigned int z0, const unsigned int z1) { 19139 return get_slices(z0,z1).move_to(*this); 19140 } 19141 19142 CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const { 19143 return get_crop(0,0,(int)z0,0,width()-1,height()-1,(int)z1,spectrum()-1); 19144 } 19145 19146 //! Get a channel. 19147 CImg<T>& channel(const unsigned int c0) { 19148 return channels(c0,c0); 19149 } 19150 19151 CImg<T> get_channel(const unsigned int c0) const { 19152 return get_channels(c0,c0); 19153 } 19154 19155 //! Get a set of channels. 19156 CImg<T>& channels(const unsigned int c0, const unsigned int c1) { 19157 return get_channels(c0,c1).move_to(*this); 19158 } 19159 19160 CImg<T> get_channels(const unsigned int c0, const unsigned int c1) const { 19161 return get_crop(0,0,0,(int)c0,width()-1,height()-1,depth()-1,(int)c1); 19162 } 19163 19164 //! Get a shared-memory image referencing a set of points of the instance image. 19165 CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1, 19166 const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) { 19167 const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = offset(x1,y0,z0,c0); 19168 if (beg>end || beg>=size() || end>=size()) 19169 throw CImgArgumentException(_cimg_instance 19170 "get_shared_points() : Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", 19171 cimg_instance, 19172 x0,x1,y0,z0,c0); 19173 19174 return CImg<T>(_data+beg,x1-x0+1,1,1,1,true); 19175 } 19176 19177 const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1, 19178 const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const { 19179 const unsigned int beg = (unsigned int)offset(x0,y0,z0,c0), end = offset(x1,y0,z0,c0); 19180 if (beg>end || beg>=size() || end>=size()) 19181 throw CImgArgumentException(_cimg_instance 19182 "get_shared_points() : Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", 19183 cimg_instance, 19184 x0,x1,y0,z0,c0); 19185 19186 return CImg<T>(_data+beg,x1-x0+1,1,1,1,true); 19187 } 19188 19189 //! Return a shared-memory image referencing a set of lines of the instance image. 19190 CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1, 19191 const unsigned int z0=0, const unsigned int c0=0) { 19192 const unsigned int beg = offset(0,y0,z0,c0), end = offset(0,y1,z0,c0); 19193 if (beg>end || beg>=size() || end>=size()) 19194 throw CImgArgumentException(_cimg_instance 19195 "get_shared_lines() : Invalid request of a shared-memory subset (0->%u,%u->%u,%u,%u).", 19196 cimg_instance, 19197 _width-1,y0,y1,z0,c0); 19198 19199 return CImg<T>(_data+beg,_width,y1-y0+1,1,1,true); 19200 } 19201 19202 const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1, 19203 const unsigned int z0=0, const unsigned int c0=0) const { 19204 const unsigned int beg = offset(0,y0,z0,c0), end = offset(0,y1,z0,c0); 19205 if (beg>end || beg>=size() || end>=size()) 19206 throw CImgArgumentException(_cimg_instance 19207 "get_shared_lines() : Invalid request of a shared-memory subset (0->%u,%u->%u,%u,%u).", 19208 cimg_instance, 19209 _width-1,y0,y1,z0,c0); 19210 19211 return CImg<T>(_data+beg,_width,y1-y0+1,1,1,true); 19212 } 19213 19214 //! Return a shared-memory image referencing one particular line (y0,z0,c0) of the instance image. 19215 CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) { 19216 return get_shared_lines(y0,y0,z0,c0); 19217 } 19218 19219 const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) const { 19220 return get_shared_lines(y0,y0,z0,c0); 19221 } 19222 19223 //! Return a shared memory image referencing a set of planes (z0->z1,c0) of the instance image. 19224 CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) { 19225 const unsigned int beg = offset(0,0,z0,c0), end = offset(0,0,z1,c0); 19226 if (beg>end || beg>=size() || end>=size()) 19227 throw CImgArgumentException(_cimg_instance 19228 "get_shared_planes() : Invalid request of a shared-memory subset (0->%u,0->%u,%u->%u,%u).", 19229 cimg_instance, 19230 _width-1,_height-1,z0,z1,c0); 19231 19232 return CImg<T>(_data+beg,_width,_height,z1-z0+1,1,true); 19233 } 19234 19235 const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) const { 19236 const unsigned int beg = offset(0,0,z0,c0), end = offset(0,0,z1,c0); 19237 if (beg>end || beg>=size() || end>=size()) 19238 throw CImgArgumentException(_cimg_instance 19239 "get_shared_planes() : Invalid request of a shared-memory subset (0->%u,0->%u,%u->%u,%u).", 19240 cimg_instance, 19241 _width-1,_height-1,z0,z1,c0); 19242 19243 return CImg<T>(_data+beg,_width,_height,z1-z0+1,1,true); 19244 } 19245 19246 //! Return a shared-memory image referencing one plane (z0,c0) of the instance image. 19247 CImg<T> get_shared_plane(const unsigned int z0, const unsigned int c0=0) { 19248 return get_shared_planes(z0,z0,c0); 19249 } 19250 19251 const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int c0=0) const { 19252 return get_shared_planes(z0,z0,c0); 19253 } 19254 19255 //! Return a shared-memory image referencing a set of channels (c0->c1) of the instance image. 19256 CImg<T> get_shared_channels(const unsigned int c0, const unsigned int c1) { 19257 const unsigned int beg = offset(0,0,0,c0), end = offset(0,0,0,c1); 19258 if (beg>end || beg>=size() || end>=size()) 19259 throw CImgArgumentException(_cimg_instance 19260 "get_shared_channels() : Invalid request of a shared-memory subset (0->%u,0->%u,0->%u,%u->%u).", 19261 cimg_instance, 19262 _width-1,_height-1,_depth-1,c0,c1); 19263 19264 return CImg<T>(_data+beg,_width,_height,_depth,c1-c0+1,true); 19265 } 19266 19267 const CImg<T> get_shared_channels(const unsigned int c0, const unsigned int c1) const { 19268 const unsigned int beg = offset(0,0,0,c0), end = offset(0,0,0,c1); 19269 if (beg>end || beg>=size() || end>=size()) 19270 throw CImgArgumentException(_cimg_instance 19271 "get_shared_channels() : Invalid request of a shared-memory subset (0->%u,0->%u,0->%u,%u->%u).", 19272 cimg_instance, 19273 _width-1,_height-1,_depth-1,c0,c1); 19274 19275 return CImg<T>(_data+beg,_width,_height,_depth,c1-c0+1,true); 19276 } 19277 19278 //! Return a shared-memory image referencing one channel c0 of the instance image. 19279 CImg<T> get_shared_channel(const unsigned int c0) { 19280 return get_shared_channels(c0,c0); 19281 } 19282 19283 const CImg<T> get_shared_channel(const unsigned int c0) const { 19284 return get_shared_channels(c0,c0); 19285 } 19286 19287 //! Split image into a list. 19288 CImgList<T> get_split(const char axis, const int nb=0) const { 19289 CImgList<T> res; 19290 const char naxis = cimg::uncase(axis); 19291 const unsigned int nnb = (unsigned int)(nb==0?1:(nb>0?nb:-nb)); 19292 if (nb<=0) switch (naxis) { // Split by bloc size 19293 case 'x': { 19294 for (unsigned int p = 0; p<_width; p+=nnb) get_crop(p,0,0,0,cimg::min(p+nnb-1,_width-1),_height-1,_depth-1,_spectrum-1).move_to(res); 19295 } break; 19296 case 'y': { 19297 for (unsigned int p = 0; p<_height; p+=nnb) get_crop(0,p,0,0,_width-1,cimg::min(p+nnb-1,_height-1),_depth-1,_spectrum-1).move_to(res); 19298 } break; 19299 case 'z': { 19300 for (unsigned int p = 0; p<_depth; p+=nnb) get_crop(0,0,p,0,_width-1,_height-1,cimg::min(p+nnb-1,_depth-1),_spectrum-1).move_to(res); 19301 } break; 19302 default: { 19303 for (unsigned int p = 0; p<_spectrum; p+=nnb) get_crop(0,0,0,p,_width-1,_height-1,_depth-1,cimg::min(p+nnb-1,_spectrum-1)).move_to(res); 19304 } 19305 } else { // Split by number of blocs 19306 const unsigned int siz = naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:naxis=='c'?_spectrum:0; 19307 if (nnb>siz) 19308 throw CImgArgumentException(_cimg_instance 19309 "get_split() : Instance cannot be split along %c-axis into %u blocs.", 19310 cimg_instance, 19311 axis,nnb); 19312 res.assign(nnb); 19313 switch (naxis) { 19314 case 'x' : { 19315 cimglist_for(res,p) get_crop(p*siz/nnb,0,0,0,(p+1)*siz/nnb-1,_height-1,_depth-1,_spectrum-1).move_to(res[p]); 19316 } break; 19317 case 'y' : { 19318 cimglist_for(res,p) get_crop(0,p*siz/nnb,0,0,_width-1,(p+1)*siz/nnb-1,_depth-1,_spectrum-1).move_to(res[p]); 19319 } break; 19320 case 'z' : { 19321 cimglist_for(res,p) get_crop(0,0,p*siz/nnb,0,_width-1,_height-1,(p+1)*siz/nnb-1,_spectrum-1).move_to(res[p]); 19322 } break; 19323 default : { 19324 cimglist_for(res,p) get_crop(0,0,0,p*siz/nnb,_width-1,_height-1,_depth-1,(p+1)*siz/nnb-1).move_to(res[p]); 19325 } 19326 } 19327 } 19328 return res; 19329 } 19330 19331 // Split image into a list of vectors, according to a given splitting value. 19332 CImgList<T> get_split(const T value, const bool keep_values, const bool shared, const char axis='y') const { 19333 CImgList<T> res; 19334 const T *ptr0 = _data, *const ptre = _data + size(); 19335 while (ptr0<ptre) { 19336 const T *ptr1 = ptr0; 19337 while (ptr1<ptre && *ptr1==value) ++ptr1; 19338 const unsigned int siz0 = ptr1 - ptr0; 19339 if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared)); 19340 ptr0 = ptr1; 19341 while (ptr1<ptre && *ptr1!=value) ++ptr1; 19342 const unsigned int siz1 = ptr1 - ptr0; 19343 if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared); 19344 ptr0 = ptr1; 19345 } 19346 cimglist_apply(res,unroll)(axis); 19347 return res; 19348 } 19349 19350 //! Append an image. 19351 template<typename t> 19352 CImg<T>& append(const CImg<t>& img, const char axis='x', const char align='p') { 19353 if (is_empty()) return assign(img,false); 19354 if (!img) return *this; 19355 return CImgList<T>(*this,img).get_append(axis,align).move_to(*this); 19356 } 19357 19358 CImg<T>& append(const CImg<T>& img, const char axis='x', const char align='p') { 19359 if (is_empty()) return assign(img,false); 19360 if (!img) return *this; 19361 return CImgList<T>(*this,img,true).get_append(axis,align).move_to(*this); 19362 } 19363 19364 template<typename t> 19365 CImg<_cimg_Tt> get_append(const CImg<T>& img, const char axis='x', const char align='p') const { 19366 if (is_empty()) return +img; 19367 if (!img) return +*this; 19368 return CImgList<_cimg_Tt>(*this,img).get_append(axis,align); 19369 } 19370 19371 CImg<T> get_append(const CImg<T>& img, const char axis='x', const char align='p') const { 19372 if (is_empty()) return +img; 19373 if (!img) return +*this; 19374 return CImgList<T>(*this,img,true).get_append(axis,align); 19375 } 19376 19377 //@} 19378 //--------------------------------------- 19379 // 19380 //! \name Filtering / Transforms 19381 //@{ 19382 //--------------------------------------- 19383 19384 //! Compute the correlation of the instance image by a mask. 19385 /** 19386 The correlation of the instance image \p *this by the mask \p mask is defined to be : 19387 19388 res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k) 19389 19390 \param mask = the correlation kernel. 19391 \param cond = the border condition type (0=zero, 1=dirichlet) 19392 \param weighted_correl = enable local normalization. 19393 **/ 19394 template<typename t> 19395 CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) { 19396 return get_correlate(mask,cond,weighted_correl).move_to(*this); 19397 } 19398 19399 template<typename t> 19400 CImg<_cimg_Ttfloat> get_correlate(const CImg<t>& mask, const unsigned int cond=1, 19401 const bool weighted_correl=false) const { 19402 if (!mask || mask._spectrum!=1) 19403 throw CImgArgumentException(_cimg_instance 19404 "correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", 19405 cimg_instance, 19406 mask._width,mask._height,mask._depth,mask._spectrum,mask._data); 19407 19408 if (is_empty()) return *this; 19409 typedef _cimg_Ttfloat Ttfloat; 19410 CImg<Ttfloat> res(_width,_height,_depth,_spectrum); 19411 Ttfloat *ptrd = res._data; 19412 if (cond && mask._width==mask._height && ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) { 19413 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1) 19414 switch (mask._depth) { 19415 case 3 : { 19416 T I[27] = { 0 }; 19417 cimg_forZC(*this,z,c) cimg_for3x3x3(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19418 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + 19419 I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + 19420 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + 19421 I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] + 19422 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + 19423 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + 19424 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + 19425 I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + 19426 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]); 19427 ptrd = res._data; 19428 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for3x3x3(*this,x,y,z,c,I,T) { 19429 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + 19430 I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + 19431 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + 19432 I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + 19433 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + 19434 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + 19435 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + 19436 I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + 19437 I[24]*I[24] + I[25]*I[25] + I[26]*I[26]); 19438 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19439 ++ptrd; 19440 } 19441 } break; 19442 case 2 : { 19443 T I[8] = { 0 }; 19444 cimg_forZC(*this,z,c) cimg_for2x2x2(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19445 (I[0]*mask[0] + I[1]*mask[1] + 19446 I[2]*mask[2] + I[3]*mask[3] + 19447 I[4]*mask[4] + I[5]*mask[5] + 19448 I[6]*mask[6] + I[7]*mask[7]); 19449 ptrd = res._data; 19450 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for2x2x2(*this,x,y,z,c,I,T) { 19451 const double weight = (double)(I[0]*I[0] + I[1]*I[1] + 19452 I[2]*I[2] + I[3]*I[3] + 19453 I[4]*I[4] + I[5]*I[5] + 19454 I[6]*I[6] + I[7]*I[7]); 19455 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19456 ++ptrd; 19457 } 19458 } break; 19459 default : 19460 case 1 : 19461 switch (mask._width) { 19462 case 6 : { 19463 T I[36] = { 0 }; 19464 cimg_forZC(*this,z,c) cimg_for6x6(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19465 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + 19466 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] + 19467 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + 19468 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + 19469 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] + 19470 I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]); 19471 ptrd = res._data; 19472 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for6x6(*this,x,y,z,c,I,T) { 19473 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] + 19474 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + 19475 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + 19476 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + 19477 I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] + 19478 I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]); 19479 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19480 ++ptrd; 19481 } 19482 } break; 19483 case 5 : { 19484 T I[25] = { 0 }; 19485 cimg_forZC(*this,z,c) cimg_for5x5(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19486 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + 19487 I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + 19488 I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + 19489 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] + 19490 I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]); 19491 ptrd = res._data; 19492 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for5x5(*this,x,y,z,c,I,T) { 19493 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + 19494 I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + 19495 I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + 19496 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] + 19497 I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]); 19498 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19499 ++ptrd; 19500 } 19501 } break; 19502 case 4 : { 19503 T I[16] = { 0 }; 19504 cimg_forZC(*this,z,c) cimg_for4x4(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19505 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + 19506 I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + 19507 I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] + 19508 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]); 19509 ptrd = res._data; 19510 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for4x4(*this,x,y,z,c,I,T) { 19511 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + 19512 I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + 19513 I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] + 19514 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]); 19515 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19516 ++ptrd; 19517 } 19518 } break; 19519 case 3 : { 19520 T I[9] = { 0 }; 19521 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19522 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] + 19523 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] + 19524 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]); 19525 ptrd = res._data; 19526 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) { 19527 const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] + 19528 I[3]*I[3] + I[4]*I[4] + I[5]*I[5] + 19529 I[6]*I[6] + I[7]*I[7] + I[8]*I[8]); 19530 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19531 ++ptrd; 19532 } 19533 } break; 19534 case 2 : { 19535 T I[4] = { 0 }; 19536 cimg_forZC(*this,z,c) cimg_for2x2(*this,x,y,z,c,I,T) *(ptrd++) = (Ttfloat) 19537 (I[0]*mask[0] + I[1]*mask[1] + 19538 I[2]*mask[2] + I[3]*mask[3]); 19539 ptrd = res._data; 19540 if (weighted_correl) cimg_forZC(*this,z,c) cimg_for2x2(*this,x,y,z,c,I,T) { 19541 const double weight = (double)(I[0]*I[0] + I[1]*I[1] + 19542 I[2]*I[2] + I[3]*I[3]); 19543 if (weight>0) *ptrd/=(Ttfloat)std::sqrt(weight); 19544 ++ptrd; 19545 } 19546 } break; 19547 case 1 : (res.assign(*this))*=mask(0); break; 19548 } 19549 } 19550 } else { // Generic version for other masks 19551 const int 19552 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, 19553 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 19554 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 19555 cimg_forC(*this,c) 19556 if (!weighted_correl) { // Classical correlation 19557 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19558 Ttfloat val = 0; 19559 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) 19560 val+=(*this)(x+xm,y+ym,z+zm,c)*mask(mx1+xm,my1+ym,mz1+zm); 19561 res(x,y,z,c) = (Ttfloat)val; 19562 } 19563 if (cond) 19564 cimg_forYZC(*this,y,z,c) 19565 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19566 Ttfloat val = 0; 19567 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) 19568 val+=_atXYZ(x+xm,y+ym,z+zm,c)*mask(mx1+xm,my1+ym,mz1+zm); 19569 res(x,y,z,c) = (Ttfloat)val; 19570 } 19571 else 19572 cimg_forYZC(*this,y,z,c) 19573 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19574 Ttfloat val = 0; 19575 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) 19576 val+=atXYZ(x+xm,y+ym,z+zm,c,0)*mask(mx1+xm,my1+ym,mz1+zm); 19577 res(x,y,z,c) = (Ttfloat)val; 19578 } 19579 } else { // Weighted correlation 19580 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19581 Ttfloat val = 0, weight = 0; 19582 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19583 const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,c); 19584 val+=cval*mask(mx1+xm,my1+ym,mz1+zm); 19585 weight+=cval*cval; 19586 } 19587 res(x,y,z,c) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0; 19588 } 19589 if (cond) 19590 cimg_forYZC(*this,y,z,c) 19591 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19592 Ttfloat val = 0, weight = 0; 19593 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19594 const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,c); 19595 val+=cval*mask(mx1+xm,my1+ym,mz1+zm); 19596 weight+=cval*cval; 19597 } 19598 res(x,y,z,c) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0; 19599 } 19600 else 19601 cimg_forYZC(*this,y,z,c) 19602 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19603 Ttfloat val = 0, weight = 0; 19604 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19605 const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,c,0); 19606 val+=cval*mask(mx1+xm,my1+ym,mz1+zm); 19607 weight+=cval*cval; 19608 } 19609 res(x,y,z,c) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0; 19610 } 19611 } 19612 } 19613 return res; 19614 } 19615 19616 //! Compute the convolution of the image by a mask. 19617 /** 19618 The result \p res of the convolution of an image \p img by a mask \p mask is defined to be : 19619 19620 res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k) 19621 19622 \param mask = the correlation kernel. 19623 \param cond = the border condition type (0=zero, 1=dirichlet) 19624 \param weighted_convol = enable local normalization. 19625 **/ 19626 template<typename t> 19627 CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) { 19628 return get_convolve(mask,cond,weighted_convol).move_to(*this); 19629 } 19630 19631 template<typename t> 19632 CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& mask, const unsigned int cond=1, 19633 const bool weighted_convol=false) const { 19634 if (!mask || mask._spectrum!=1) 19635 throw CImgArgumentException(_cimg_instance 19636 "convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", 19637 cimg_instance, 19638 mask._width,mask._height,mask._depth,mask._spectrum,mask._data); 19639 19640 if (is_empty()) return *this; 19641 return get_correlate(CImg<t>(mask._data,mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol); 19642 } 19643 19644 //! Return the erosion of the image by a structuring element. 19645 template<typename t> 19646 CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) { 19647 return get_erode(mask,cond,weighted_erosion).move_to(*this); 19648 } 19649 19650 template<typename t> 19651 CImg<_cimg_Tt> get_erode(const CImg<t>& mask, const unsigned int cond=1, 19652 const bool weighted_erosion=false) const { 19653 if (!mask || mask._spectrum!=1) 19654 throw CImgArgumentException(_cimg_instance 19655 "erode() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", 19656 cimg_instance, 19657 mask._width,mask._height,mask._depth,mask._spectrum,mask._data); 19658 19659 if (is_empty()) return *this; 19660 typedef _cimg_Tt Tt; 19661 CImg<Tt> res(_width,_height,_depth,_spectrum); 19662 const int 19663 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, 19664 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 19665 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 19666 cimg_forC(*this,c) 19667 if (!weighted_erosion) { // Classical erosion 19668 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19669 Tt min_val = cimg::type<Tt>::max(); 19670 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19671 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,c); 19672 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval; 19673 } 19674 res(x,y,z,c) = min_val; 19675 } 19676 if (cond) 19677 cimg_forYZC(*this,y,z,c) 19678 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19679 Tt min_val = cimg::type<Tt>::max(); 19680 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19681 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,c); 19682 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval; 19683 } 19684 res(x,y,z,c) = min_val; 19685 } 19686 else 19687 cimg_forYZC(*this,y,z,c) 19688 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19689 Tt min_val = cimg::type<Tt>::max(); 19690 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19691 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,c,0); 19692 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval; 19693 } 19694 res(x,y,z,c) = min_val; 19695 } 19696 } else { // Weighted erosion 19697 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19698 Tt min_val = cimg::type<Tt>::max(); 19699 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19700 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19701 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,c) + mval); 19702 if (mval && cval<min_val) min_val = cval; 19703 } 19704 res(x,y,z,c) = min_val; 19705 } 19706 if (cond) 19707 cimg_forYZC(*this,y,z,c) 19708 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19709 Tt min_val = cimg::type<Tt>::max(); 19710 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19711 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19712 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,c) + mval); 19713 if (mval && cval<min_val) min_val = cval; 19714 } 19715 res(x,y,z,c) = min_val; 19716 } 19717 else 19718 cimg_forYZC(*this,y,z,c) 19719 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19720 Tt min_val = cimg::type<Tt>::max(); 19721 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19722 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19723 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,c,0) + mval); 19724 if (mval && cval<min_val) min_val = cval; 19725 } 19726 res(x,y,z,c) = min_val; 19727 } 19728 } 19729 return res; 19730 } 19731 19732 //! Erode the image by a rectangular structuring element of size sx,sy,sz. 19733 CImg<T>& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { 19734 if (sx>1 && _width>1) { // Along X-axis. 19735 const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19736 CImg<T> buf(L); 19737 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19738 cimg_forYZC(*this,y,z,c) { 19739 const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19740 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19741 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19742 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19743 for (int p = L - s - 1; p>0; --p) { 19744 const T val = *ptrs; ptrs+=off; 19745 if (is_first) { 19746 const T *nptrs = ptrs - off; cur = val; 19747 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; } 19748 nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false; 19749 } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19750 *(ptrd++) = cur; 19751 } 19752 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19753 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val<cur) cur = val; } *(ptrd--) = cur; 19754 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur; } 19755 T *pd = data(_width-1,y,z,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19756 } 19757 } 19758 19759 if (sy>1 && _height>1) { // Along Y-axis. 19760 const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19761 CImg<T> buf(L); 19762 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19763 cimg_forXZC(*this,x,z,c) { 19764 const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19765 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19766 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19767 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19768 for (int p = L - s - 1; p>0; --p) { 19769 const T val = *ptrs; ptrs+=off; 19770 if (is_first) { 19771 const T *nptrs = ptrs - off; cur = val; 19772 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; } 19773 nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false; 19774 } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19775 *(ptrd++) = cur; 19776 } 19777 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19778 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val<cur) cur = val; } *(ptrd--) = cur; 19779 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur; } 19780 T *pd = data(x,_height-1,z,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19781 } 19782 } 19783 19784 if (sz>1 && _depth>1) { // Along Z-axis. 19785 const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19786 CImg<T> buf(L); 19787 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19788 cimg_forXYC(*this,x,y,c) { 19789 const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19790 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19791 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19792 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val<=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19793 for (int p = L - s - 1; p>0; --p) { 19794 const T val = *ptrs; ptrs+=off; 19795 if (is_first) { 19796 const T *nptrs = ptrs - off; cur = val; 19797 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval<cur) cur = nval; } 19798 nptrs-=off; const T nval = *nptrs; if (nval<cur) { cur = nval; is_first = true; } else is_first = false; 19799 } else { if (val<=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19800 *(ptrd++) = cur; 19801 } 19802 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19803 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val<cur) cur = val; } *(ptrd--) = cur; 19804 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val<cur) cur = val; *(ptrd--) = cur; } 19805 T *pd = data(x,y,_depth-1,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19806 } 19807 } 19808 return *this; 19809 } 19810 19811 CImg<T> get_erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { 19812 return (+*this).erode(sx,sy,sz); 19813 } 19814 19815 //! Erode the image by a square structuring element of size sx. 19816 CImg<T>& erode(const unsigned int s) { 19817 return erode(s,s,s); 19818 } 19819 19820 CImg<T> get_erode(const unsigned int s) const { 19821 return (+*this).erode(s); 19822 } 19823 19824 //! Dilate the image by a structuring element. 19825 template<typename t> 19826 CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) { 19827 return get_dilate(mask,cond,weighted_dilatation).move_to(*this); 19828 } 19829 19830 template<typename t> 19831 CImg<_cimg_Tt> get_dilate(const CImg<t>& mask, const unsigned int cond=1, 19832 const bool weighted_dilatation=false) const { 19833 if (!mask || mask._spectrum!=1) 19834 throw CImgArgumentException(_cimg_instance 19835 "dilate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", 19836 cimg_instance, 19837 mask._width,mask._height,mask._depth,mask._spectrum,mask._data); 19838 19839 if (is_empty()) return *this; 19840 typedef _cimg_Tt Tt; 19841 CImg<Tt> res(_width,_height,_depth,_spectrum); 19842 const int 19843 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, 19844 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 19845 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 19846 cimg_forC(*this,c) 19847 if (!weighted_dilatation) { // Classical dilatation 19848 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19849 Tt max_val = cimg::type<Tt>::min(); 19850 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19851 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,c); 19852 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; 19853 } 19854 res(x,y,z,c) = max_val; 19855 } 19856 if (cond) 19857 cimg_forYZC(*this,y,z,c) 19858 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19859 Tt max_val = cimg::type<Tt>::min(); 19860 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19861 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,c); 19862 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; 19863 } 19864 res(x,y,z,c) = max_val; 19865 } 19866 else 19867 cimg_forYZC(*this,y,z,c) 19868 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19869 Tt max_val = cimg::type<Tt>::min(); 19870 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19871 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,c,0); 19872 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval; 19873 } 19874 res(x,y,z,c) = max_val; 19875 } 19876 } else { // Weighted dilatation 19877 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) { 19878 Tt max_val = cimg::type<Tt>::min(); 19879 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19880 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19881 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,c) - mval); 19882 if (mval && cval>max_val) max_val = cval; 19883 } 19884 res(x,y,z,c) = max_val; 19885 } 19886 if (cond) 19887 cimg_forYZC(*this,y,z,c) 19888 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19889 Tt max_val = cimg::type<Tt>::min(); 19890 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19891 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19892 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,c) - mval); 19893 if (mval && cval>max_val) max_val = cval; 19894 } 19895 res(x,y,z,c) = max_val; 19896 } 19897 else 19898 cimg_forYZC(*this,y,z,c) 19899 for (int x = 0; x<width(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) { 19900 Tt max_val = cimg::type<Tt>::min(); 19901 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) { 19902 const t mval = mask(mx1+xm,my1+ym,mz1+zm); 19903 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,c,0) - mval); 19904 if (mval && cval>max_val) max_val = cval; 19905 } 19906 res(x,y,z,c) = max_val; 19907 } 19908 } 19909 return res; 19910 } 19911 19912 //! Dilate the image by a rectangular structuring element of size sx,sy,sz. 19913 CImg<T>& dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { 19914 if (sx>1 && _width>1) { // Along X-axis. 19915 const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19916 CImg<T> buf(L); 19917 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19918 cimg_forYZC(*this,y,z,c) { 19919 const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19920 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19921 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19922 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19923 for (int p = L - s - 1; p>0; --p) { 19924 const T val = *ptrs; ptrs+=off; 19925 if (is_first) { 19926 const T *nptrs = ptrs - off; cur = val; 19927 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } 19928 nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; 19929 } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19930 *(ptrd++) = cur; 19931 } 19932 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19933 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; 19934 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } 19935 T *pd = data(_width-1,y,z,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19936 } 19937 } 19938 19939 if (sy>1 && _height>1) { // Along Y-axis. 19940 const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19941 CImg<T> buf(L); 19942 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19943 cimg_forXZC(*this,x,z,c) { 19944 const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19945 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19946 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19947 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19948 for (int p = L - s - 1; p>0; --p) { 19949 const T val = *ptrs; ptrs+=off; 19950 if (is_first) { 19951 const T *nptrs = ptrs - off; cur = val; 19952 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } 19953 nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; 19954 } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19955 *(ptrd++) = cur; 19956 } 19957 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19958 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; 19959 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } 19960 T *pd = data(x,_height-1,z,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19961 } 19962 } 19963 19964 if (sz>1 && _depth>1) { // Along Z-axis. 19965 const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; 19966 CImg<T> buf(L); 19967 T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; 19968 cimg_forXYC(*this,x,y,c) { 19969 const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + L*off - off; 19970 ptrd = buf._data; T cur = *ptrs; ptrs+=off; bool is_first = true; 19971 for (int p = s2-1; p>0 && ptrs<=ptrse; --p) { const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; }} *(ptrd++) = cur; 19972 for (int p = s1; p>0 && ptrd<=ptrde; --p) { const T val = *ptrs; if (ptrs<ptrse) ptrs+=off; if (val>=cur) { cur = val; is_first = false; } *(ptrd++) = cur; } 19973 for (int p = L - s - 1; p>0; --p) { 19974 const T val = *ptrs; ptrs+=off; 19975 if (is_first) { 19976 const T *nptrs = ptrs - off; cur = val; 19977 for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } 19978 nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; 19979 } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } 19980 *(ptrd++) = cur; 19981 } 19982 ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; 19983 for (int p = s1; p>0 && ptrs>=ptrsb; --p) { const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; } *(ptrd--) = cur; 19984 for (int p = s2-1; p>0 && ptrd>=ptrdb; --p) { const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; } 19985 T *pd = data(x,y,_depth-1,c) + off; cimg_for(buf,ps,T) { pd-=off; *pd = *ps; } 19986 } 19987 } 19988 return *this; 19989 } 19990 19991 CImg<T> get_dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { 19992 return (+*this).dilate(sx,sy,sz); 19993 } 19994 19995 //! Erode the image by a square structuring element of size sx. 19996 CImg<T>& dilate(const unsigned int s) { 19997 return dilate(s,s,s); 19998 } 19999 20000 CImg<T> get_dilate(const unsigned int s) const { 20001 return (+*this).dilate(s); 20002 } 20003 20004 //! Compute the watershed transform, from an instance image of non-zero labels. 20005 template<typename t> 20006 CImg<T>& watershed(const CImg<t>& priority, const bool fill_lines=true) { 20007 if (is_empty()) return *this; 20008 if (!is_sameXYZ(priority)) 20009 throw CImgArgumentException(_cimg_instance 20010 "watershed() : Instance image and specified priority (%u,%u,%u,%u,%p) have different dimensions.", 20011 cimg_instance,priority._width,priority._height,priority._depth,priority._spectrum,priority._data); 20012 if (_spectrum!=1) { cimg_forC(*this,c) get_shared_channel(c).watershed(priority.get_shared_channel(c%priority._spectrum),fill_lines); return *this; } 20013 20014 CImg<boolT> in_queue(_width,_height,_depth,1,0); 20015 CImg<typename cimg::superset2<T,t,int>::type> Q; 20016 unsigned int sizeQ = 0; 20017 20018 // Find seed points and insert them in priority queue. 20019 const T *ptrs = _data; 20020 cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { 20021 if (x-1>=0 && !(*this)(x-1,y,z)) Q._watershed_insert(in_queue,sizeQ,priority(x-1,y,z),x-1,y,z); 20022 if (x+1<width() && !(*this)(x+1,y,z)) Q._watershed_insert(in_queue,sizeQ,priority(x+1,y,z),x+1,y,z); 20023 if (y-1>=0 && !(*this)(x,y-1,z)) Q._watershed_insert(in_queue,sizeQ,priority(x,y-1,z),x,y-1,z); 20024 if (y+1<height() && !(*this)(x,y+1,z)) Q._watershed_insert(in_queue,sizeQ,priority(x,y+1,z),x,y+1,z); 20025 if (z-1>=0 && !(*this)(x,y,z-1)) Q._watershed_insert(in_queue,sizeQ,priority(x,y,z-1),x,y,z-1); 20026 if (z+1<depth() && !(*this)(x,y,z+1)) Q._watershed_insert(in_queue,sizeQ,priority(x,y,z+1),x,y,z+1); 20027 } 20028 20029 // Start watershed computation. 20030 while (sizeQ) { 20031 20032 // Get and remove point with minimal priority from the queue. 20033 const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3); 20034 Q._watershed_remove(sizeQ); 20035 20036 // Check labels of the neighbors. 20037 bool is_same_label = true; 20038 unsigned int label = 0; 20039 if (x-1>=0) { 20040 if ((*this)(x-1,y,z)) { if (!label) label = (*this)(x-1,y,z); else if (label!=(*this)(x-1,y,z)) is_same_label = false; } 20041 else Q._watershed_insert(in_queue,sizeQ,priority(x-1,y,z),x-1,y,z); 20042 } 20043 if (x+1<width()) { 20044 if ((*this)(x+1,y,z)) { if (!label) label = (*this)(x+1,y,z); else if (label!=(*this)(x+1,y,z)) is_same_label = false; } 20045 else Q._watershed_insert(in_queue,sizeQ,priority(x+1,y,z),x+1,y,z); 20046 } 20047 if (y-1>=0) { 20048 if ((*this)(x,y-1,z)) { if (!label) label = (*this)(x,y-1,z); else if (label!=(*this)(x,y-1,z)) is_same_label = false; } 20049 else Q._watershed_insert(in_queue,sizeQ,priority(x,y-1,z),x,y-1,z); 20050 } 20051 if (y+1<height()) { 20052 if ((*this)(x,y+1,z)) { if (!label) label = (*this)(x,y+1,z); else if (label!=(*this)(x,y+1,z)) is_same_label = false; } 20053 else Q._watershed_insert(in_queue,sizeQ,priority(x,y+1,z),x,y+1,z); 20054 } 20055 if (z-1>=0) { 20056 if ((*this)(x,y,z-1)) { if (!label) label = (*this)(x,y,z-1); else if (label!=(*this)(x,y,z-1)) is_same_label = false; } 20057 else Q._watershed_insert(in_queue,sizeQ,priority(x,y,z-1),x,y,z-1); 20058 } 20059 if (z+1<depth()) { 20060 if ((*this)(x,y,z+1)) { if (!label) label = (*this)(x,y,z+1); else if (label!=(*this)(x,y,z+1)) is_same_label = false; } 20061 else Q._watershed_insert(in_queue,sizeQ,priority(x,y,z+1),x,y,z+1); 20062 } 20063 if (is_same_label) (*this)(x,y,z) = label; 20064 } 20065 20066 // Fill lines. 20067 if (fill_lines) { 20068 20069 // Sort all non-labeled pixels with labeled neighbors. 20070 in_queue = false; 20071 const T *ptrs = _data; 20072 cimg_forXYZ(*this,x,y,z) if (!*(ptrs++) && 20073 ((x-1>=0 && (*this)(x-1,y,z)) || (x+1<width() && (*this)(x+1,y,z)) || 20074 (y-1>=0 && (*this)(x,y-1,z)) || (y+1<height() && (*this)(x,y+1,z)) || 20075 (z-1>=0 && (*this)(x,y,z-1)) || (z+1>depth() && (*this)(x,y,z+1)))) 20076 Q._watershed_insert(in_queue,sizeQ,priority(x,y,z),x,y,z); 20077 20078 // Start line filling process. 20079 while (sizeQ) { 20080 const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3); 20081 Q._watershed_remove(sizeQ); 20082 t pmax = cimg::type<t>::min(); 20083 int xmax = 0, ymax = 0, zmax = 0; 20084 if (x-1>=0) { 20085 if ((*this)(x-1,y,z)) { if (priority(x-1,y,z)>pmax) { pmax = priority(x-1,y,z); xmax = x-1; ymax = y; zmax = z; }} 20086 else Q._watershed_insert(in_queue,sizeQ,priority(x-1,y,z),x-1,y,z); 20087 } 20088 if (x+1<width()) { 20089 if ((*this)(x+1,y,z)) { if (priority(x+1,y,z)>pmax) { pmax = priority(x+1,y,z); xmax = x+1; ymax = y; zmax = z; }} 20090 else Q._watershed_insert(in_queue,sizeQ,priority(x+1,y,z),x+1,y,z); 20091 } 20092 if (y-1>=0) { 20093 if ((*this)(x,y-1,z)) { if (priority(x,y-1,z)>pmax) { pmax = priority(x,y-1,z); xmax = x; ymax = y-1; zmax = z; }} 20094 else Q._watershed_insert(in_queue,sizeQ,priority(x,y-1,z),x,y-1,z); 20095 } 20096 if (y+1<height()) { 20097 if ((*this)(x,y+1,z)) { if (priority(x,y+1,z)>pmax) { pmax = priority(x,y+1,z); xmax = x; ymax = y+1; zmax = z; }} 20098 else Q._watershed_insert(in_queue,sizeQ,priority(x,y+1,z),x,y+1,z); 20099 } 20100 if (z-1>=0) { 20101 if ((*this)(x,y,z-1)) { if (priority(x,y,z-1)>pmax) { pmax = priority(x,y,z-1); xmax = x; ymax = y; zmax = z-1; }} 20102 else Q._watershed_insert(in_queue,sizeQ,priority(x,y,z-1),x,y,z-1); 20103 } 20104 if (z+1<depth()) { 20105 if ((*this)(x,y,z+1)) { if (priority(x,y,z+1)>pmax) { pmax = priority(x,y,z+1); xmax = x; ymax = y; zmax = z+1; }} 20106 else Q._watershed_insert(in_queue,sizeQ,priority(x,y,z+1),x,y,z+1); 20107 } 20108 (*this)(x,y,z) = (*this)(xmax,ymax,zmax); 20109 } 20110 } 20111 return *this; 20112 } 20113 20114 template<typename t> 20115 CImg<T> get_watershed(const CImg<t>& priority, const bool fill_lines=true) const { 20116 return (+*this).watershed(priority,fill_lines); 20117 } 20118 20119 // Insert/Remove items in priority queue, for watershed transform. 20120 template<typename t> 20121 CImg<T>& _watershed_insert(CImg<boolT>& in_queue, unsigned int& siz, const t value, const unsigned int x, const unsigned int y, const unsigned int z) { 20122 if (in_queue(x,y,z)) return *this; 20123 in_queue(x,y,z) = true; 20124 if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); } 20125 (*this)(siz-1,0) = (T)value; (*this)(siz-1,1) = (T)x; (*this)(siz-1,2) = (T)y; (*this)(siz-1,3) = (T)z; 20126 for (unsigned int pos = siz - 1, par = 0; pos && value>(*this)(par=(pos+1)/2-1,0); pos = par) { 20127 cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1)); 20128 cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3)); 20129 } 20130 return *this; 20131 } 20132 20133 CImg<T>& _watershed_remove(unsigned int& siz) { 20134 (*this)(0,0) = (*this)(--siz,0); (*this)(0,1) = (*this)(siz,1); (*this)(0,2) = (*this)(siz,2); (*this)(0,3) = (*this)(siz,3); 20135 const float value = (*this)(0,0); 20136 for (unsigned int pos = 0, left = 0, right = 0; 20137 ((right=2*(pos+1),(left=right-1))<siz && value<(*this)(left,0)) || (right<siz && value<(*this)(right,0));) { 20138 if (right<siz) { 20139 if ((*this)(left,0)>(*this)(right,0)) { 20140 cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1)); 20141 cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3)); 20142 pos = left; 20143 } else { 20144 cimg::swap((*this)(pos,0),(*this)(right,0)); cimg::swap((*this)(pos,1),(*this)(right,1)); 20145 cimg::swap((*this)(pos,2),(*this)(right,2)); cimg::swap((*this)(pos,3),(*this)(right,3)); 20146 pos = right; 20147 } 20148 } else { 20149 cimg::swap((*this)(pos,0),(*this)(left,0)); cimg::swap((*this)(pos,1),(*this)(left,1)); 20150 cimg::swap((*this)(pos,2),(*this)(left,2)); cimg::swap((*this)(pos,3),(*this)(left,3)); 20151 pos = left; 20152 } 20153 } 20154 return *this; 20155 } 20156 20157 //! Compute the result of the Deriche filter. 20158 /** 20159 The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of 20160 order 0,1 or 2 of an image. 20161 **/ 20162 CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) { 20163 #define _cimg_deriche2_apply \ 20164 Tfloat *ptrY = Y._data, yb = 0, yp = 0; \ 20165 T xp = (T)0; \ 20166 if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \ 20167 for (int m = 0; m<N; ++m) { \ 20168 const T xc = *ptrX; ptrX+=off; \ 20169 const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \ 20170 xp = xc; yb = yp; yp = yc; \ 20171 } \ 20172 T xn = (T)0, xa = (T)0; \ 20173 Tfloat yn = 0, ya = 0; \ 20174 if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \ 20175 for (int n = N-1; n>=0; --n) { \ 20176 const T xc = *(ptrX-=off); \ 20177 const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \ 20178 xa = xn; xn = xc; ya = yn; yn = yc; \ 20179 *ptrX = (T)(*(--ptrY)+yc); \ 20180 } 20181 const char naxis = cimg::uncase(axis); 20182 const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; 20183 if (is_empty() || (nsigma<0.1 && !order)) return *this; 20184 const float 20185 nnsigma = nsigma<0.1f?0.1f:nsigma, 20186 alpha = 1.695f/nnsigma, 20187 ema = (float)std::exp(-alpha), 20188 ema2 = (float)std::exp(-2*alpha), 20189 b1 = -2*ema, 20190 b2 = ema2; 20191 float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0; 20192 switch (order) { 20193 case 0 : { 20194 const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2); 20195 a0 = k; 20196 a1 = k*(alpha-1)*ema; 20197 a2 = k*(alpha+1)*ema; 20198 a3 = -k*ema2; 20199 } break; 20200 case 1 : { 20201 const float k = (1-ema)*(1-ema)/ema; 20202 a0 = k*ema; 20203 a1 = a3 = 0; 20204 a2 = -a0; 20205 } break; 20206 case 2 : { 20207 const float 20208 ea = (float)std::exp(-alpha), 20209 k = -(ema2-1)/(2*alpha*ema), 20210 kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea)); 20211 a0 = kn; 20212 a1 = -kn*(1+k*alpha)*ema; 20213 a2 = kn*(1-k*alpha)*ema; 20214 a3 = -kn*ema2; 20215 } break; 20216 default : 20217 throw CImgArgumentException(_cimg_instance 20218 "deriche() : Invalid specified filter order %u " 20219 "(should be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).", 20220 cimg_instance, 20221 order); 20222 } 20223 coefp = (a0+a1)/(1+b1+b2); 20224 coefn = (a2+a3)/(1+b1+b2); 20225 switch (naxis) { 20226 case 'x' : { 20227 const int N = _width, off = 1; 20228 CImg<Tfloat> Y(N); 20229 cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche2_apply; } 20230 } break; 20231 case 'y' : { 20232 const int N = _height, off = _width; 20233 CImg<Tfloat> Y(N); 20234 cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche2_apply; } 20235 } break; 20236 case 'z' : { 20237 const int N = _depth, off = _width*_height; 20238 CImg<Tfloat> Y(N); 20239 cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche2_apply; } 20240 } break; 20241 default : { 20242 const int N = _spectrum, off = _width*_height*_depth; 20243 CImg<Tfloat> Y(N); 20244 cimg_forXYZ(*this,x,y,z) { T *ptrX = data(x,y,z,0); _cimg_deriche2_apply; } 20245 } 20246 } 20247 return *this; 20248 } 20249 20250 CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const { 20251 return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond); 20252 } 20253 20254 //! Return a blurred version of the image, using a Canny-Deriche filter. 20255 /** 20256 Blur the image with an anisotropic exponential filter (Deriche filter of order 0). 20257 **/ 20258 CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) { 20259 if (!is_empty()) { 20260 if (_width>1) deriche(sigmax,0,'x',cond); 20261 if (_height>1) deriche(sigmay,0,'y',cond); 20262 if (_depth>1) deriche(sigmaz,0,'z',cond); 20263 } 20264 return *this; 20265 } 20266 20267 CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) const { 20268 return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond); 20269 } 20270 20271 //! Return a blurred version of the image, using a Canny-Deriche filter. 20272 CImg<T>& blur(const float sigma, const bool cond=true) { 20273 const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; 20274 return blur(nsigma,nsigma,nsigma,cond); 20275 } 20276 20277 CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const { 20278 return CImg<Tfloat>(*this,false).blur(sigma,cond); 20279 } 20280 20281 //! Blur the image anisotropically following a field of diffusion tensors. 20282 /** 20283 \param G = Field of square roots of diffusion tensors/vectors used to drive the smoothing. 20284 \param amplitude = amplitude of the smoothing. 20285 \param dl = spatial discretization. 20286 \param da = angular discretization. 20287 \param gauss_prec = precision of the gaussian function. 20288 \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta) 20289 \param fast_approx = Tell to use the fast approximation or not. 20290 **/ 20291 template<typename t> 20292 CImg<T>& blur_anisotropic(const CImg<t>& G, 20293 const float amplitude=60, const float dl=0.8f, const float da=30, 20294 const float gauss_prec=2, const unsigned int interpolation_type=0, 20295 const bool fast_approx=1) { 20296 20297 // Check arguments and init variables 20298 if (!is_sameXYZ(G) || (G._spectrum!=3 && G._spectrum!=6)) 20299 throw CImgArgumentException(_cimg_instance 20300 "blur_anisotropic() : Invalid specified diffusion tensor field (%u,%u,%u,%u,%p).", 20301 cimg_instance, 20302 G._width,G._height,G._depth,G._spectrum,G._data); 20303 20304 if (is_empty() || amplitude<=0 || dl<0) return *this; 20305 const bool is_threed = (G._spectrum==6); 20306 T val_min, val_max = max_min(val_min); 20307 20308 if (da<=0) { // Iterated oriented Laplacians 20309 CImg<Tfloat> velocity(_width,_height,_depth,_spectrum); 20310 for (unsigned int iteration = 0; iteration<(unsigned int)amplitude; ++iteration) { 20311 Tfloat *ptrd = velocity._data, veloc_max = 0; 20312 if (is_threed) { // 3d version 20313 CImg_3x3x3(I,Tfloat); 20314 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 20315 const Tfloat 20316 ixx = Incc + Ipcc - 2*Iccc, 20317 ixy = (Innc + Ippc - Inpc - Ipnc)/4, 20318 ixz = (Incn + Ipcp - Incp - Ipcn)/4, 20319 iyy = Icnc + Icpc - 2*Iccc, 20320 iyz = (Icnn + Icpp - Icnp - Icpn)/4, 20321 izz = Iccn + Iccp - 2*Iccc, 20322 veloc = (Tfloat)(G(x,y,z,0)*ixx + 2*G(x,y,z,1)*ixy + 2*G(x,y,z,2)*ixz + G(x,y,z,3)*iyy + 2*G(x,y,z,4)*iyz + G(x,y,z,5)*izz); 20323 *(ptrd++) = veloc; 20324 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 20325 } 20326 } else { // 2d version 20327 CImg_3x3(I,Tfloat); 20328 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 20329 const Tfloat 20330 ixx = Inc + Ipc - 2*Icc, 20331 ixy = (Inn + Ipp - Inp - Ipn)/4, 20332 iyy = Icn + Icp - 2*Icc, 20333 veloc = (Tfloat)(G(x,y,0,0)*ixx + 2*G(x,y,0,1)*ixy + G(x,y,0,2)*iyy); 20334 *(ptrd++) = veloc; 20335 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 20336 } 20337 } 20338 if (veloc_max>0) *this+=(velocity*=dl/veloc_max); 20339 } 20340 } else { // LIC-based smoothing. 20341 const unsigned int whd = _width*_height*_depth; 20342 const float sqrt2amplitude = (float)std::sqrt(2*amplitude); 20343 const int dx1 = width() - 1, dy1 = height() - 1, dz1 = depth() - 1; 20344 CImg<Tfloat> res(_width,_height,_depth,_spectrum,0), W(_width,_height,_depth,is_threed?4:3), val(_spectrum); 20345 int N = 0; 20346 if (is_threed) { // 3d version 20347 for (float phi = (180%(int)da)/2.0f; phi<=180; phi+=da) { 20348 const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)), da2 = datmp<1?360.0f:datmp; 20349 for (float theta = 0; theta<360; (theta+=da2),++N) { 20350 const float 20351 thetar = (float)(theta*cimg::PI/180), 20352 vx = (float)(std::cos(thetar)*std::cos(phir)), 20353 vy = (float)(std::sin(thetar)*std::cos(phir)), 20354 vz = (float)std::sin(phir); 20355 const t 20356 *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2), 20357 *pd = G.data(0,0,0,3), *pe = G.data(0,0,0,4), *pf = G.data(0,0,0,5); 20358 Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2), *pd3 = W.data(0,0,0,3); 20359 cimg_forXYZ(G,xg,yg,zg) { 20360 const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++); 20361 const float 20362 u = (float)(a*vx + b*vy + c*vz), 20363 v = (float)(b*vx + d*vy + e*vz), 20364 w = (float)(c*vx + e*vy + f*vz), 20365 n = (float)std::sqrt(1e-5+u*u+v*v+w*w), 20366 dln = dl/n; 20367 *(pd0++) = (Tfloat)(u*dln); 20368 *(pd1++) = (Tfloat)(v*dln); 20369 *(pd2++) = (Tfloat)(w*dln); 20370 *(pd3++) = (Tfloat)n; 20371 } 20372 20373 Tfloat *ptrd = res._data; 20374 cimg_forXYZ(*this,x,y,z) { 20375 val.fill(0); 20376 const float 20377 n = (float)W(x,y,z,3), 20378 fsigma = (float)(n*sqrt2amplitude), 20379 fsigma2 = 2*fsigma*fsigma, 20380 length = gauss_prec*fsigma; 20381 float 20382 S = 0, 20383 X = (float)x, 20384 Y = (float)y, 20385 Z = (float)z; 20386 switch (interpolation_type) { 20387 case 0 : { // Nearest neighbor 20388 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { 20389 const int 20390 cx = (int)(X+0.5f), 20391 cy = (int)(Y+0.5f), 20392 cz = (int)(Z+0.5f); 20393 const float 20394 u = (float)W(cx,cy,cz,0), 20395 v = (float)W(cx,cy,cz,1), 20396 w = (float)W(cx,cy,cz,2); 20397 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,cz,c); ++S; } 20398 else { 20399 const float coef = (float)std::exp(-l*l/fsigma2); 20400 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,cz,c)); 20401 S+=coef; 20402 } 20403 X+=u; Y+=v; Z+=w; 20404 } 20405 } break; 20406 case 1 : { // Linear interpolation 20407 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { 20408 const float 20409 u = (float)(W._linear_atXYZ(X,Y,Z,0)), 20410 v = (float)(W._linear_atXYZ(X,Y,Z,1)), 20411 w = (float)(W._linear_atXYZ(X,Y,Z,2)); 20412 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } 20413 else { 20414 const float coef = (float)std::exp(-l*l/fsigma2); 20415 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); 20416 S+=coef; 20417 } 20418 X+=u; Y+=v; Z+=w; 20419 } 20420 } break; 20421 default : { // 2nd order Runge Kutta 20422 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { 20423 const float 20424 u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)), 20425 v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)), 20426 w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2)), 20427 u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)), 20428 v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)), 20429 w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2)); 20430 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } 20431 else { 20432 const float coef = (float)std::exp(-l*l/fsigma2); 20433 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); 20434 S+=coef; 20435 } 20436 X+=u; Y+=v; Z+=w; 20437 } 20438 } break; 20439 } 20440 Tfloat *_ptrd = ptrd++; 20441 if (S>0) cimg_forC(res,c) { *_ptrd+=val[c]/S; _ptrd+=whd; } 20442 else cimg_forC(res,c) { *_ptrd+=(Tfloat)((*this)(x,y,z,c)); _ptrd+=whd; } 20443 } 20444 } 20445 } 20446 } else { // 2d LIC algorithm 20447 for (float theta = (360%(int)da)/2.0f; theta<360; (theta+=da),++N) { 20448 const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar)); 20449 const t *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2); 20450 Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2); 20451 cimg_forXY(G,xg,yg) { 20452 const t a = *(pa++), b = *(pb++), c = *(pc++); 20453 const float 20454 u = (float)(a*vx + b*vy), 20455 v = (float)(b*vx + c*vy), 20456 n = (float)std::sqrt(1e-5+u*u+v*v), 20457 dln = dl/n; 20458 *(pd0++) = (Tfloat)(u*dln); 20459 *(pd1++) = (Tfloat)(v*dln); 20460 *(pd2++) = (Tfloat)n; 20461 } 20462 Tfloat *ptrd = res._data; 20463 cimg_forXY(*this,x,y) { 20464 val.fill(0); 20465 const float 20466 n = (float)W(x,y,0,2), 20467 fsigma = (float)(n*sqrt2amplitude), 20468 fsigma2 = 2*fsigma*fsigma, 20469 length = gauss_prec*fsigma; 20470 float 20471 S = 0, 20472 X = (float)x, 20473 Y = (float)y; 20474 switch (interpolation_type) { 20475 case 0 : { // Nearest-neighbor 20476 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { 20477 const int 20478 cx = (int)(X+0.5f), 20479 cy = (int)(Y+0.5f); 20480 const float 20481 u = (float)W(cx,cy,0,0), 20482 v = (float)W(cx,cy,0,1); 20483 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,0,c); ++S; } 20484 else { 20485 const float coef = (float)std::exp(-l*l/fsigma2); 20486 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,0,c)); 20487 S+=coef; 20488 } 20489 X+=u; Y+=v; 20490 } 20491 } break; 20492 case 1 : { // Linear interpolation 20493 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { 20494 const float 20495 u = (float)(W._linear_atXY(X,Y,0,0)), 20496 v = (float)(W._linear_atXY(X,Y,0,1)); 20497 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } 20498 else { 20499 const float coef = (float)std::exp(-l*l/fsigma2); 20500 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); 20501 S+=coef; 20502 } 20503 X+=u; Y+=v; 20504 } 20505 } break; 20506 default : { // 2nd-order Runge-kutta interpolation 20507 for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { 20508 const float 20509 u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)), 20510 v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1)), 20511 u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)), 20512 v = (float)(W._linear_atXY(X+u0,Y+v0,0,1)); 20513 if (fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } 20514 else { 20515 const float coef = (float)std::exp(-l*l/fsigma2); 20516 cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); 20517 S+=coef; 20518 } 20519 X+=u; Y+=v; 20520 } 20521 } 20522 } 20523 Tfloat *_ptrd = ptrd++; 20524 if (S>0) cimg_forC(res,c) { *_ptrd+=val[c]/S; _ptrd+=whd; } 20525 else cimg_forC(res,c) { *_ptrd+=(Tfloat)((*this)(x,y,0,c)); _ptrd+=whd; } 20526 } 20527 } 20528 } 20529 const Tfloat *ptrs = res.end(); 20530 cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<val_min?val_min:(val>val_max?val_max:(T)val); } 20531 } 20532 return *this; 20533 } 20534 20535 template<typename t> 20536 CImg<T> get_blur_anisotropic(const CImg<t>& G, 20537 const float amplitude=60, const float dl=0.8f, const float da=30, 20538 const float gauss_prec=2, const unsigned int interpolation_type=0, 20539 const bool fast_approx=true) const { 20540 return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx); 20541 } 20542 20543 //! Blur an image following in an anisotropic way. 20544 CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, 20545 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, 20546 const float gauss_prec=2, const unsigned int interpolation_type=0, 20547 const bool fast_approx=true) { 20548 return blur_anisotropic(get_edge_tensors(sharpness,anisotropy,alpha,sigma,interpolation_type!=3), 20549 amplitude,dl,da,gauss_prec,interpolation_type,fast_approx); 20550 } 20551 20552 CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, 20553 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, 20554 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, 20555 const bool fast_approx=true) const { 20556 return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx); 20557 } 20558 20559 //! Blur an image using the bilateral filter. 20560 /** 20561 \param sigma_x Amount of blur along the X-axis. 20562 \param sigma_y Amount of blur along the Y-axis. 20563 \param sigma_z Amount of blur along the Z-axis. 20564 \param sigma_r Amount of blur along the range axis. 20565 \param bgrid_x Size of the bilateral grid along the X-axis. 20566 \param bgrid_y Size of the bilateral grid along the Y-axis. 20567 \param bgrid_z Size of the bilateral grid along the Z-axis. 20568 \param bgrid_r Size of the bilateral grid along the range axis. 20569 \param interpolation_type Use interpolation for image slicing. 20570 \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006 20571 (extended for 3d volumetric images). 20572 **/ 20573 CImg<T>& blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, 20574 const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, 20575 const bool interpolation_type=true) { 20576 if (is_empty()) return *this; 20577 T m, M = max_min(m); 20578 const float range = (float)(1.0f+M-m); 20579 const unsigned int 20580 bx0 = bgrid_x>=0?bgrid_x:_width*(-bgrid_x)/100, 20581 by0 = bgrid_y>=0?bgrid_y:_height*(-bgrid_y)/100, 20582 bz0 = bgrid_z>=0?bgrid_z:_depth*(-bgrid_z)/100, 20583 br0 = bgrid_r>=0?bgrid_r:(int)(-range*bgrid_r/100), 20584 bx = bx0>0?bx0:1, 20585 by = by0>0?by0:1, 20586 bz = bz0>0?bz0:1, 20587 br = br0>0?br0:1; 20588 const float 20589 _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100, 20590 _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100, 20591 _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100, 20592 nsigma_x = _sigma_x*bx/_width, 20593 nsigma_y = _sigma_y*by/_height, 20594 nsigma_z = _sigma_z*bz/_depth, 20595 nsigma_r = sigma_r*br/range; 20596 if (nsigma_x>0 || nsigma_y>0 || nsigma_z>0 || nsigma_r>0) { 20597 const bool is_threed = (_depth>1); 20598 if (is_threed) { // 3d version of the algorithm 20599 CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br); 20600 cimg_forC(*this,c) { 20601 bgrid.fill(0); bgridw.fill(0); 20602 cimg_forXYZ(*this,x,y,z) { 20603 const T val = (*this)(x,y,z,c); 20604 const int X = x*bx/_width, Y = y*by/_height, Z = z*bz/_depth, R = (int)((val-m)*br/range); 20605 bgrid(X,Y,Z,R) = (float)val; 20606 bgridw(X,Y,Z,R) = 1; 20607 } 20608 bgrid.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'c',false); 20609 bgridw.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'c',false); 20610 if (interpolation_type) cimg_forXYZ(*this,x,y,z) { 20611 const T val = (*this)(x,y,z,c); 20612 const float X = (float)x*bx/_width, Y = (float)y*by/_height, Z = (float)z*bz/_depth, R = (float)((val-m)*br/range), 20613 bval0 = bgrid._linear_atXYZC(X,Y,Z,R), bval1 = bgridw._linear_atXYZC(X,Y,Z,R); 20614 (*this)(x,y,z,c) = (T)(bval0/bval1); 20615 } else cimg_forXYZ(*this,x,y,z) { 20616 const T val = (*this)(x,y,z,c); 20617 const int X = x*bx/_width, Y = y*by/_height, Z = z*bz/_depth, R = (int)((val-m)*br/range); 20618 const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R); 20619 (*this)(x,y,z,c) = (T)(bval0/bval1); 20620 } 20621 } 20622 } else { // 2d version of the algorithm 20623 CImg<floatT> bgrid(bx,by,br,2); 20624 cimg_forC(*this,c) { 20625 bgrid.fill(0); 20626 cimg_forXY(*this,x,y) { 20627 const T val = (*this)(x,y,c); 20628 const int X = x*bx/_width, Y = y*by/_height, R = (int)((val-m)*br/range); 20629 bgrid(X,Y,R,0) = (float)val; 20630 bgrid(X,Y,R,1) = 1; 20631 } 20632 bgrid.blur(nsigma_x,nsigma_y,0,true).blur(0,0,nsigma_r,false); 20633 if (interpolation_type) cimg_forXY(*this,x,y) { 20634 const T val = (*this)(x,y,c); 20635 const float X = (float)x*bx/_width, Y = (float)y*by/_height, R = (float)((val-m)*br/range), 20636 bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1); 20637 (*this)(x,y,c) = (T)(bval0/bval1); 20638 } else cimg_forXY(*this,x,y) { 20639 const T val = (*this)(x,y,c); 20640 const int X = x*bx/_width, Y = y*by/_height, R = (int)((val-m)*br/range); 20641 const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1); 20642 (*this)(x,y,c) = (T)(bval0/bval1); 20643 } 20644 } 20645 } 20646 } 20647 return *this; 20648 } 20649 20650 CImg<T> get_blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, 20651 const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, 20652 const bool interpolation_type=true) const { 20653 return (+*this).blur_bilateral(sigma_x,sigma_y,sigma_z,sigma_r,bgrid_x,bgrid_y,bgrid_z,bgrid_r,interpolation_type); 20654 } 20655 20656 //! Blur an image using the bilateral filter. 20657 CImg<T>& blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, 20658 const bool interpolation_type=true) { 20659 const float nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100; 20660 return blur_bilateral(nsigma_s,nsigma_s,nsigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r,interpolation_type); 20661 } 20662 20663 CImg<T> get_blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, 20664 const bool interpolation_type=true) const { 20665 return (+*this).blur_bilateral(sigma_s,sigma_s,sigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r,interpolation_type); 20666 } 20667 20668 //! Blur an image in its patch-based space. 20669 CImg<T>& blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, 20670 const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true) { 20671 return get_blur_patch(sigma_s,sigma_p,patch_size,lookup_size,smoothness,fast_approx).move_to(*this); 20672 } 20673 20674 CImg<T> get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, 20675 const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true) const { 20676 20677 #define _cimg_blur_patch3d_fast(N) \ 20678 cimg_for##N##XYZ(res,x,y,z) { \ 20679 T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \ 20680 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ 20681 float sum_weights = 0; \ 20682 cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0) - img(p,q,r,0))<sigma_p3) { \ 20683 T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \ 20684 float distance2 = 0; \ 20685 pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \ 20686 distance2/=Pnorm; \ 20687 const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \ 20688 alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = alldist>3?0.0f:1.0f; \ 20689 sum_weights+=weight; \ 20690 cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \ 20691 } \ 20692 if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \ 20693 else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ 20694 } 20695 20696 #define _cimg_blur_patch3d(N) \ 20697 cimg_for##N##XYZ(res,x,y,z) { \ 20698 T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,x,y,z,c,pP,T); pP+=N3; } \ 20699 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ 20700 float sum_weights = 0, weight_max = 0; \ 20701 cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { \ 20702 T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N##x##N(img,p,q,r,c,pQ,T); pQ+=N3; } \ 20703 float distance2 = 0; \ 20704 pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \ 20705 distance2/=Pnorm; \ 20706 const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \ 20707 alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)std::exp(-alldist); \ 20708 if (weight>weight_max) weight_max = weight; \ 20709 sum_weights+=weight; \ 20710 cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); \ 20711 } \ 20712 sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); \ 20713 if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; \ 20714 else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ 20715 } 20716 20717 #define _cimg_blur_patch2d_fast(N) \ 20718 cimg_for##N##XY(res,x,y) { \ 20719 T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \ 20720 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ 20721 float sum_weights = 0; \ 20722 cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0,0) - img(p,q,0,0))<sigma_p3) { \ 20723 T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \ 20724 float distance2 = 0; \ 20725 pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \ 20726 distance2/=Pnorm; \ 20727 const float dx = (float)p - x, dy = (float)q - y, \ 20728 alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = alldist>3?0.0f:1.0f; \ 20729 sum_weights+=weight; \ 20730 cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \ 20731 } \ 20732 if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \ 20733 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ 20734 } 20735 20736 #define _cimg_blur_patch2d(N) \ 20737 cimg_for##N##XY(res,x,y) { \ 20738 T *pP = P._data; cimg_forC(res,c) { cimg_get##N##x##N(img,x,y,0,c,pP,T); pP+=N2; } \ 20739 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ 20740 float sum_weights = 0, weight_max = 0; \ 20741 cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { \ 20742 T *pQ = Q._data; cimg_forC(res,c) { cimg_get##N##x##N(img,p,q,0,c,pQ,T); pQ+=N2; } \ 20743 float distance2 = 0; \ 20744 pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \ 20745 distance2/=Pnorm; \ 20746 const float dx = (float)p - x, dy = (float)q - y, \ 20747 alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)std::exp(-alldist); \ 20748 if (weight>weight_max) weight_max = weight; \ 20749 sum_weights+=weight; \ 20750 cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); \ 20751 } \ 20752 sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); \ 20753 if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; \ 20754 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ 20755 } 20756 20757 CImg<Tfloat> res(_width,_height,_depth,_spectrum,0); 20758 const CImg<T> _img = smoothness>0?get_blur(smoothness):CImg<Tfloat>(),&img = smoothness>0?_img:*this; 20759 CImg<T> P(patch_size*patch_size*_spectrum), Q(P); 20760 const float 20761 nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100, 20762 sigma_s2 = nsigma_s*nsigma_s, sigma_p2 = sigma_p*sigma_p, sigma_p3 = 3*sigma_p, 20763 Pnorm = P.size()*sigma_p2; 20764 const int rsize2 = (int)lookup_size/2, rsize1 = (int)lookup_size - rsize2 - 1; 20765 const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size; 20766 if (_depth>1) switch (patch_size) { // 3d 20767 case 2 : if (fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break; 20768 case 3 : if (fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break; 20769 default : { 20770 const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; 20771 if (fast_approx) cimg_forXYZ(res,x,y,z) { // Fast 20772 P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); 20773 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; 20774 float sum_weights = 0; 20775 cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0)-img(p,q,r,0))<sigma_p3) { 20776 (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P; 20777 const float 20778 dx = (float)x - p, dy = (float)y - q, dz = (float)z - r, 20779 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2), 20780 weight = distance2>3?0.0f:1.0f; 20781 sum_weights+=weight; 20782 cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); 20783 } 20784 if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; 20785 else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); 20786 } else cimg_forXYZ(res,x,y,z) { // Exact 20787 P = img.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); 20788 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; 20789 float sum_weights = 0, weight_max = 0; 20790 cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { 20791 (Q = img.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P; 20792 const float 20793 dx = (float)x - p, dy = (float)y - q, dz = (float)z - r, 20794 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2), 20795 weight = (float)std::exp(-distance2); 20796 if (weight>weight_max) weight_max = weight; 20797 sum_weights+=weight; 20798 cimg_forC(res,c) res(x,y,z,c)+=weight*(*this)(p,q,r,c); 20799 } 20800 sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=weight_max*(*this)(x,y,z,c); 20801 if (sum_weights>0) cimg_forC(res,c) res(x,y,z,c)/=sum_weights; 20802 else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); 20803 } 20804 } 20805 } else switch (patch_size) { // 2d 20806 case 2 : if (fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break; 20807 case 3 : if (fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break; 20808 case 4 : if (fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break; 20809 case 5 : if (fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break; 20810 case 6 : if (fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break; 20811 case 7 : if (fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break; 20812 case 8 : if (fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break; 20813 case 9 : if (fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break; 20814 default : { // Fast 20815 const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; 20816 if (fast_approx) cimg_forXY(res,x,y) { // 2d fast approximation. 20817 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); 20818 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; 20819 float sum_weights = 0; 20820 cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0)-img(p,q,0))<sigma_p3) { 20821 (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P; 20822 const float 20823 dx = (float)x - p, dy = (float)y - q, 20824 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2), 20825 weight = distance2>3?0.0f:1.0f; 20826 sum_weights+=weight; 20827 cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); 20828 } 20829 if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; 20830 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); 20831 } else cimg_forXY(res,x,y) { // 2d exact algorithm. 20832 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); 20833 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; 20834 float sum_weights = 0, weight_max = 0; 20835 cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { 20836 (Q = img.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P; 20837 const float 20838 dx = (float)x - p, dy = (float)y - q, 20839 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2), 20840 weight = (float)std::exp(-distance2); 20841 if (weight>weight_max) weight_max = weight; 20842 sum_weights+=weight; 20843 cimg_forC(res,c) res(x,y,c)+=weight*(*this)(p,q,c); 20844 } 20845 sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=weight_max*(*this)(x,y,c); 20846 if (sum_weights>0) cimg_forC(res,c) res(x,y,c)/=sum_weights; 20847 else cimg_forC(res,c) res(x,y,0,c) = (Tfloat)((*this)(x,y,c)); 20848 } 20849 } 20850 } 20851 return res; 20852 } 20853 20854 //! Apply a median filter. 20855 CImg<T>& blur_median(const unsigned int n) { 20856 if (!n) return *this; 20857 return get_blur_median(n).move_to(*this); 20858 } 20859 20860 CImg<T> get_blur_median(const unsigned int n) const { 20861 if (is_empty() || n<=1) return *this; 20862 CImg<T> res(_width,_height,_depth,_spectrum); 20863 T *ptrd = res._data; 20864 const int hl = n/2, hr = hl - 1 + n%2; 20865 if (res._depth!=1) cimg_forXYZC(*this,x,y,z,c) { // 3d 20866 const int 20867 x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr, 20868 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, 20869 nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1, nz1 = z1>=depth()?depth()-1:z1; 20870 *(ptrd++) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median(); 20871 } else { 20872 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b) 20873 if (res._height!=1) switch (n) { // 2d 20874 case 3 : { 20875 T I[9] = { 0 }; 20876 CImg_3x3(J,T); 20877 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) { 20878 std::memcpy(J,I,9*sizeof(T)); 20879 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn); 20880 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn); 20881 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn); 20882 _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn); 20883 _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc); 20884 _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc); 20885 _cimg_median_sort(Jcc, Jnp); 20886 *(ptrd++) = Jcc; 20887 } 20888 } break; 20889 case 5 : { 20890 T I[25] = { 0 }; 20891 CImg_5x5(J,T); 20892 cimg_forC(*this,c) cimg_for5x5(*this,x,y,0,c,I,T) { 20893 std::memcpy(J,I,25*sizeof(T)); 20894 _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb); 20895 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc); 20896 _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc); 20897 _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn); 20898 _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca); 20899 _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp); 20900 _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp); 20901 _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac); 20902 _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc); 20903 _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna); 20904 _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa); 20905 _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn); 20906 _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan); 20907 _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc); 20908 _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca); 20909 _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna); 20910 _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn); 20911 _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna); 20912 _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc); 20913 _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc); 20914 _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp); 20915 _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc); 20916 _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn); 20917 _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn); 20918 _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc); 20919 *(ptrd++) = Jcc; 20920 } 20921 } break; 20922 default : { 20923 cimg_forXYC(*this,x,y,c) { 20924 const int 20925 x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, 20926 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, 20927 nx1 = x1>=width()?width()-1:x1, ny1 = y1>=height()?height()-1:y1; 20928 *(ptrd++) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median(); 20929 } 20930 } 20931 } else switch (n) { // 1d 20932 case 2 : { 20933 T I[4] = { 0 }; 20934 cimg_forC(*this,c) cimg_for2x2(*this,x,y,0,c,I,T) *(ptrd++) = (T)(0.5f*(I[0]+I[1])); 20935 } break; 20936 case 3 : { 20937 T I[9] = { 0 }; 20938 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) 20939 *(ptrd++) = 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])); 20940 } break; 20941 default : { 20942 cimg_forXC(*this,x,c) { 20943 const int 20944 x0 = x - hl, x1 = x + hr, 20945 nx0 = x0<0?0:x0, nx1 = x1>=width()?width()-1:x1; 20946 *(ptrd++) = get_crop(nx0,0,0,c,nx1,0,0,c).median(); 20947 } 20948 } 20949 } 20950 } 20951 return res; 20952 } 20953 20954 //! Sharpen image using anisotropic shock filters or inverse diffusion. 20955 CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) { 20956 if (is_empty()) return *this; 20957 T val_min, val_max = max_min(val_min); 20958 const float nedge = edge/2; 20959 CImg<Tfloat> val, vec, velocity(_width,_height,_depth,_spectrum); 20960 Tfloat *ptrd = velocity._data, veloc_max = 0; 20961 20962 if (_depth>1) { // 3d 20963 CImg_3x3x3(I,Tfloat); 20964 if (sharpen_type) { // Shock filters. 20965 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); 20966 if (sigma>0) G.blur(sigma); 20967 Tfloat *ptrG0 = G.data(0,0,0,0), *ptrG1 = G.data(0,0,0,1), *ptrG2 = G.data(0,0,0,2), *ptrG3 = G.data(0,0,0,3); 20968 cimg_forXYZ(G,x,y,z) { 20969 G.get_tensor_at(x,y,z).symmetric_eigen(val,vec); 20970 if (val[0]<0) val[0] = 0; 20971 if (val[1]<0) val[1] = 0; 20972 if (val[2]<0) val[2] = 0; 20973 *(ptrG0++) = vec(0,0); 20974 *(ptrG1++) = vec(0,1); 20975 *(ptrG2++) = vec(0,2); 20976 *(ptrG3++) = 1 - (Tfloat)std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge); 20977 } 20978 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 20979 const Tfloat 20980 u = G(x,y,z,0), 20981 v = G(x,y,z,1), 20982 w = G(x,y,z,2), 20983 amp = G(x,y,z,3), 20984 ixx = Incc + Ipcc - 2*Iccc, 20985 ixy = (Innc + Ippc - Inpc - Ipnc)/4, 20986 ixz = (Incn + Ipcp - Incp - Ipcn)/4, 20987 iyy = Icnc + Icpc - 2*Iccc, 20988 iyz = (Icnn + Icpp - Icnp - Icpn)/4, 20989 izz = Iccn + Iccp - 2*Iccc, 20990 ixf = Incc - Iccc, 20991 ixb = Iccc - Ipcc, 20992 iyf = Icnc - Iccc, 20993 iyb = Iccc - Icpc, 20994 izf = Iccn - Iccc, 20995 izb = Iccc - Iccp, 20996 itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz, 20997 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb), 20998 veloc = -amp*cimg::sign(itt)*cimg::abs(it); 20999 *(ptrd++) = veloc; 21000 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21001 } 21002 } else cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { // Inverse diffusion. 21003 const Tfloat veloc = -Ipcc - Incc - Icpc - Icnc - Iccp - Iccn + 6*Iccc; 21004 *(ptrd++) = veloc; 21005 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21006 } 21007 } else { 21008 CImg_3x3(I,Tfloat); 21009 if (sharpen_type) { // Shock filters. 21010 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); 21011 if (sigma>0) G.blur(sigma); 21012 Tfloat *ptrG0 = G.data(0,0,0,0), *ptrG1 = G.data(0,0,0,1), *ptrG2 = G.data(0,0,0,2); 21013 cimg_forXY(G,x,y) { 21014 G.get_tensor_at(x,y).symmetric_eigen(val,vec); 21015 if (val[0]<0) val[0] = 0; 21016 if (val[1]<0) val[1] = 0; 21017 *(ptrG0++) = vec(0,0); 21018 *(ptrG1++) = vec(0,1); 21019 *(ptrG2++) = 1 - (Tfloat)std::pow(1+val[0]+val[1],-(Tfloat)nedge); 21020 } 21021 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) { 21022 const Tfloat 21023 u = G(x,y,0), 21024 v = G(x,y,1), 21025 amp = G(x,y,2), 21026 ixx = Inc + Ipc - 2*Icc, 21027 ixy = (Inn + Ipp - Inp - Ipn)/4, 21028 iyy = Icn + Icp - 2*Icc, 21029 ixf = Inc - Icc, 21030 ixb = Icc - Ipc, 21031 iyf = Icn - Icc, 21032 iyb = Icc - Icp, 21033 itt = u*u*ixx + v*v*iyy + 2*u*v*ixy, 21034 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb), 21035 veloc = -amp*cimg::sign(itt)*cimg::abs(it); 21036 *(ptrd++) = veloc; 21037 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21038 } 21039 } else cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) { // Inverse diffusion. 21040 const Tfloat veloc = -Ipc - Inc - Icp - Icn + 4*Icc; 21041 *(ptrd++) = veloc; 21042 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21043 } 21044 } 21045 if (veloc_max<=0) return *this; 21046 return ((velocity*=amplitude/veloc_max)+=*this).cut(val_min,val_max).move_to(*this); 21047 } 21048 21049 CImg<T> get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) const { 21050 return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma); 21051 } 21052 21053 //! Compute the list of images, corresponding to the XY-gradients of an image. 21054 /** 21055 \param scheme = Numerical scheme used for the gradient computation : 21056 - -1 = Backward finite differences 21057 - 0 = Centered finite differences 21058 - 1 = Forward finite differences 21059 - 2 = Using Sobel masks 21060 - 3 = Using rotation invariant masks 21061 - 4 = Using Deriche recusrsive filter. 21062 **/ 21063 CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const { 21064 CImgList<Tfloat> grad(2,_width,_height,_depth,_spectrum); 21065 Tfloat *ptrd0 = grad[0]._data, *ptrd1 = grad[1]._data; 21066 bool is_threed = false; 21067 if (axes) { 21068 for (unsigned int a = 0; axes[a]; ++a) { 21069 const char axis = cimg::uncase(axes[a]); 21070 switch (axis) { 21071 case 'x' : case 'y' : break; 21072 case 'z' : is_threed = true; break; 21073 default : 21074 throw CImgArgumentException(_cimg_instance 21075 "get_gradient() : Invalid specified axis '%c'.", 21076 cimg_instance, 21077 axis); 21078 } 21079 } 21080 } else is_threed = (_depth>1); 21081 if (is_threed) { 21082 CImg<Tfloat>(_width,_height,_depth,_spectrum).move_to(grad); 21083 Tfloat *ptrd2 = grad[2]._data; 21084 switch (scheme) { // 3d. 21085 case -1 : { // Backward finite differences. 21086 CImg_3x3x3(I,Tfloat); 21087 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21088 *(ptrd0++) = Iccc - Ipcc; 21089 *(ptrd1++) = Iccc - Icpc; 21090 *(ptrd2++) = Iccc - Iccp; 21091 } 21092 } break; 21093 case 1 : { // Forward finite differences. 21094 CImg_2x2x2(I,Tfloat); 21095 cimg_forC(*this,c) cimg_for2x2x2(*this,x,y,z,c,I,Tfloat) { 21096 *(ptrd0++) = Incc - Iccc; 21097 *(ptrd1++) = Icnc - Iccc; 21098 *(ptrd2++) = Iccn - Iccc; 21099 } 21100 } break; 21101 case 4 : { // Using Deriche filter with low standard variation. 21102 grad[0] = get_deriche(0,1,'x'); 21103 grad[1] = get_deriche(0,1,'y'); 21104 grad[2] = get_deriche(0,1,'z'); 21105 } break; 21106 default : { // Central finite differences. 21107 CImg_3x3x3(I,Tfloat); 21108 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21109 *(ptrd0++) = (Incc - Ipcc)/2; 21110 *(ptrd1++) = (Icnc - Icpc)/2; 21111 *(ptrd2++) = (Iccn - Iccp)/2; 21112 } 21113 } 21114 } 21115 } else switch (scheme) { // 2d. 21116 case -1 : { // Backward finite differences. 21117 CImg_3x3(I,Tfloat); 21118 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 21119 *(ptrd0++) = Icc - Ipc; 21120 *(ptrd1++) = Icc - Icp; 21121 } 21122 } break; 21123 case 1 : { // Forward finite differences. 21124 CImg_2x2(I,Tfloat); 21125 cimg_forZC(*this,z,c) cimg_for2x2(*this,x,y,z,c,I,Tfloat) { 21126 *(ptrd0++) = Inc - Icc; 21127 *(ptrd1++) = Icn - Icc; 21128 } 21129 } break; 21130 case 2 : { // Sobel scheme. 21131 CImg_3x3(I,Tfloat); 21132 const Tfloat a = 1, b = 2; 21133 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 21134 *(ptrd0++) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn; 21135 *(ptrd1++) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn; 21136 } 21137 } break; 21138 case 3 : { // Rotation invariant mask. 21139 CImg_3x3(I,Tfloat); 21140 const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f)-1)); 21141 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 21142 *(ptrd0++) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn; 21143 *(ptrd1++) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn; 21144 } 21145 } break; 21146 case 4 : { // using Deriche filter with low standard variation 21147 grad[0] = get_deriche(0,1,'x'); 21148 grad[1] = get_deriche(0,1,'y'); 21149 } break; 21150 default : { // central finite differences 21151 CImg_3x3(I,Tfloat); 21152 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 21153 *(ptrd0++) = (Inc - Ipc)/2; 21154 *(ptrd1++) = (Icn - Icp)/2; 21155 } 21156 } 21157 } 21158 if (!axes) return grad; 21159 CImgList<Tfloat> res; 21160 for (unsigned int l = 0; axes[l]; ++l) { 21161 const char axis = cimg::uncase(axes[l]); 21162 switch (axis) { 21163 case 'x' : res.insert(grad[0]); break; 21164 case 'y' : res.insert(grad[1]); break; 21165 case 'z' : res.insert(grad[2]); break; 21166 } 21167 } 21168 grad.assign(); 21169 return res; 21170 } 21171 21172 //! Get components of the Hessian matrix of an image. 21173 CImgList<Tfloat> get_hessian(const char *const axes=0) const { 21174 CImgList<Tfloat> res; 21175 const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz"; 21176 if (!axes) naxes = _depth>1?def_axes3d:def_axes2d; 21177 const unsigned int lmax = std::strlen(naxes); 21178 if (lmax%2) 21179 throw CImgArgumentException(_cimg_instance 21180 "get_hessian() : Invalid specified axes '%s'.", 21181 cimg_instance, 21182 naxes); 21183 21184 res.assign(lmax/2,_width,_height,_depth,_spectrum); 21185 if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d 21186 Tfloat 21187 *ptrd0 = res[0]._data, *ptrd1 = res[1]._data, *ptrd2 = res[2]._data, 21188 *ptrd3 = res[3]._data, *ptrd4 = res[4]._data, *ptrd5 = res[5]._data; 21189 CImg_3x3x3(I,Tfloat); 21190 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21191 *(ptrd0++) = Ipcc + Incc - 2*Iccc; // Ixx 21192 *(ptrd1++) = (Ippc + Innc - Ipnc - Inpc)/4; // Ixy 21193 *(ptrd2++) = (Ipcp + Incn - Ipcn - Incp)/4; // Ixz 21194 *(ptrd3++) = Icpc + Icnc - 2*Iccc; // Iyy 21195 *(ptrd4++) = (Icpp + Icnn - Icpn - Icnp)/4; // Iyz 21196 *(ptrd5++) = Iccn + Iccp - 2*Iccc; // Izz 21197 } 21198 } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // 2d 21199 Tfloat *ptrd0 = res[0]._data, *ptrd1 = res[1]._data, *ptrd2 = res[2]._data; 21200 CImg_3x3(I,Tfloat); 21201 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) { 21202 *(ptrd0++) = Ipc + Inc - 2*Icc; // Ixx 21203 *(ptrd1++) = (Ipp + Inn - Ipn - Inp)/4; // Ixy 21204 *(ptrd2++) = Icp + Icn - 2*Icc; // Iyy 21205 } 21206 } else for (unsigned int l = 0; l<lmax; ) { // Version with custom axes. 21207 const unsigned int l2 = l/2; 21208 char axis1 = naxes[l++], axis2 = naxes[l++]; 21209 if (axis1>axis2) cimg::swap(axis1,axis2); 21210 bool valid_axis = false; 21211 Tfloat *ptrd = res[l2]._data; 21212 if (axis1=='x' && axis2=='x') { // Ixx 21213 valid_axis = true; CImg_3x3(I,Tfloat); 21214 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Ipc + Inc - 2*Icc; 21215 } 21216 else if (axis1=='x' && axis2=='y') { // Ixy 21217 valid_axis = true; CImg_3x3(I,Tfloat); 21218 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipp + Inn - Ipn - Inp)/4; 21219 } 21220 else if (axis1=='x' && axis2=='z') { // Ixz 21221 valid_axis = true; CImg_3x3x3(I,Tfloat); 21222 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipcp + Incn - Ipcn - Incp)/4; 21223 } 21224 else if (axis1=='y' && axis2=='y') { // Iyy 21225 valid_axis = true; CImg_3x3(I,Tfloat); 21226 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Icp + Icn - 2*Icc; 21227 } 21228 else if (axis1=='y' && axis2=='z') { // Iyz 21229 valid_axis = true; CImg_3x3x3(I,Tfloat); 21230 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Icpp + Icnn - Icpn - Icnp)/4; 21231 } 21232 else if (axis1=='z' && axis2=='z') { // Izz 21233 valid_axis = true; CImg_3x3x3(I,Tfloat); 21234 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Iccn + Iccp - 2*Iccc; 21235 } 21236 else if (!valid_axis) 21237 throw CImgArgumentException(_cimg_instance 21238 "get_hessian() : Invalid specified axes '%s'.", 21239 cimg_instance, 21240 naxes); 21241 } 21242 return res; 21243 } 21244 21245 //! Compute the laplacian of the instance image. 21246 CImg<T>& laplacian() { 21247 return get_laplacian().move_to(*this); 21248 } 21249 21250 CImg<Tfloat> get_laplacian() const { 21251 if (is_empty()) return CImg<Tfloat>(); 21252 CImg<Tfloat> res(_width,_height,_depth,_spectrum); 21253 Tfloat *ptrd = res._data; 21254 if (_depth>1) { // 3d 21255 CImg_3x3x3(I,Tfloat); 21256 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) 21257 *(ptrd++) = Incc + Ipcc + Icnc + Icpc + Iccn + Iccp - 6*Iccc; 21258 } else if (_height>1) { // 2d 21259 CImg_3x3(I,Tfloat); 21260 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) 21261 *(ptrd++) = Inc + Ipc + Icn + Icp - 4*Icc; 21262 } else { // 1d 21263 CImg_3x3(I,Tfloat); 21264 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) 21265 *(ptrd++) = Inc + Ipc - 2*Icc; 21266 } 21267 return res; 21268 } 21269 21270 //! Compute the structure tensor field of an image. 21271 CImg<T>& structure_tensors(const unsigned int scheme=1) { 21272 return get_structure_tensors(scheme).move_to(*this); 21273 } 21274 21275 CImg<Tfloat> get_structure_tensors(const unsigned int scheme=1) const { 21276 if (is_empty()) return *this; 21277 CImg<Tfloat> res; 21278 if (_depth>1) { // 3d 21279 res.assign(_width,_height,_depth,6,0); 21280 CImg_3x3x3(I,Tfloat); 21281 switch (scheme) { 21282 case 0 : { // classical central finite differences 21283 cimg_forC(*this,c) { 21284 Tfloat 21285 *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), 21286 *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); 21287 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21288 const Tfloat 21289 ix = (Incc - Ipcc)/2, 21290 iy = (Icnc - Icpc)/2, 21291 iz = (Iccn - Iccp)/2; 21292 *(ptrd0++)+=ix*ix; 21293 *(ptrd1++)+=ix*iy; 21294 *(ptrd2++)+=ix*iz; 21295 *(ptrd3++)+=iy*iy; 21296 *(ptrd4++)+=iy*iz; 21297 *(ptrd5++)+=iz*iz; 21298 } 21299 } 21300 } break; 21301 case 1 : { // Forward/backward finite differences (version 1). 21302 cimg_forC(*this,c) { 21303 Tfloat 21304 *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), 21305 *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); 21306 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21307 const Tfloat 21308 ixf = Incc - Iccc, ixb = Iccc - Ipcc, 21309 iyf = Icnc - Iccc, iyb = Iccc - Icpc, 21310 izf = Iccn - Iccc, izb = Iccc - Iccp; 21311 *(ptrd0++)+=(ixf*ixf + ixf*ixb + ixb*ixf + ixb*ixb)/4; 21312 *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; 21313 *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4; 21314 *(ptrd3++)+=(iyf*iyf + iyf*iyb + iyb*iyf + iyb*iyb)/4; 21315 *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4; 21316 *(ptrd5++)+=(izf*izf + izf*izb + izb*izf + izb*izb)/4; 21317 } 21318 } 21319 } break; 21320 default : { // Forward/backward finite differences (version 2). 21321 cimg_forC(*this,c) { 21322 Tfloat 21323 *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), 21324 *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); 21325 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 21326 const Tfloat 21327 ixf = Incc - Iccc, ixb = Iccc - Ipcc, 21328 iyf = Icnc - Iccc, iyb = Iccc - Icpc, 21329 izf = Iccn - Iccc, izb = Iccc - Iccp; 21330 *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; 21331 *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; 21332 *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4; 21333 *(ptrd3++)+=(iyf*iyf + iyb*iyb)/2; 21334 *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4; 21335 *(ptrd5++)+=(izf*izf + izb*izb)/2; 21336 } 21337 } 21338 } break; 21339 } 21340 } else { // 2d 21341 res.assign(_width,_height,_depth,3,0); 21342 CImg_3x3(I,Tfloat); 21343 switch (scheme) { 21344 case 0 : { // classical central finite differences 21345 cimg_forC(*this,c) { 21346 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 21347 cimg_for3x3(*this,x,y,0,c,I,Tfloat) { 21348 const Tfloat 21349 ix = (Inc - Ipc)/2, 21350 iy = (Icn - Icp)/2; 21351 *(ptrd0++)+=ix*ix; 21352 *(ptrd1++)+=ix*iy; 21353 *(ptrd2++)+=iy*iy; 21354 } 21355 } 21356 } break; 21357 case 1 : { // Forward/backward finite differences (version 1). 21358 cimg_forC(*this,c) { 21359 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 21360 cimg_for3x3(*this,x,y,0,c,I,Tfloat) { 21361 const Tfloat 21362 ixf = Inc - Icc, ixb = Icc - Ipc, 21363 iyf = Icn - Icc, iyb = Icc - Icp; 21364 *(ptrd0++)+=(ixf*ixf + ixf*ixb + ixb*iyf + ixb*ixb)/4; 21365 *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; 21366 *(ptrd2++)+=(iyf*iyf + iyf*iyb + iyb*iyf + iyb*iyb)/4; 21367 } 21368 } 21369 } break; 21370 default : { // Forward/backward finite differences (version 2). 21371 cimg_forC(*this,c) { 21372 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 21373 cimg_for3x3(*this,x,y,0,c,I,Tfloat) { 21374 const Tfloat 21375 ixf = Inc - Icc, ixb = Icc - Ipc, 21376 iyf = Icn - Icc, iyb = Icc - Icp; 21377 *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; 21378 *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4; 21379 *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2; 21380 } 21381 } 21382 } break; 21383 } 21384 } 21385 return res; 21386 } 21387 21388 //! Get a diffusion tensor for edge-preserving anisotropic smoothing of an image. 21389 CImg<T>& edge_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, 21390 const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) { 21391 CImg<Tfloat> res; 21392 const float nsharpness = cimg::max(sharpness,1e-5f), power1 = (is_sqrt?0.5f:1)*nsharpness, power2 = power1/(1e-7f+1-anisotropy); 21393 blur(alpha).normalize(0,(T)255); 21394 21395 if (_depth>1) { // 3d 21396 CImg<floatT> val(3), vec(3,3); 21397 get_structure_tensors().move_to(res).blur(sigma); 21398 Tfloat 21399 *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), 21400 *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); 21401 cimg_forXYZ(*this,x,y,z) { 21402 res.get_tensor_at(x,y,z).symmetric_eigen(val,vec); 21403 const float 21404 _l1 = val[2], _l2 = val[1], _l3 = val[0], 21405 l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0, 21406 ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), 21407 vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), 21408 wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), 21409 n1 = (float)std::pow(1+l1+l2+l3,-power1), 21410 n2 = (float)std::pow(1+l1+l2+l3,-power2); 21411 *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx; 21412 *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy; 21413 *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz; 21414 *(ptrd3++) = n1*(uy*uy + vy*vy) + n2*wy*wy; 21415 *(ptrd4++) = n1*(uy*uz + vy*vz) + n2*wy*wz; 21416 *(ptrd5++) = n1*(uz*uz + vz*vz) + n2*wz*wz; 21417 } 21418 } else { // for 2d images 21419 CImg<floatT> val(2), vec(2,2); 21420 get_structure_tensors().move_to(res).blur(sigma); 21421 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 21422 cimg_forXY(*this,x,y) { 21423 res.get_tensor_at(x,y).symmetric_eigen(val,vec); 21424 const float 21425 _l1 = val[1], _l2 = val[0], 21426 l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, 21427 ux = vec(1,0), uy = vec(1,1), 21428 vx = vec(0,0), vy = vec(0,1), 21429 n1 = (float)std::pow(1+l1+l2,-power1), 21430 n2 = (float)std::pow(1+l1+l2,-power2); 21431 *(ptrd0++) = n1*ux*ux + n2*vx*vx; 21432 *(ptrd1++) = n1*ux*uy + n2*vx*vy; 21433 *(ptrd2++) = n1*uy*uy + n2*vy*vy; 21434 } 21435 } 21436 return res.move_to(*this); 21437 } 21438 21439 CImg<Tfloat> get_edge_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, 21440 const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const { 21441 return CImg<Tfloat>(*this,false).edge_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt); 21442 } 21443 21444 //! Estimate a displacement field between instance image and given target image. 21445 /** 21446 \param backward : if false, match I2(X+U(X)) = I1(X), else match I2(X) = I1(X-U(X)). 21447 **/ 21448 CImg<T>& displacement(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f, 21449 const unsigned int nb_scales=0, const unsigned int iteration_max=1000, 21450 const bool backward = true) { 21451 return get_displacement(target,smooth,precision,nb_scales,iteration_max,backward).move_to(*this); 21452 } 21453 21454 CImg<Tfloat> get_displacement(const CImg<T>& target, 21455 const float smoothness=0.1f, const float precision=0.1f, 21456 const unsigned int nb_scales=0, const unsigned int iteration_max=1000, 21457 const bool backward = true) const { 21458 if (is_empty() || !target) return *this; 21459 if (!is_sameXYZC(target)) 21460 throw CImgArgumentException(_cimg_instance 21461 "displacement() : Instance and target image (%u,%u,%u,%u,%p) have different dimensions.", 21462 cimg_instance, 21463 target._width,target._height,target._depth,target._spectrum,target._data); 21464 if (smoothness<0) 21465 throw CImgArgumentException(_cimg_instance 21466 "displacement() : Invalid specified smoothness %g " 21467 "(should be >=0", 21468 cimg_instance, 21469 smoothness); 21470 if (precision<0) 21471 throw CImgArgumentException(_cimg_instance 21472 "displacement() : Invalid specified precision %g " 21473 "(should be >=0", 21474 cimg_instance, 21475 precision); 21476 21477 const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*std::log((double)(cimg::max(_width,_height,_depth)))); 21478 Tfloat m1, M1 = (Tfloat)max_min(m1), m2, M2 = (Tfloat)target.max_min(m2); 21479 const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2)); 21480 CImg<Tfloat> U0; 21481 const bool is_threed = (_depth>1); 21482 21483 // Begin multi-scale motion estimation 21484 for (int scale = (int)nscales-1; scale>=0; --scale) { 21485 const float sfactor = (float)std::pow(1.5f,(float)scale), sprecision = (float)(precision/std::pow(2.25,1+scale)); 21486 const int 21487 sw = (int)(_width/sfactor), sh = (int)(_height/sfactor), sd = (int)(_depth/sfactor), 21488 swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1; 21489 CImg<Tfloat> 21490 I1 = get_resize(swidth,sheight,sdepth,-100,2), 21491 I2 = target.get_resize(swidth,sheight,sdepth,-100,2); 21492 I1/=factor; I2/=factor; 21493 CImg<Tfloat> U; 21494 if (U0) U = (U0*=1.5f).get_resize(I1.width(),I1.height(),I1.depth(),-100,3); 21495 else U.assign(I1.width(),I1.height(),I1.depth(),is_threed?3:2,0); 21496 21497 // Begin single-scale motion estimation 21498 CImg<Tfloat> veloc(U); 21499 float dt = 2, energy = cimg::type<float>::max(); 21500 const CImgList<Tfloat> dI = backward?I1.get_gradient():I2.get_gradient(); 21501 for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) { 21502 veloc.fill(0); 21503 float nenergy = 0; 21504 if (is_threed) { 21505 cimg_for3XYZ(U,x,y,z) { 21506 const float 21507 sgnU = backward?-1.0f:1.0f, 21508 X = (float)(x + sgnU * U(x,y,z,0)), 21509 Y = (float)(y + sgnU * U(x,y,z,1)), 21510 Z = (float)(z + sgnU * U(x,y,z,2)); 21511 cimg_forC(U,c) { 21512 const Tfloat 21513 Ux = 0.5f*(U(_n1x,y,z,c) - U(_p1x,y,z,c)), 21514 Uy = 0.5f*(U(x,_n1y,z,c) - U(x,_p1y,z,c)), 21515 Uz = 0.5f*(U(x,y,_n1z,c) - U(x,y,_p1z,c)), 21516 Uxx = U(_n1x,y,z,c) + U(_p1x,y,z,c) - 2*U(x,y,z,c), 21517 Uyy = U(x,_n1y,z,c) + U(x,_p1y,z,c) - 2*U(x,y,z,c), 21518 Uzz = U(x,y,_n1z,c) + U(x,y,_n1z,c) - 2*U(x,y,z,c); 21519 nenergy+=(float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz)); 21520 Tfloat deltaIgrad = 0; 21521 cimg_forC(I1,i) { 21522 const Tfloat deltaIi = (float)(backward?I2(x,y,z,i)-I1._linear_atXYZ(X,Y,Z,i):I2._linear_atXYZ(X,Y,Z,i)-I1(x,y,z,i)); 21523 nenergy+=(float)(deltaIi*deltaIi/2); 21524 deltaIgrad+=-deltaIi*dI[c]._linear_atXYZ(X,Y,Z,i); 21525 } 21526 veloc(x,y,z,c) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz); 21527 } 21528 } 21529 } else { 21530 cimg_for3XY(U,x,y) { 21531 const float 21532 sgnU = backward?-1.0f:1.0f, 21533 X = (float)(x + sgnU * U(x,y,0)), 21534 Y = (float)(y + sgnU * U(x,y,1)); 21535 cimg_forC(U,c) { 21536 const Tfloat 21537 Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)), 21538 Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)), 21539 Uxx = U(_n1x,y,c) + U(_p1x,y,c) - 2*U(x,y,c), 21540 Uyy = U(x,_n1y,c) + U(x,_p1y,c) - 2*U(x,y,c); 21541 nenergy+=(float)(smoothness*(Ux*Ux + Uy*Uy)); 21542 Tfloat deltaIgrad = 0; 21543 cimg_forC(I1,i) { 21544 const Tfloat deltaIi = (float)(backward?I2(x,y,i)-I1.linear_atXY(X,Y,i):I2._linear_atXY(X,Y,i)-I1(x,y,i)); 21545 nenergy+=(float)(deltaIi*deltaIi/2); 21546 deltaIgrad+=-deltaIi*dI[c]._linear_atXY(X,Y,i); 21547 } 21548 veloc(x,y,c) = deltaIgrad + smoothness*(Uxx + Uyy); 21549 } 21550 } 21551 } 21552 const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max())); 21553 U+=(veloc*=dt/(1e-6+vmax)); 21554 if (cimg::abs(nenergy-energy)<sprecision) break; 21555 if (nenergy<energy) dt*=0.5f; 21556 energy = nenergy; 21557 } 21558 U.move_to(U0); 21559 } 21560 return U0; 21561 } 21562 21563 //! Compute the Euclidean distance map to a shape of specified isovalue. 21564 CImg<T>& distance(const T isovalue, 21565 const float sizex=1, const float sizey=1, const float sizez=1, 21566 const bool compute_sqrt=true) { 21567 return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).move_to(*this); 21568 } 21569 21570 CImg<floatT> get_distance(const T isovalue, 21571 const float sizex=1, const float sizey=1, const float sizez=1, 21572 const bool compute_sqrt=true) const { 21573 if (is_empty()) return *this; 21574 const int dx = width(), dy = height(), dz = depth(); 21575 CImg<floatT> res(dx,dy,dz,_spectrum); 21576 const float maxdist = (float)std::sqrt((float)dx*dx + dy*dy + dz*dz); 21577 cimg_forC(*this,c) { 21578 bool is_isophote = false; 21579 21580 if (_depth>1) { // 3d version 21581 cimg_forYZ(*this,y,z) { 21582 if ((*this)(0,y,z,c)==isovalue) { is_isophote = true; res(0,y,z,c) = 0; } else res(0,y,z,c) = maxdist; 21583 for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,c)==isovalue) { is_isophote = true; res(x,y,z,c) = 0; } 21584 else res(x,y,z,c) = res(x-1,y,z,c) + sizex; 21585 for (int x = dx-2; x>=0; --x) if (res(x+1,y,z,c)<res(x,y,z,c)) res(x,y,z,c) = res(x+1,y,z,c) + sizex; 21586 } 21587 if (!is_isophote) { res.get_shared_channel(c).fill(cimg::type<floatT>::max()); continue; } 21588 CImg<floatT> tmp(cimg::max(dy,dz)); 21589 CImg<intT> s(tmp._width), t(s._width); 21590 cimg_forXZ(*this,x,z) { 21591 cimg_forY(*this,y) tmp[y] = res(x,y,z,c); 21592 int q = s[0] = t[0] = 0; 21593 for (int y = 1; y<dy; ++y) { 21594 const float val = tmp[y], val2 = val*val; 21595 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q; 21596 if (q<0) { q = 0; s[0] = y; } 21597 else { 21598 const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey); 21599 if (w<dy) { s[++q] = y; t[q] = w; } 21600 } 21601 } 21602 for (int y = dy - 1; y>=0; --y) { 21603 res(x,y,z,c) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey); 21604 if (y==t[q]) --q; 21605 } 21606 } 21607 cimg_forXY(*this,x,y) { 21608 cimg_forZ(*this,z) tmp[z] = res(x,y,z,c); 21609 int q = s[0] = t[0] = 0; 21610 for (int z = 1; z<dz; ++z) { 21611 const float val = tmp[z]; 21612 while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q; 21613 if (q<0) { q = 0; s[0] = z; } 21614 else { 21615 const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez); 21616 if (w<dz) { s[++q] = z; t[q] = w; } 21617 } 21618 } 21619 for (int z = dz - 1; z>=0; --z) { 21620 const float val = _distance_f(z,s[q],tmp[s[q]],sizez); 21621 res(x,y,z,c) = compute_sqrt?(float)std::sqrt(val):val; 21622 if (z==t[q]) --q; 21623 } 21624 } 21625 } else { // 2d version (with small optimizations) 21626 cimg_forX(*this,x) { 21627 const T *ptrs = data(x,0,0,c); 21628 float *ptrd = res.data(x,0,0,c), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist; 21629 for (int y = 1; y<dy; ++y) { ptrs+=_width; ptrd+=_width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; } 21630 for (int y = dy - 2; y>=0; --y) { ptrd-=_width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; } 21631 } 21632 if (!is_isophote) { res.get_shared_channel(c).fill(cimg::type<floatT>::max()); continue; } 21633 CImg<floatT> tmp(dx); 21634 CImg<intT> s(dx), t(dx); 21635 cimg_forY(*this,y) { 21636 float *ptmp = tmp._data; 21637 std::memcpy(ptmp,res.data(0,y,0,c),sizeof(float)*dx); 21638 int q = s[0] = t[0] = 0; 21639 for (int x = 1; x<dx; ++x) { 21640 const float val = *(++ptmp), val2 = val*val; 21641 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q; 21642 if (q<0) { q = 0; s[0] = x; } 21643 else { 21644 const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex); 21645 if (w<dx) { s[++q] = x; t[q] = w; } 21646 } 21647 } 21648 float *pres = res.data(0,y,0,c) + _width; 21649 for (int x = dx - 1; x>=0; --x) { 21650 const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex); 21651 *(--pres) = compute_sqrt?(float)std::sqrt(val):val; 21652 if (x==t[q]) --q; 21653 } 21654 } 21655 } 21656 } 21657 return res; 21658 } 21659 21660 static float _distance_f(const int x, const int i, const float gi2, const float fact) { 21661 const float xmi = fact*((float)x - i); 21662 return xmi*xmi + gi2; 21663 } 21664 static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) { 21665 const float fact2 = fact*fact; 21666 return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i)); 21667 } 21668 21669 //! Compute distance function from 0-valued isophotes by the application of an Eikonal PDE. 21670 CImg<T>& distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) { 21671 if (is_empty()) return *this; 21672 CImg<Tfloat> velocity(*this); 21673 for (unsigned int iteration = 0; iteration<nb_iterations; ++iteration) { 21674 Tfloat *ptrd = velocity._data, veloc_max = 0; 21675 if (_depth>1) { // 3d 21676 CImg_3x3x3(I,Tfloat); 21677 cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) if (band_size<=0 || cimg::abs(Iccc)<band_size) { 21678 const Tfloat 21679 gx = (Incc - Ipcc)/2, 21680 gy = (Icnc - Icpc)/2, 21681 gz = (Iccn - Iccp)/2, 21682 sgn = -cimg::sign(Iccc), 21683 ix = gx*sgn>0?(Incc - Iccc):(Iccc - Ipcc), 21684 iy = gy*sgn>0?(Icnc - Iccc):(Iccc - Icpc), 21685 iz = gz*sgn>0?(Iccn - Iccc):(Iccc - Iccp), 21686 ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy + gz*gz)), 21687 ngx = gx/ng, 21688 ngy = gy/ng, 21689 ngz = gz/ng, 21690 veloc = sgn*(ngx*ix + ngy*iy + ngz*iz - 1); 21691 *(ptrd++) = veloc; 21692 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21693 } else *(ptrd++) = 0; 21694 } else { // 2d version 21695 CImg_3x3(I,Tfloat); 21696 cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) if (band_size<=0 || cimg::abs(Icc)<band_size) { 21697 const Tfloat 21698 gx = (Inc - Ipc)/2, 21699 gy = (Icn - Icp)/2, 21700 sgn = -cimg::sign(Icc), 21701 ix = gx*sgn>0?(Inc - Icc):(Icc - Ipc), 21702 iy = gy*sgn>0?(Icn - Icc):(Icc - Icp), 21703 ng = (Tfloat)(1e-5f + std::sqrt(gx*gx + gy*gy)), 21704 ngx = gx/ng, 21705 ngy = gy/ng, 21706 veloc = sgn*(ngx*ix + ngy*iy - 1); 21707 *(ptrd++) = veloc; 21708 if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; 21709 } else *(ptrd++) = 0; 21710 } 21711 if (veloc_max>0) *this+=(velocity*=time_step/veloc_max); 21712 } 21713 return *this; 21714 } 21715 21716 CImg<Tfloat> get_distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) const { 21717 return CImg<Tfloat>(*this,false).distance_eikonal(nb_iterations,band_size,time_step); 21718 } 21719 21720 //! Compute the Haar multiscale wavelet transform (monodimensional version). 21721 /** 21722 \param axis Axis considered for the transform. 21723 \param invert Set inverse of direct transform. 21724 \param nb_scales Number of scales used for the transform. 21725 **/ 21726 CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) { 21727 return get_haar(axis,invert,nb_scales).move_to(*this); 21728 } 21729 21730 CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const { 21731 if (is_empty() || !nb_scales) return *this; 21732 CImg<Tfloat> res; 21733 21734 if (nb_scales==1) { 21735 switch (cimg::uncase(axis)) { // Single scale transform 21736 case 'x' : { 21737 const unsigned int w = _width/2; 21738 if (w) { 21739 if (w%2) 21740 throw CImgInstanceException(_cimg_instance 21741 "haar() : Sub-image width %u is not even at scale %u.", 21742 cimg_instance, 21743 w); 21744 21745 res.assign(_width,_height,_depth,_spectrum); 21746 if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X 21747 for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) { 21748 const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(xw,y,z,c); 21749 res(x2++,y,z,c) = val0 - val1; 21750 res(x2++,y,z,c) = val0 + val1; 21751 } 21752 } else cimg_forYZC(*this,y,z,c) { // Direct transform along X 21753 for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) { 21754 const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,c), val1 = (Tfloat)(*this)(x2++,y,z,c); 21755 res(x,y,z,c) = (val0 + val1)/2; 21756 res(xw,y,z,c) = (val1 - val0)/2; 21757 } 21758 } 21759 } else return *this; 21760 } break; 21761 case 'y' : { 21762 const unsigned int h = _height/2; 21763 if (h) { 21764 if (h%2) 21765 throw CImgInstanceException(_cimg_instance 21766 "haar() : Sub-image height %u is not even at scale %u.", 21767 cimg_instance, 21768 h); 21769 21770 res.assign(_width,_height,_depth,_spectrum); 21771 if (invert) cimg_forXZC(*this,x,z,c) { // Inverse transform along Y 21772 for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { 21773 const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,yh,z,c); 21774 res(x,y2++,z,c) = val0 - val1; 21775 res(x,y2++,z,c) = val0 + val1; 21776 } 21777 } else cimg_forXZC(*this,x,z,c) { 21778 for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { // Direct transform along Y 21779 const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,c), val1 = (Tfloat)(*this)(x,y2++,z,c); 21780 res(x,y,z,c) = (val0 + val1)/2; 21781 res(x,yh,z,c) = (val1 - val0)/2; 21782 } 21783 } 21784 } else return *this; 21785 } break; 21786 case 'z' : { 21787 const unsigned int d = _depth/2; 21788 if (d) { 21789 if (d%2) 21790 throw CImgInstanceException(_cimg_instance 21791 "haar() : Sub-image depth %u is not even at scale %u.", 21792 cimg_instance, 21793 d); 21794 21795 res.assign(_width,_height,_depth,_spectrum); 21796 if (invert) cimg_forXYC(*this,x,y,c) { // Inverse transform along Z 21797 for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { 21798 const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,y,zd,c); 21799 res(x,y,z2++,c) = val0 - val1; 21800 res(x,y,z2++,c) = val0 + val1; 21801 } 21802 } else cimg_forXYC(*this,x,y,c) { 21803 for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z 21804 const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,c), val1 = (Tfloat)(*this)(x,y,z2++,c); 21805 res(x,y,z,c) = (val0 + val1)/2; 21806 res(x,y,zd,c) = (val1 - val0)/2; 21807 } 21808 } 21809 } else return *this; 21810 } break; 21811 default : 21812 throw CImgArgumentException(_cimg_instance 21813 "haar() : Invalid specified axis '%c' " 21814 "(should be { x | y | z }).", 21815 cimg_instance, 21816 axis); 21817 } 21818 } else { // Multi-scale version 21819 if (invert) { 21820 res.assign(*this); 21821 switch (cimg::uncase(axis)) { 21822 case 'x' : { 21823 unsigned int w = _width; 21824 for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2; 21825 for (w = w?w:1; w<=_width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1)); 21826 } break; 21827 case 'y' : { 21828 unsigned int h = _width; 21829 for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2; 21830 for (h = h?h:1; h<=_height; h*=2) res.draw_image(res.get_crop(0,0,_width-1,h-1).get_haar('y',true,1)); 21831 } break; 21832 case 'z' : { 21833 unsigned int d = _depth; 21834 for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2; 21835 for (d = d?d:1; d<=_depth; d*=2) res.draw_image(res.get_crop(0,0,0,_width-1,_height-1,d-1).get_haar('z',true,1)); 21836 } break; 21837 default : 21838 throw CImgArgumentException(_cimg_instance 21839 "haar() : Invalid specified axis '%c' " 21840 "(should be { x | y | z }).", 21841 cimg_instance, 21842 axis); 21843 } 21844 } else { // Direct transform 21845 res = get_haar(axis,false,1); 21846 switch (cimg::uncase(axis)) { 21847 case 'x' : { 21848 for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',false,1)); 21849 } break; 21850 case 'y' : { 21851 for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2) res.draw_image(res.get_crop(0,0,_width-1,h-1).get_haar('y',false,1)); 21852 } break; 21853 case 'z' : { 21854 for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2) res.draw_image(res.get_crop(0,0,0,_width-1,_height-1,d-1).get_haar('z',false,1)); 21855 } break; 21856 default : 21857 throw CImgArgumentException(_cimg_instance 21858 "haar() : Invalid specified axis '%c' " 21859 "(should be { x | y | z }).", 21860 cimg_instance, 21861 axis); 21862 } 21863 } 21864 } 21865 return res; 21866 } 21867 21868 //! Compute the Haar multiscale wavelet transform. 21869 /** 21870 \param invert Set inverse of direct transform. 21871 \param nb_scales Number of scales used for the transform. 21872 **/ 21873 CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) { 21874 return get_haar(invert,nb_scales).move_to(*this); 21875 } 21876 21877 CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const { 21878 CImg<Tfloat> res; 21879 21880 if (nb_scales==1) { // Single scale transform 21881 if (_width>1) get_haar('x',invert,1).move_to(res); 21882 if (_height>1) { if (res) res.haar('y',invert,1); else get_haar('y',invert,1).move_to(res); } 21883 if (_depth>1) { if (res) res.haar('z',invert,1); else get_haar('z',invert,1).move_to(res); } 21884 if (res) return res; 21885 } else { // Multi-scale transform 21886 if (invert) { // Inverse transform 21887 res.assign(*this); 21888 if (_width>1) { 21889 if (_height>1) { 21890 if (_depth>1) { 21891 unsigned int w = _width, h = _height, d = _depth; for (unsigned int s = 1; w && h && d && s<nb_scales; ++s) { w/=2; h/=2; d/=2; } 21892 for (w = w?w:1, h = h?h:1, d = d?d:1; w<=_width && h<=_height && d<=_depth; w*=2, h*=2, d*=2) 21893 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1)); 21894 } else { 21895 unsigned int w = _width, h = _height; for (unsigned int s = 1; w && h && s<nb_scales; ++s) { w/=2; h/=2; } 21896 for (w = w?w:1, h = h?h:1; w<=_width && h<=_height; w*=2, h*=2) 21897 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1)); 21898 } 21899 } else { 21900 if (_depth>1) { 21901 unsigned int w = _width, d = _depth; for (unsigned int s = 1; w && d && s<nb_scales; ++s) { w/=2; d/=2; } 21902 for (w = w?w:1, d = d?d:1; w<=_width && d<=_depth; w*=2, d*=2) 21903 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1)); 21904 } else { 21905 unsigned int w = _width; for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2; 21906 for (w = w?w:1; w<=_width; w*=2) 21907 res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1)); 21908 } 21909 } 21910 } else { 21911 if (_height>1) { 21912 if (_depth>1) { 21913 unsigned int h = _height, d = _depth; for (unsigned int s = 1; h && d && s<nb_scales; ++s) { h/=2; d/=2; } 21914 for (h = h?h:1, d = d?d:1; h<=_height && d<=_depth; h*=2, d*=2) 21915 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1)); 21916 } else { 21917 unsigned int h = _height; for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2; 21918 for (h = h?h:1; h<=_height; h*=2) 21919 res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1)); 21920 } 21921 } else { 21922 if (_depth>1) { 21923 unsigned int d = _depth; for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2; 21924 for (d = d?d:1; d<=_depth; d*=2) 21925 res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1)); 21926 } else return *this; 21927 } 21928 } 21929 } else { // Direct transform 21930 res = get_haar(false,1); 21931 if (_width>1) { 21932 if (_height>1) { 21933 if (_depth>1) for (unsigned int s = 1, w = _width/2, h = _height/2, d = _depth/2; w && h && d && s<nb_scales; ++s, w/=2, h/=2, d/=2) 21934 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1)); 21935 else for (unsigned int s = 1, w = _width/2, h = _height/2; w && h && s<nb_scales; ++s, w/=2, h/=2) 21936 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1)); 21937 } else { 21938 if (_depth>1) for (unsigned int s = 1, w = _width/2, d = _depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2) 21939 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1)); 21940 else for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2) 21941 res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1)); 21942 } 21943 } else { 21944 if (_height>1) { 21945 if (_depth>1) for (unsigned int s = 1, h = _height/2, d = _depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2) 21946 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1)); 21947 else for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2) 21948 res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1)); 21949 } else { 21950 if (_depth>1) for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2) 21951 res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1)); 21952 else return *this; 21953 } 21954 } 21955 } 21956 return res; 21957 } 21958 return *this; 21959 } 21960 21961 //! Compute a 1d Fast Fourier Transform, along a specified axis. 21962 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const { 21963 CImgList<Tfloat> res(*this,CImg<Tfloat>()); 21964 CImg<Tfloat>::FFT(res[0],res[1],axis,invert); 21965 return res; 21966 } 21967 21968 //! Compute a n-d Fast-Fourier Transform. 21969 CImgList<Tfloat> get_FFT(const bool invert=false) const { 21970 CImgList<Tfloat> res(*this,CImg<Tfloat>()); 21971 CImg<Tfloat>::FFT(res[0],res[1],invert); 21972 return res; 21973 } 21974 21975 //! Compute a 1d Fast Fourier Transform, along a specified axis. 21976 static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool invert=false) { 21977 if (!real) 21978 throw CImgInstanceException("CImg<%s>::FFT() : Specified real part is empty.", 21979 pixel_type()); 21980 21981 if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0); 21982 if (!real.is_sameXYZC(imag)) 21983 throw CImgInstanceException("CImg<%s>::FFT() : Specified real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p) have different dimensions.", 21984 pixel_type(), 21985 real._width,real._height,real._depth,real._spectrum,real._data, 21986 imag._width,imag._height,imag._depth,imag._spectrum,imag._data); 21987 #ifdef cimg_use_fftw3 21988 fftw_complex *data_in; 21989 fftw_plan data_plan; 21990 21991 switch (cimg::uncase(axis)) { 21992 case 'x' : { // Fourier along X, using FFTW library. 21993 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width); 21994 data_plan = fftw_plan_dft_1d(real._width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); 21995 cimg_forYZC(real,y,z,c) { 21996 T *ptrr = real.data(0,y,z,c), *ptri = imag.data(0,y,z,c); 21997 double *ptrd = (double*)data_in; 21998 cimg_forX(real,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); } 21999 fftw_execute(data_plan); 22000 const unsigned int fact = real._width; 22001 if (invert) cimg_forX(real,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); } 22002 else cimg_forX(real,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); } 22003 } 22004 } break; 22005 case 'y' : { // Fourier along Y, using FFTW library. 22006 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._height); 22007 data_plan = fftw_plan_dft_1d(real._height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); 22008 const unsigned int off = real._width; 22009 cimg_forXZC(real,x,z,c) { 22010 T *ptrr = real.data(x,0,z,c), *ptri = imag.data(x,0,z,c); 22011 double *ptrd = (double*)data_in; 22012 cimg_forY(real,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } 22013 fftw_execute(data_plan); 22014 const unsigned int fact = real._height; 22015 if (invert) cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } 22016 else cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } 22017 } 22018 } break; 22019 case 'z' : { // Fourier along Z, using FFTW library. 22020 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._depth); 22021 data_plan = fftw_plan_dft_1d(real._depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); 22022 const unsigned int off = real._width*real._height; 22023 cimg_forXYC(real,x,y,c) { 22024 T *ptrr = real.data(x,y,0,c), *ptri = imag.data(x,y,0,c); 22025 double *ptrd = (double*)data_in; 22026 cimg_forZ(real,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } 22027 fftw_execute(data_plan); 22028 const unsigned int fact = real._depth; 22029 if (invert) cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } 22030 else cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } 22031 } 22032 } break; 22033 default : { // Fourier along C, using FFTW library. 22034 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real._spectrum); 22035 data_plan = fftw_plan_dft_1d(real._spectrum,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); 22036 const unsigned int off = real._width*real._height*real._depth; 22037 cimg_forXYZ(real,x,y,z) { 22038 T *ptrr = real.data(x,y,z,0), *ptri = imag.data(x,y,z,0); 22039 double *ptrd = (double*)data_in; 22040 cimg_forC(real,c) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } 22041 fftw_execute(data_plan); 22042 const unsigned int fact = real._spectrum; 22043 if (invert) cimg_forC(real,c) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); } 22044 else cimg_forC(real,c) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } 22045 } 22046 } 22047 } 22048 fftw_destroy_plan(data_plan); 22049 fftw_free(data_in); 22050 #else 22051 switch (cimg::uncase(axis)) { 22052 case 'x' : { // Fourier along X, using built-in functions. 22053 const unsigned int N = real._width, N2 = (N>>1); 22054 if (((N-1)&N) && N!=1) 22055 throw CImgInstanceException("CImgList<%s>::FFT() : Specified real and imaginary parts (%u,%u,%u,%u) have non 2^N dimension along the X-axis.", 22056 pixel_type(), 22057 real._width,real._height,real._depth,real._spectrum); 22058 22059 for (unsigned int i = 0, j = 0; i<N2; ++i) { 22060 if (j>i) cimg_forYZC(real,y,z,c) { 22061 cimg::swap(real(i,y,z,c),real(j,y,z,c)); cimg::swap(imag(i,y,z,c),imag(j,y,z,c)); 22062 if (j<N2) { 22063 const unsigned int ri = N-1-i, rj = N-1-j; 22064 cimg::swap(real(ri,y,z,c),real(rj,y,z,c)); cimg::swap(imag(ri,y,z,c),imag(rj,y,z,c)); 22065 } 22066 } 22067 for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {} 22068 } 22069 for (unsigned int delta = 2; delta<=N; delta<<=1) { 22070 const unsigned int delta2 = (delta>>1); 22071 for (unsigned int i = 0; i<N; i+=delta) { 22072 float wr = 1, wi = 0; 22073 const float angle = (float)((invert?+1:-1)*2*cimg::PI/delta), 22074 ca = (float)std::cos(angle), 22075 sa = (float)std::sin(angle); 22076 for (unsigned int k = 0; k<delta2; ++k) { 22077 const unsigned int j = i + k, nj = j + delta2; 22078 cimg_forYZC(real,y,z,c) { 22079 T &ir = real(j,y,z,c), &ii = imag(j,y,z,c), &nir = real(nj,y,z,c), &nii = imag(nj,y,z,c); 22080 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir); 22081 nir = (T)(ir - tmpr); 22082 nii = (T)(ii - tmpi); 22083 ir+=(T)tmpr; 22084 ii+=(T)tmpi; 22085 } 22086 const float nwr = wr*ca-wi*sa; 22087 wi = wi*ca + wr*sa; 22088 wr = nwr; 22089 } 22090 } 22091 } 22092 if (invert) { real/=N; imag/=N; } 22093 } break; 22094 case 'y' : { // Fourier along Y, using built-in functions. 22095 const unsigned int N = real._height, N2 = (N>>1); 22096 if (((N-1)&N) && N!=1) 22097 throw CImgInstanceException("CImgList<%s>::FFT() : Specified real and imaginary parts (%u,%u,%u,%u) have non 2^N dimension along the Y-axis.", 22098 pixel_type(), 22099 real._width,real._height,real._depth,real._spectrum); 22100 22101 for (unsigned int i = 0, j = 0; i<N2; ++i) { 22102 if (j>i) cimg_forXZC(real,x,z,c) { 22103 cimg::swap(real(x,i,z,c),real(x,j,z,c)); cimg::swap(imag(x,i,z,c),imag(x,j,z,c)); 22104 if (j<N2) { 22105 const unsigned int ri = N - 1 - i, rj = N - 1 - j; 22106 cimg::swap(real(x,ri,z,c),real(x,rj,z,c)); cimg::swap(imag(x,ri,z,c),imag(x,rj,z,c)); 22107 } 22108 } 22109 for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {} 22110 } 22111 for (unsigned int delta = 2; delta<=N; delta<<=1) { 22112 const unsigned int delta2 = (delta>>1); 22113 for (unsigned int i = 0; i<N; i+=delta) { 22114 float wr = 1, wi = 0; 22115 const float angle = (float)((invert?+1:-1)*2*cimg::PI/delta), 22116 ca = (float)std::cos(angle), sa = (float)std::sin(angle); 22117 for (unsigned int k = 0; k<delta2; ++k) { 22118 const unsigned int j = i + k, nj = j + delta2; 22119 cimg_forXZC(real,x,z,c) { 22120 T &ir = real(x,j,z,c), &ii = imag(x,j,z,c), &nir = real(x,nj,z,c), &nii = imag(x,nj,z,c); 22121 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir); 22122 nir = (T)(ir - tmpr); 22123 nii = (T)(ii - tmpi); 22124 ir+=(T)tmpr; 22125 ii+=(T)tmpi; 22126 } 22127 const float nwr = wr*ca-wi*sa; 22128 wi = wi*ca + wr*sa; 22129 wr = nwr; 22130 } 22131 } 22132 } 22133 if (invert) { real/=N; imag/=N; } 22134 } break; 22135 case 'z' : { // Fourier along Z, using built-in functions. 22136 const unsigned int N = real._depth, N2 = (N>>1); 22137 if (((N-1)&N) && N!=1) 22138 throw CImgInstanceException("CImgList<%s>::FFT() : Specified real and imaginary parts (%u,%u,%u,%u) have non 2^N dimension along the Z-axis.", 22139 pixel_type(), 22140 real._width,real._height,real._depth,real._spectrum); 22141 22142 for (unsigned int i = 0, j = 0; i<N2; ++i) { 22143 if (j>i) cimg_forXYC(real,x,y,c) { 22144 cimg::swap(real(x,y,i,c),real(x,y,j,c)); cimg::swap(imag(x,y,i,c),imag(x,y,j,c)); 22145 if (j<N2) { 22146 const unsigned int ri = N - 1 - i, rj = N - 1 - j; 22147 cimg::swap(real(x,y,ri,c),real(x,y,rj,c)); cimg::swap(imag(x,y,ri,c),imag(x,y,rj,c)); 22148 } 22149 } 22150 for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {} 22151 } 22152 for (unsigned int delta = 2; delta<=N; delta<<=1) { 22153 const unsigned int delta2 = (delta>>1); 22154 for (unsigned int i = 0; i<N; i+=delta) { 22155 float wr = 1, wi = 0; 22156 const float angle = (float)((invert?+1:-1)*2*cimg::PI/delta), 22157 ca = (float)std::cos(angle), sa = (float)std::sin(angle); 22158 for (unsigned int k = 0; k<delta2; ++k) { 22159 const unsigned int j = i + k, nj = j + delta2; 22160 cimg_forXYC(real,x,y,c) { 22161 T &ir = real(x,y,j,c), &ii = imag(x,y,j,c), &nir = real(x,y,nj,c), &nii = imag(x,y,nj,c); 22162 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir); 22163 nir = (T)(ir - tmpr); 22164 nii = (T)(ii - tmpi); 22165 ir+=(T)tmpr; 22166 ii+=(T)tmpi; 22167 } 22168 const float nwr = wr*ca-wi*sa; 22169 wi = wi*ca + wr*sa; 22170 wr = nwr; 22171 } 22172 } 22173 } 22174 if (invert) { real/=N; imag/=N; } 22175 } break; 22176 default : 22177 throw CImgArgumentException("CImgList<%s>::FFT() : Invalid specified axis '%c' for real and imaginary parts (%u,%u,%u,%u) " 22178 "(should be { x | y | z }).", 22179 pixel_type(),axis, 22180 real._width,real._height,real._depth,real._spectrum); 22181 } 22182 #endif 22183 } 22184 22185 //! Compute a n-d Fast Fourier Transform. 22186 static void FFT(CImg<T>& real, CImg<T>& imag, const bool invert=false) { 22187 if (!real) 22188 throw CImgInstanceException("CImgList<%s>::FFT() : Empty specified real part.", 22189 pixel_type()); 22190 22191 if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,0); 22192 if (!real.is_sameXYZC(imag)) 22193 throw CImgInstanceException("CImgList<%s>::FFT() : Specified real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p) have different dimensions.", 22194 pixel_type(), 22195 real._width,real._height,real._depth,real._spectrum,real._data, 22196 imag._width,imag._height,imag._depth,imag._spectrum,imag._data); 22197 22198 #ifdef cimg_use_fftw3 22199 fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth); 22200 fftw_plan data_plan; 22201 const unsigned int w = real._width, wh = w*real._height, whd = wh*real._depth; 22202 data_plan = fftw_plan_dft_3d(real._width,real._height,real._depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); 22203 cimg_forC(real,c) { 22204 T *ptrr = real.data(0,0,0,c), *ptri = imag.data(0,0,0,c); 22205 double *ptrd = (double*)data_in; 22206 for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh-1, ptri-=wh-1) 22207 for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w) 22208 for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) { 22209 *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; 22210 } 22211 fftw_execute(data_plan); 22212 ptrd = (double*)data_in; 22213 ptrr = real.data(0,0,0,c); 22214 ptri = imag.data(0,0,0,c); 22215 if (!invert) for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh-1, ptri-=wh-1) 22216 for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w) 22217 for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) { 22218 *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++); 22219 } 22220 else for (unsigned int x = 0; x<real._width; ++x, ptrr-=wh-1, ptri-=wh-1) 22221 for (unsigned int y = 0; y<real._height; ++y, ptrr-=whd-w, ptri-=whd-w) 22222 for (unsigned int z = 0; z<real._depth; ++z, ptrr+=wh, ptri+=wh) { 22223 *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd); 22224 } 22225 } 22226 fftw_destroy_plan(data_plan); 22227 fftw_free(data_in); 22228 #else 22229 if (real._depth>1) FFT(real,imag,'z',invert); 22230 if (real._height>1) FFT(real,imag,'y',invert); 22231 if (real._width>1) FFT(real,imag,'x',invert); 22232 #endif 22233 } 22234 22235 //@} 22236 //------------------------------------- 22237 // 22238 //! \name 3d Objects Management 22239 //@{ 22240 //------------------------------------- 22241 22242 //! Shift a 3d object. 22243 CImg<T>& shift_object3d(const float tx, const float ty=0, const float tz=0) { 22244 if (_height!=3 || _depth>1 || _spectrum>1) 22245 throw CImgInstanceException(_cimg_instance 22246 "shift_object3d() : Instance is not a set of 3d vertices.", 22247 cimg_instance); 22248 22249 get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz; 22250 return *this; 22251 } 22252 22253 CImg<Tfloat> get_shift_object3d(const float tx, const float ty=0, const float tz=0) const { 22254 return CImg<Tfloat>(*this,false).shift_object3d(tx,ty,tz); 22255 } 22256 22257 //! Shift a 3d object so that it becomes centered. 22258 CImg<T>& shift_object3d() { 22259 if (_height!=3 || _depth>1 || _spectrum>1) 22260 throw CImgInstanceException(_cimg_instance 22261 "shift_object3d() : Instance is not a set of 3d vertices.", 22262 cimg_instance); 22263 22264 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2); 22265 float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); 22266 xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2; 22267 return *this; 22268 } 22269 22270 CImg<Tfloat> get_shift_object3d() const { 22271 return CImg<Tfloat>(*this,false).shift_object3d(); 22272 } 22273 22274 //! Resize a 3d object. 22275 CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) { 22276 if (_height!=3 || _depth>1 || _spectrum>1) 22277 throw CImgInstanceException(_cimg_instance 22278 "resize_object3d() : Instance is not a set of 3d vertices.", 22279 cimg_instance); 22280 22281 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2); 22282 float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); 22283 if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; } 22284 if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; } 22285 if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; } 22286 return *this; 22287 } 22288 22289 CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const { 22290 return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz); 22291 } 22292 22293 //! Resize a 3d object so that its max dimension if one. 22294 CImg<T> resize_object3d() const { 22295 if (_height!=3 || _depth>1 || _spectrum>1) 22296 throw CImgInstanceException(_cimg_instance 22297 "resize_object3d() : Instance is not a set of 3d vertices.", 22298 cimg_instance); 22299 22300 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2); 22301 float xm, xM = (float)xcoords.max_min(xm), ym, yM = (float)ycoords.max_min(ym), zm, zM = (float)zcoords.max_min(zm); 22302 const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz); 22303 if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; } 22304 return *this; 22305 } 22306 22307 CImg<Tfloat> get_resize_object3d() const { 22308 return CImg<Tfloat>(*this,false).resize_object3d(); 22309 } 22310 22311 //! Append a 3d object to another one. 22312 template<typename tf, typename tp, typename tff> 22313 CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_vertices, const CImgList<tff>& obj_primitives) { 22314 if (!obj_vertices || !obj_primitives) return *this; 22315 if (obj_vertices._height!=3 || obj_vertices._depth>1 || obj_vertices._spectrum>1) 22316 throw CImgInstanceException(_cimg_instance 22317 "append_object3d() : Specified vertice image (%u,%u,%u,%u,%p) is not a set of 3d vertices.", 22318 cimg_instance, 22319 obj_vertices._width,obj_vertices._height,obj_vertices._depth,obj_vertices._spectrum,obj_vertices._data); 22320 22321 if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); } 22322 if (_height!=3 || _depth>1 || _spectrum>1) 22323 throw CImgInstanceException(_cimg_instance 22324 "append_object3d() : Instance is not a set of 3d vertices.", 22325 cimg_instance); 22326 22327 const unsigned int P = _width; 22328 append(obj_vertices,'x'); 22329 const unsigned int N = primitives._width; 22330 primitives.insert(obj_primitives); 22331 for (unsigned int i = N; i<primitives._width; ++i) { 22332 CImg<tf> &p = primitives[i]; 22333 switch (p.size()) { 22334 case 1 : p[0]+=P; break; // Point. 22335 case 5 : p[0]+=P; p[1]+=P; break; // Sphere. 22336 case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment. 22337 case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle. 22338 case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle. 22339 } 22340 } 22341 return *this; 22342 } 22343 22344 //! Create and return a 3d elevation of the instance image. 22345 /** 22346 \param[out] primitives The returned list of the 3d object primitives 22347 (template type \e tf should be at least \e unsigned \e int). 22348 \param[out] colors The returned list of the 3d object colors. 22349 \param elevation The input elevation map. 22350 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 22351 \par Sample code : 22352 \code 22353 const CImg<float> img("reference.jpg"); 22354 CImgList<unsigned int> faces3d; 22355 CImgList<unsigned char> colors3d; 22356 const CImg<float> points3d = img.get_elevation3d(faces3d,colors,img.get_norm()*0.2); 22357 CImg<unsigned char>().display_object3d(points3d,faces3d,colors3d); 22358 \endcode 22359 \image html ref_elevation3d.jpg 22360 **/ 22361 template<typename tf, typename tc, typename te> 22362 CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const { 22363 if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1) 22364 throw CImgArgumentException(_cimg_instance 22365 "get_elevation3d() : Instance and specified elevation (%u,%u,%u,%u,%p) " 22366 "have incompatible dimensions.", 22367 cimg_instance, 22368 elevation._width,elevation._height,elevation._depth,elevation._spectrum,elevation._data); 22369 22370 if (is_empty()) return *this; 22371 float m, M = (float)max_min(m); 22372 if (M==m) ++M; 22373 colors.assign(); 22374 const unsigned int size_x1 = _width - 1, size_y1 = _height - 1; 22375 for (unsigned int y = 0; y<size_y1; ++y) 22376 for (unsigned int x = 0; x<size_x1; x++) { 22377 const unsigned char 22378 r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)), 22379 g = _spectrum>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r, 22380 b = _spectrum>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(_spectrum>1?0:r); 22381 CImg<tc>::vector((tc)r,(tc)g,(tc)b).move_to(colors); 22382 } 22383 const typename CImg<te>::_functor2d_int func(elevation); 22384 return elevation3d(primitives,func,0,0,_width-1.0f,_height-1.0f,_width,_height); 22385 } 22386 22387 //! Create and return a isoline of the instance image as a 3d object. 22388 /** 22389 \param[out] primitives The returned list of the 3d object primitives 22390 (template type \e tf should be at least \e unsigned \e int). 22391 \param isovalue The returned list of the 3d object colors. 22392 \param size_x The number of subdivisions along the X-axis. 22393 \param size_y The number of subdisivions along the Y-axis. 22394 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 22395 \par Sample code : 22396 \code 22397 const CImg<float> img("reference.jpg"); 22398 CImgList<unsigned int> faces3d; 22399 const CImg<float> points3d = img.get_isoline3d(faces3d,100); 22400 CImg<unsigned char>().display_object3d(points3d,faces3d,colors3d); 22401 \endcode 22402 \image html ref_isoline3d.jpg 22403 **/ 22404 template<typename tf> 22405 CImg<floatT> get_isoline3d(CImgList<tf>& primitives, const float isovalue, 22406 const int size_x=-100, const int size_y=-100) const { 22407 if (_spectrum>1) 22408 throw CImgInstanceException(_cimg_instance 22409 "get_isoline3d() : Instance is not a scalar image.", 22410 cimg_instance); 22411 primitives.assign(); 22412 if (is_empty()) return *this; 22413 CImg<floatT> vertices; 22414 if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) { 22415 const _functor2d_int func(*this); 22416 vertices = isoline3d(primitives,func,isovalue,0,0,width()-1.0f,height()-1.0f,size_x,size_y); 22417 } else { 22418 const _functor2d_float func(*this); 22419 vertices = isoline3d(primitives,func,isovalue,0,0,width()-1.0f,height()-1.0f,size_x,size_y); 22420 } 22421 return vertices; 22422 } 22423 22424 //! Create and return a isosurface of the instance image as a 3d object. 22425 /** 22426 \param[out] primitives The returned list of the 3d object primitives 22427 (template type \e tf should be at least \e unsigned \e int). 22428 \param isovalue The returned list of the 3d object colors. 22429 \param size_x The number of subdivisions along the X-axis. 22430 \param size_y The number of subdisivions along the Y-axis. 22431 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 22432 \par Sample code : 22433 \code 22434 const CImg<float> img = CImg<unsigned char>("reference.jpg").resize(-100,-100,20); 22435 CImgList<unsigned int> faces3d; 22436 const CImg<float> points3d = img.get_isosurface3d(faces3d,100); 22437 CImg<unsigned char>().display_object3d(points3d,faces3d,colors3d); 22438 \endcode 22439 \image html ref_isosurface3d.jpg 22440 **/ 22441 template<typename tf> 22442 CImg<floatT> get_isosurface3d(CImgList<tf>& primitives, const float isovalue, 22443 const int size_x=-100, const int size_y=-100, const int size_z=-100) const { 22444 if (_spectrum>1) 22445 throw CImgInstanceException(_cimg_instance 22446 "get_isosurface3d() : Instance is not a scalar image.", 22447 cimg_instance); 22448 primitives.assign(); 22449 if (is_empty()) return *this; 22450 CImg<floatT> vertices; 22451 if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) { 22452 const _functor3d_int func(*this); 22453 vertices = isosurface3d(primitives,func,isovalue,0,0,0,width()-1.0f,height()-1.0f,depth()-1.0f,size_x,size_y,size_z); 22454 } else { 22455 const _functor3d_float func(*this); 22456 vertices = isosurface3d(primitives,func,isovalue,0,0,0,width()-1.0f,height()-1.0f,depth()-1.0f,size_x,size_y,size_z); 22457 } 22458 return vertices; 22459 } 22460 22461 //! Get elevation3d of a function. 22462 template<typename tf, typename tfunc> 22463 static CImg<floatT> elevation3d(CImgList<tf>& primitives, const tfunc& func, 22464 const float x0, const float y0, const float x1, const float y1, 22465 const int size_x=256, const int size_y=256) { 22466 const float 22467 nx0 = x0<x1?x0:x1, ny0 = y0<y1?y0:y1, 22468 nx1 = x0<x1?x1:x0, ny1 = y0<y1?y1:y0; 22469 const unsigned int 22470 _nsize_x = (unsigned int)(size_x>=0?size_x:(nx1-nx0)*-size_x/100), nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1, 22471 _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100), nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1; 22472 if (nsize_x<2 || nsize_y<2) 22473 throw CImgArgumentException("CImg<%s>::elevation3d() : Invalid specified size (%d,%d).", 22474 pixel_type(), 22475 nsize_x,nsize_y); 22476 22477 CImg<floatT> vertices(nsize_x*nsize_y,3); 22478 floatT *ptr_x = vertices.data(0,0), *ptr_y = vertices.data(0,1), *ptr_z = vertices.data(0,2); 22479 for (unsigned int y = 0; y<nsize_y; ++y) { 22480 const float Y = ny0 + y*(ny1-ny0)/nsize_y1; 22481 for (unsigned int x = 0; x<nsize_x; ++x) { 22482 const float X = nx0 + x*(nx1-nx0)/nsize_x1; 22483 *(ptr_x++) = (float)x; 22484 *(ptr_y++) = (float)y; 22485 *(ptr_z++) = (float)func(X,Y); 22486 } 22487 } 22488 primitives.assign(nsize_x1*nsize_y1,1,4); 22489 for (unsigned int p = 0, y = 0; y<nsize_y1; ++y) { 22490 const unsigned int yw = y*nsize_x; 22491 for (unsigned int x = 0; x<nsize_x1; ++x) { 22492 const unsigned int xpyw = x + yw, xpyww = xpyw + nsize_x; 22493 primitives[p++].fill(xpyw,xpyww,xpyww+1,xpyw+1); 22494 } 22495 } 22496 return vertices; 22497 } 22498 22499 template<typename tf> 22500 static CImg<floatT> elevation3d(CImgList<tf>& primitives, const char *const expression, 22501 const float x0, const float y0, const float x1, const float y1, 22502 const int sizex=256, const int sizey=256) { 22503 const _functor2d_expr func(expression); 22504 return elevation3d(primitives,func,x0,y0,x1,y1,sizex,sizey); 22505 } 22506 22507 //! Get isoline as a 3d object. 22508 template<typename tf, typename tfunc> 22509 static CImg<floatT> isoline3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue, 22510 const float x0, const float y0, const float x1, const float y1, 22511 const int sizex=256, const int sizey=256) { 22512 static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 }; 22513 static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 }, 22514 { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 }, 22515 { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 }, 22516 { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } }; 22517 const unsigned int 22518 _nx = (unsigned int)(sizex>=0?sizex:((x1-x0)*-sizex/100 + 1)), 22519 _ny = (unsigned int)(sizey>=0?sizey:((y1-y0)*-sizey/100 + 1)), 22520 nx = _nx?_nx:1, 22521 ny = _ny?_ny:1, 22522 nxm1 = nx - 1, 22523 nym1 = ny - 1; 22524 primitives.assign(); 22525 if (!nxm1 || !nym1) return CImg<floatT>(); 22526 const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1; 22527 CImgList<floatT> vertices; 22528 CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2); 22529 CImg<floatT> values1(nx), values2(nx); 22530 float X = x0, Y = y0, nX = X + dx, nY = Y + dy; 22531 22532 // Fill first line with values 22533 cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; } 22534 22535 // Run the marching squares algorithm 22536 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=dy) { 22537 X = x0; nX = X + dx; 22538 indices2.fill(-1); 22539 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=dx) { 22540 22541 // Determine square configuration 22542 const float 22543 val0 = values1(xi), 22544 val1 = values1(nxi), 22545 val2 = values2(nxi) = (float)func(nX,nY), 22546 val3 = values2(xi) = (float)func(X,nY); 22547 const unsigned int 22548 configuration = (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0), 22549 edge = edges[configuration]; 22550 22551 // Compute intersection vertices 22552 if (edge) { 22553 if ((edge&1) && indices1(xi,0)<0) { 22554 const float Xi = X + (isovalue-val0)*dx/(val1-val0); 22555 indices1(xi,0) = vertices._width; 22556 CImg<floatT>::vector(Xi,Y,0).move_to(vertices); 22557 } 22558 if ((edge&2) && indices1(nxi,1)<0) { 22559 const float Yi = Y + (isovalue-val1)*dy/(val2-val1); 22560 indices1(nxi,1) = vertices._width; 22561 CImg<floatT>::vector(nX,Yi,0).move_to(vertices); 22562 } 22563 if ((edge&4) && indices2(xi,0)<0) { 22564 const float Xi = X + (isovalue-val3)*dx/(val2-val3); 22565 indices2(xi,0) = vertices._width; 22566 CImg<floatT>::vector(Xi,nY,0).move_to(vertices); 22567 } 22568 if ((edge&8) && indices1(xi,1)<0) { 22569 const float Yi = Y + (isovalue-val0)*dy/(val3-val0); 22570 indices1(xi,1) = vertices._width; 22571 CImg<floatT>::vector(X,Yi,0).move_to(vertices); 22572 } 22573 22574 // Create segments 22575 for (const int *segment = segments[configuration]; *segment!=-1; ) { 22576 const unsigned int p0 = *(segment++), p1 = *(segment++); 22577 const tf 22578 i0 = (tf)(_isoline3d_indice(p0,indices1,indices2,xi,nxi)), 22579 i1 = (tf)(_isoline3d_indice(p1,indices1,indices2,xi,nxi)); 22580 CImg<tf>::vector(i0,i1).move_to(primitives); 22581 } 22582 } 22583 } 22584 values1.swap(values2); 22585 indices1.swap(indices2); 22586 } 22587 return vertices>'x'; 22588 } 22589 22590 template<typename tf> 22591 static CImg<floatT> isoline3d(CImgList<tf>& primitives, const char *const expression, const float isovalue, 22592 const float x0, const float y0, const float x1, const float y1, 22593 const int sizex=256, const int sizey=256) { 22594 const _functor2d_expr func(expression); 22595 return isoline3d(primitives,func,isovalue,x0,y0,x1,y1,sizex,sizey); 22596 } 22597 22598 template<typename t> 22599 static int _isoline3d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2, 22600 const unsigned int x, const unsigned int nx) { 22601 switch (edge) { 22602 case 0 : return (int)indices1(x,0); 22603 case 1 : return (int)indices1(nx,1); 22604 case 2 : return (int)indices2(x,0); 22605 case 3 : return (int)indices1(x,1); 22606 } 22607 return 0; 22608 } 22609 22610 //! Get isosurface as a 3d object. 22611 template<typename tf, typename tfunc> 22612 static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue, 22613 const float x0, const float y0, const float z0, 22614 const float x1, const float y1, const float z1, 22615 const int size_x=32, const int size_y=32, const int size_z=32) { 22616 static unsigned int edges[256] = { 22617 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 22618 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 22619 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 22620 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 22621 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 22622 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 22623 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 22624 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 22625 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 22626 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 22627 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 22628 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 22629 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 22630 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 22631 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 22632 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 }; 22633 22634 static int triangles[256][16] = { 22635 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22636 { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22637 { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22638 { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, 22639 { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22640 { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, 22641 { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, 22642 { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22643 { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22644 { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, 22645 { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, 22646 { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, 22647 { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, 22648 { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, 22649 { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, 22650 { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, 22651 { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22652 { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, 22653 { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, 22654 { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, 22655 { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, 22656 { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, 22657 { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, 22658 { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, 22659 { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, 22660 { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22661 { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, 22662 { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, 22663 { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, 22664 { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, 22665 { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, 22666 { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22667 { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22668 { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, 22669 { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, 22670 { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, 22671 { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, 22672 { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, 22673 { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, 22674 { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, 22675 { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, 22676 { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, 22677 { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, 22678 { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, 22679 { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, 22680 { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, 22681 { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, 22682 { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, 22683 { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, 22684 { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, 22685 { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, 22686 { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, 22687 { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, 22688 { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, 22689 { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, 22690 { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22691 { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, 22692 { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, 22693 { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, 22694 { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22695 { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, 22696 { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, 22697 { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22698 { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22699 { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22700 { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, 22701 { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, 22702 { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, 22703 { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, 22704 { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, 22705 { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, 22706 { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, 22707 { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, 22708 { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, 22709 { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, 22710 { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, 22711 { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22712 { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, 22713 { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, 22714 { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22715 { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, 22716 { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, 22717 { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, 22718 { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, 22719 { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, 22720 { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, 22721 { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, 22722 { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, 22723 { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, 22724 { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, 22725 { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, 22726 { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, 22727 { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, 22728 { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22729 { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, 22730 { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22731 { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, 22732 { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, 22733 { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, 22734 { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, 22735 { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, 22736 { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, 22737 { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, 22738 { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22739 { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, 22740 { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, 22741 { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, 22742 { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22743 { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, 22744 { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, 22745 { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22746 { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22747 { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, 22748 { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, 22749 { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, 22750 { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, 22751 { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, 22752 { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22753 { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, 22754 { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22755 { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, 22756 { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22757 { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, 22758 { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22759 { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22760 { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22761 { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22762 { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } 22763 }; 22764 22765 const unsigned int 22766 _nx = (unsigned int)(size_x>=0?size_x:((x1-x0)*-size_x/100 + 1)), 22767 _ny = (unsigned int)(size_y>=0?size_y:((y1-y0)*-size_y/100 + 1)), 22768 _nz = (unsigned int)(size_z>=0?size_y:((z1-z0)*-size_z/100 + 1)), 22769 nx = _nx?_nx:1, 22770 ny = _ny?_ny:1, 22771 nz = _nz?_nz:1, 22772 nxm1 = nx - 1, 22773 nym1 = ny - 1, 22774 nzm1 = nz - 1; 22775 primitives.assign(); 22776 if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>(); 22777 const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1, dz = (z1 - z0)/nzm1; 22778 CImgList<floatT> vertices; 22779 CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1); 22780 CImg<floatT> values1(nx,ny), values2(nx,ny); 22781 float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0; 22782 22783 // Fill the first plane with function values 22784 Y = y0; 22785 cimg_forY(values1,y) { 22786 X = x0; 22787 cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=dx; } 22788 Y+=dy; 22789 } 22790 22791 // Run Marching Cubes algorithm 22792 Z = z0; nZ = Z + dz; 22793 for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=dz) { 22794 Y = y0; nY = Y + dy; 22795 indices2.fill(-1); 22796 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=dy) { 22797 X = x0; nX = X + dx; 22798 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=dx) { 22799 22800 // Determine cube configuration 22801 const float 22802 val0 = values1(xi,yi), 22803 val1 = values1(nxi,yi), 22804 val2 = values1(nxi,nyi), 22805 val3 = values1(xi,nyi), 22806 val4 = values2(xi,yi) = (float)func(X,Y,nZ), 22807 val5 = values2(nxi,yi) = (float)func(nX,Y,nZ), 22808 val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ), 22809 val7 = values2(xi,nyi) = (float)func(X,nY,nZ); 22810 22811 const unsigned int configuration = 22812 (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0) | 22813 (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0), 22814 edge = edges[configuration]; 22815 22816 // Compute intersection vertices 22817 if (edge) { 22818 if ((edge&1) && indices1(xi,yi,0)<0) { 22819 const float Xi = X + (isovalue-val0)*dx/(val1-val0); 22820 indices1(xi,yi,0) = vertices._width; 22821 CImg<floatT>::vector(Xi,Y,Z).move_to(vertices); 22822 } 22823 if ((edge&2) && indices1(nxi,yi,1)<0) { 22824 const float Yi = Y + (isovalue-val1)*dy/(val2-val1); 22825 indices1(nxi,yi,1) = vertices._width; 22826 CImg<floatT>::vector(nX,Yi,Z).move_to(vertices); 22827 } 22828 if ((edge&4) && indices1(xi,nyi,0)<0) { 22829 const float Xi = X + (isovalue-val3)*dx/(val2-val3); 22830 indices1(xi,nyi,0) = vertices._width; 22831 CImg<floatT>::vector(Xi,nY,Z).move_to(vertices); 22832 } 22833 if ((edge&8) && indices1(xi,yi,1)<0) { 22834 const float Yi = Y + (isovalue-val0)*dy/(val3-val0); 22835 indices1(xi,yi,1) = vertices._width; 22836 CImg<floatT>::vector(X,Yi,Z).move_to(vertices); 22837 } 22838 if ((edge&16) && indices2(xi,yi,0)<0) { 22839 const float Xi = X + (isovalue-val4)*dx/(val5-val4); 22840 indices2(xi,yi,0) = vertices._width; 22841 CImg<floatT>::vector(Xi,Y,nZ).move_to(vertices); 22842 } 22843 if ((edge&32) && indices2(nxi,yi,1)<0) { 22844 const float Yi = Y + (isovalue-val5)*dy/(val6-val5); 22845 indices2(nxi,yi,1) = vertices._width; 22846 CImg<floatT>::vector(nX,Yi,nZ).move_to(vertices); 22847 } 22848 if ((edge&64) && indices2(xi,nyi,0)<0) { 22849 const float Xi = X + (isovalue-val7)*dx/(val6-val7); 22850 indices2(xi,nyi,0) = vertices._width; 22851 CImg<floatT>::vector(Xi,nY,nZ).move_to(vertices); 22852 } 22853 if ((edge&128) && indices2(xi,yi,1)<0) { 22854 const float Yi = Y + (isovalue-val4)*dy/(val7-val4); 22855 indices2(xi,yi,1) = vertices._width; 22856 CImg<floatT>::vector(X,Yi,nZ).move_to(vertices); 22857 } 22858 if ((edge&256) && indices1(xi,yi,2)<0) { 22859 const float Zi = Z+ (isovalue-val0)*dz/(val4-val0); 22860 indices1(xi,yi,2) = vertices._width; 22861 CImg<floatT>::vector(X,Y,Zi).move_to(vertices); 22862 } 22863 if ((edge&512) && indices1(nxi,yi,2)<0) { 22864 const float Zi = Z + (isovalue-val1)*dz/(val5-val1); 22865 indices1(nxi,yi,2) = vertices._width; 22866 CImg<floatT>::vector(nX,Y,Zi).move_to(vertices); 22867 } 22868 if ((edge&1024) && indices1(nxi,nyi,2)<0) { 22869 const float Zi = Z + (isovalue-val2)*dz/(val6-val2); 22870 indices1(nxi,nyi,2) = vertices._width; 22871 CImg<floatT>::vector(nX,nY,Zi).move_to(vertices); 22872 } 22873 if ((edge&2048) && indices1(xi,nyi,2)<0) { 22874 const float Zi = Z + (isovalue-val3)*dz/(val7-val3); 22875 indices1(xi,nyi,2) = vertices._width; 22876 CImg<floatT>::vector(X,nY,Zi).move_to(vertices); 22877 } 22878 22879 // Create triangles 22880 for (const int *triangle = triangles[configuration]; *triangle!=-1; ) { 22881 const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++); 22882 const tf 22883 i0 = (tf)(_isosurface3d_indice(p0,indices1,indices2,xi,yi,nxi,nyi)), 22884 i1 = (tf)(_isosurface3d_indice(p1,indices1,indices2,xi,yi,nxi,nyi)), 22885 i2 = (tf)(_isosurface3d_indice(p2,indices1,indices2,xi,yi,nxi,nyi)); 22886 CImg<tf>::vector(i0,i2,i1).move_to(primitives); 22887 } 22888 } 22889 } 22890 } 22891 cimg::swap(values1,values2); 22892 cimg::swap(indices1,indices2); 22893 } 22894 return vertices>'x'; 22895 } 22896 22897 template<typename tf> 22898 static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const char *const expression, const float isovalue, 22899 const float x0, const float y0, const float z0, 22900 const float x1, const float y1, const float z1, 22901 const int dx=32, const int dy=32, const int dz=32) { 22902 const _functor3d_expr func(expression); 22903 return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz); 22904 } 22905 22906 template<typename t> 22907 static int _isosurface3d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2, 22908 const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) { 22909 switch (edge) { 22910 case 0 : return indices1(x,y,0); 22911 case 1 : return indices1(nx,y,1); 22912 case 2 : return indices1(x,ny,0); 22913 case 3 : return indices1(x,y,1); 22914 case 4 : return indices2(x,y,0); 22915 case 5 : return indices2(nx,y,1); 22916 case 6 : return indices2(x,ny,0); 22917 case 7 : return indices2(x,y,1); 22918 case 8 : return indices1(x,y,2); 22919 case 9 : return indices1(nx,y,2); 22920 case 10 : return indices1(nx,ny,2); 22921 case 11 : return indices1(x,ny,2); 22922 } 22923 return 0; 22924 } 22925 22926 // Define functors for accessing image values (used in previous functions). 22927 struct _functor2d_int { 22928 const CImg<T>& ref; 22929 _functor2d_int(const CImg<T>& pref):ref(pref) {} 22930 float operator()(const float x, const float y) const { 22931 return (float)ref((int)x,(int)y); 22932 } 22933 }; 22934 22935 struct _functor2d_float { 22936 const CImg<T>& ref; 22937 _functor2d_float(const CImg<T>& pref):ref(pref) {} 22938 float operator()(const float x, const float y) const { 22939 return (float)ref._linear_atXY(x,y); 22940 } 22941 }; 22942 22943 struct _functor2d_expr { 22944 _cimg_math_parser *mp; 22945 _functor2d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } 22946 ~_functor2d_expr() { if (mp) delete mp; } 22947 float operator()(const float x, const float y) const { 22948 return (float)mp->eval(x,y,0,0); 22949 } 22950 }; 22951 22952 struct _functor3d_int { 22953 const CImg<T>& ref; 22954 _functor3d_int(const CImg<T>& pref):ref(pref) {} 22955 float operator()(const float x, const float y, const float z) const { 22956 return (float)ref((int)x,(int)y,(int)z); 22957 } 22958 }; 22959 22960 struct _functor3d_float { 22961 const CImg<T>& ref; 22962 _functor3d_float(const CImg<T>& pref):ref(pref) {} 22963 float operator()(const float x, const float y, const float z) const { 22964 return (float)ref._linear_atXYZ(x,y,z); 22965 } 22966 }; 22967 22968 struct _functor3d_expr { 22969 _cimg_math_parser *mp; 22970 ~_functor3d_expr() { if (mp) delete mp; } 22971 _functor3d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } 22972 float operator()(const float x, const float y, const float z) const { 22973 return (float)mp->eval(x,y,z,0); 22974 } 22975 }; 22976 22977 struct _functor4d_int { 22978 const CImg<T>& ref; 22979 _functor4d_int(const CImg<T>& pref):ref(pref) {} 22980 float operator()(const float x, const float y, const float z, const unsigned int c) const { 22981 return (float)ref((int)x,(int)y,(int)z,c); 22982 } 22983 }; 22984 22985 //! Create and return a 3d box object. 22986 /** 22987 \param[out] primitives The returned list of the 3d object primitives 22988 (template type \e tf should be at least \e unsigned \e int). 22989 \param size_x The width of the box (dimension along the X-axis). 22990 \param size_y The height of the box (dimension along the Y-axis). 22991 \param size_z The depth of the box (dimension along the Z-axis). 22992 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 22993 \par Sample code : 22994 \code 22995 CImgList<unsigned int> faces3d; 22996 const CImg<float> points3d = CImg<float>::box3d(faces3d,10,20,30); 22997 CImg<unsigned char>().display_object3d(points3d,faces3d); 22998 \endcode 22999 \image html ref_box3d.jpg 23000 **/ 23001 template<typename tf> 23002 static CImg<floatT> box3d(CImgList<tf>& primitives, 23003 const float size_x=200, const float size_y=100, const float size_z=100) { 23004 primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5); 23005 return CImg<floatT>(8,3,1,1, 23006 0.,size_x,size_x, 0., 0.,size_x,size_x, 0., 23007 0., 0.,size_y,size_y, 0., 0.,size_y,size_y, 23008 0., 0., 0., 0.,size_z,size_z,size_z,size_z); 23009 } 23010 23011 //! Create and return a 3d cone. 23012 /** 23013 \param[out] primitives The returned list of the 3d object primitives 23014 (template type \e tf should be at least \e unsigned \e int). 23015 \param radius The radius of the cone basis. 23016 \param size_z The cone's height. 23017 \param subdivisions The number of basis angular subdivisions. 23018 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23019 \par Sample code : 23020 \code 23021 CImgList<unsigned int> faces3d; 23022 const CImg<float> points3d = CImg<float>::cone3d(faces3d,50); 23023 CImg<unsigned char>().display_object3d(points3d,faces3d); 23024 \endcode 23025 \image html ref_cone3d.jpg 23026 **/ 23027 template<typename tf> 23028 static CImg<floatT> cone3d(CImgList<tf>& primitives, 23029 const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { 23030 primitives.assign(); 23031 if (!subdivisions) return CImg<floatT>(); 23032 CImgList<floatT> vertices(2,1,3,1,1, 23033 0.,0.,size_z, 23034 0.,0.,0.); 23035 for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) { 23036 const float a = (float)(angle*cimg::PI/180); 23037 CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0).move_to(vertices); 23038 } 23039 const unsigned int nbr = vertices._width - 2; 23040 for (unsigned int p = 0; p<nbr; ++p) { 23041 const unsigned int curr = 2 + p, next = 2 + ((p+1)%nbr); 23042 CImg<tf>::vector(1,next,curr).move_to(primitives); 23043 CImg<tf>::vector(0,curr,next).move_to(primitives); 23044 } 23045 return vertices>'x'; 23046 } 23047 23048 //! Create and return a 3d cylinder. 23049 /** 23050 \param[out] primitives The returned list of the 3d object primitives 23051 (template type \e tf should be at least \e unsigned \e int). 23052 \param radius The radius of the cylinder basis. 23053 \param size_z The cylinder's height. 23054 \param subdivisions The number of basis angular subdivisions. 23055 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23056 \par Sample code : 23057 \code 23058 CImgList<unsigned int> faces3d; 23059 const CImg<float> points3d = CImg<float>::cylinder3d(faces3d,50); 23060 CImg<unsigned char>().display_object3d(points3d,faces3d); 23061 \endcode 23062 \image html ref_cylinder3d.jpg 23063 **/ 23064 template<typename tf> 23065 static CImg<floatT> cylinder3d(CImgList<tf>& primitives, 23066 const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { 23067 primitives.assign(); 23068 if (!subdivisions) return CImg<floatT>(); 23069 CImgList<floatT> vertices(2,1,3,1,1, 23070 0.,0.,0., 23071 0.,0.,size_z); 23072 for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) { 23073 const float a = (float)(angle*cimg::PI/180); 23074 CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.0f).move_to(vertices); 23075 CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices); 23076 } 23077 const unsigned int nbr = (vertices._width - 2)/2; 23078 for (unsigned int p = 0; p<nbr; ++p) { 23079 const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr)); 23080 CImg<tf>::vector(0,next,curr).move_to(primitives); 23081 CImg<tf>::vector(1,curr+1,next+1).move_to(primitives); 23082 CImg<tf>::vector(curr,next,next+1,curr+1).move_to(primitives); 23083 } 23084 return vertices>'x'; 23085 } 23086 23087 //! Create and return a 3d torus. 23088 /** 23089 \param[out] primitives The returned list of the 3d object primitives 23090 (template type \e tf should be at least \e unsigned \e int). 23091 \param radius1 The large radius. 23092 \param radius2 The small radius. 23093 \param subdivisions1 The number of angular subdivisions for the large radius. 23094 \param subdivisions2 The number of angular subdivisions for the small radius. 23095 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23096 \par Sample code : 23097 \code 23098 CImgList<unsigned int> faces3d; 23099 const CImg<float> points3d = CImg<float>::torus3d(faces3d,20,4); 23100 CImg<unsigned char>().display_object3d(points3d,faces3d); 23101 \endcode 23102 \image html ref_torus3d.jpg 23103 **/ 23104 template<typename tf> 23105 static CImg<floatT> torus3d(CImgList<tf>& primitives, 23106 const float radius1=100, const float radius2=30, 23107 const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) { 23108 primitives.assign(); 23109 if (!subdivisions1 || !subdivisions2) return CImg<floatT>(); 23110 CImgList<floatT> vertices; 23111 for (unsigned int v = 0; v<subdivisions1; ++v) { 23112 const float 23113 beta = (float)(v*2*cimg::PI/subdivisions1), 23114 xc = radius1*(float)std::cos(beta), 23115 yc = radius1*(float)std::sin(beta); 23116 for (unsigned int u = 0; u<subdivisions2; ++u) { 23117 const float 23118 alpha = (float)(u*2*cimg::PI/subdivisions2), 23119 x = xc + radius2*(float)(std::cos(alpha)*std::cos(beta)), 23120 y = yc + radius2*(float)(std::cos(alpha)*std::sin(beta)), 23121 z = radius2*(float)std::sin(alpha); 23122 CImg<floatT>::vector(x,y,z).move_to(vertices); 23123 } 23124 } 23125 for (unsigned int vv = 0; vv<subdivisions1; ++vv) { 23126 const unsigned int nv = (vv+1)%subdivisions1; 23127 for (unsigned int uu = 0; uu<subdivisions2; ++uu) { 23128 const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv; 23129 CImg<tf>::vector(svv+nu,svv+uu,snv+uu).move_to(primitives); 23130 CImg<tf>::vector(svv+nu,snv+uu,snv+nu).move_to(primitives); 23131 } 23132 } 23133 return vertices>'x'; 23134 } 23135 23136 //! Create and return a 3d XY-plane. 23137 /** 23138 \param[out] primitives The returned list of the 3d object primitives 23139 (template type \e tf should be at least \e unsigned \e int). 23140 \param size_x The width of the plane (dimension along the X-axis). 23141 \param size_y The height of the plane (dimensions along the Y-axis). 23142 \param subdivisions_x The number of planar subdivisions along the X-axis. 23143 \param subdivisions_y The number of planar subdivisions along the Y-axis. 23144 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23145 \par Sample code : 23146 \code 23147 CImgList<unsigned int> faces3d; 23148 const CImg<float> points3d = CImg<float>::plane3d(faces3d,100,50); 23149 CImg<unsigned char>().display_object3d(points3d,faces3d); 23150 \endcode 23151 \image html ref_plane3d.jpg 23152 **/ 23153 template<typename tf> 23154 static CImg<floatT> plane3d(CImgList<tf>& primitives, 23155 const float size_x=100, const float size_y=100, 23156 const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10) { 23157 primitives.assign(); 23158 if (!subdivisions_x || !subdivisions_y) return CImg<floatT>(); 23159 CImgList<floatT> vertices; 23160 const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1; 23161 const float fx = (float)size_x/w, fy = (float)size_y/h; 23162 for (unsigned int y = 0; y<h; ++y) for (unsigned int x = 0; x<w; ++x) 23163 CImg<floatT>::vector(fx*x,fy*y,0).move_to(vertices); 23164 for (unsigned int y = 0; y<subdivisions_y; ++y) for (unsigned int x = 0; x<subdivisions_x; ++x) { 23165 const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w; 23166 CImg<tf>::vector(off1,off4,off3,off2).move_to(primitives); 23167 } 23168 return vertices>'x'; 23169 } 23170 23171 //! Create and return a 3d sphere. 23172 /** 23173 \param[out] primitives The returned list of the 3d object primitives 23174 (template type \e tf should be at least \e unsigned \e int). 23175 \param radius The radius of the sphere (dimension along the X-axis). 23176 \param subdivisions The number of recursive subdivisions from an initial icosahedron. 23177 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23178 \par Sample code : 23179 \code 23180 CImgList<unsigned int> faces3d; 23181 const CImg<float> points3d = CImg<float>::sphere3d(faces3d,100,4); 23182 CImg<unsigned char>().display_object3d(points3d,faces3d); 23183 \endcode 23184 \image html ref_sphere3d.jpg 23185 **/ 23186 template<typename tf> 23187 static CImg<floatT> sphere3d(CImgList<tf>& primitives, 23188 const float radius=50, const unsigned int subdivisions=3) { 23189 23190 // Create initial icosahedron 23191 primitives.assign(); 23192 const double tmp = (1+std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1+tmp*tmp), b = tmp*a; 23193 CImgList<floatT> vertices(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b, 23194 -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a); 23195 primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6, 23196 8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3, 23197 5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2); 23198 // edge - length/2 23199 float he = (float)a; 23200 23201 // Recurse subdivisions 23202 for (unsigned int i = 0; i<subdivisions; ++i) { 23203 const unsigned int L = primitives._width; 23204 he/=2; 23205 const float he2 = he*he; 23206 for (unsigned int l = 0; l<L; ++l) { 23207 const unsigned int 23208 p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2); 23209 const float 23210 x0 = vertices(p0,0), y0 = vertices(p0,1), z0 = vertices(p0,2), 23211 x1 = vertices(p1,0), y1 = vertices(p1,1), z1 = vertices(p1,2), 23212 x2 = vertices(p2,0), y2 = vertices(p2,1), z2 = vertices(p2,2), 23213 tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0), 23214 tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1), 23215 tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2), 23216 nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0, 23217 nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1, 23218 nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2; 23219 int i0 = -1, i1 = -1, i2 = -1; 23220 cimglist_for(vertices,p) { 23221 const float x = (float)vertices(p,0), y = (float)vertices(p,1), z = (float)vertices(p,2); 23222 if (cimg::sqr(x-nx0) + cimg::sqr(y-ny0) + cimg::sqr(z-nz0)<he2) i0 = p; 23223 if (cimg::sqr(x-nx1) + cimg::sqr(y-ny1) + cimg::sqr(z-nz1)<he2) i1 = p; 23224 if (cimg::sqr(x-nx2) + cimg::sqr(y-ny2) + cimg::sqr(z-nz2)<he2) i2 = p; 23225 } 23226 if (i0<0) { CImg<floatT>::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices._width - 1; } 23227 if (i1<0) { CImg<floatT>::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices._width - 1; } 23228 if (i2<0) { CImg<floatT>::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices._width - 1; } 23229 primitives.remove(0); 23230 CImg<tf>::vector(p0,i0,i1).move_to(primitives); 23231 CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives); 23232 CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2).move_to(primitives); 23233 CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2).move_to(primitives); 23234 } 23235 } 23236 return (vertices>'x')*=radius; 23237 } 23238 23239 //! Create and return a 3d ellipsoid. 23240 /** 23241 \param[out] primitives The returned list of the 3d object primitives 23242 (template type \e tf should be at least \e unsigned \e int). 23243 \param tensor The tensor which gives the shape and size of the ellipsoid. 23244 \param subdivisions The number of recursive subdivisions from an initial stretched icosahedron. 23245 \return The N vertices (xi,yi,zi) of the 3d object as a Nx3 CImg<float> image (0<=i<=N-1). 23246 \par Sample code : 23247 \code 23248 CImgList<unsigned int> faces3d; 23249 const CImg<float> tensor = CImg<float>::diagonal(10,7,3), 23250 points3d = CImg<float>::ellipsoid3d(faces3d,tensor,4); 23251 CImg<unsigned char>().display_object3d(points3d,faces3d); 23252 \endcode 23253 \image html ref_ellipsoid3d.jpg 23254 **/ 23255 template<typename tf, typename t> 23256 static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, 23257 const CImg<t>& tensor, const unsigned int subdivisions=3) { 23258 primitives.assign(); 23259 if (!subdivisions) return CImg<floatT>(); 23260 CImg<floatT> S, V; 23261 tensor.symmetric_eigen(S,V); 23262 const float l0 = S[0], l1 = S[1], l2 = S[2]; 23263 CImg<floatT> vertices = sphere(primitives,subdivisions); 23264 vertices.get_shared_line(0)*=l0; 23265 vertices.get_shared_line(1)*=l1; 23266 vertices.get_shared_line(2)*=l2; 23267 return V.transpose()*vertices; 23268 } 23269 23270 //! Convert a 3d object into a CImg3d. 23271 template<typename tp, typename tc, typename to> 23272 CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives, 23273 const CImgList<tc>& colors, 23274 const to& opacities) { 23275 return get_object3dtoCImg3d(primitives,colors,opacities).move_to(*this); 23276 } 23277 23278 template<typename tp, typename tc> 23279 CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives, 23280 const CImgList<tc>& colors) { 23281 return get_object3dtoCImg3d(primitives,colors).move_to(*this); 23282 } 23283 23284 template<typename tp> 23285 CImg<T>& object3dtoCImg3d(const CImgList<tp>& primitives) { 23286 return get_object3dtoCImg3d(primitives).move_to(*this); 23287 } 23288 23289 CImg<T>& object3dtoCImg3d() { 23290 return get_object3dtoCImg3d().move_to(*this); 23291 } 23292 23293 template<typename tp, typename tc, typename to> 23294 CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives, 23295 const CImgList<tc>& colors, 23296 const to& opacities) const { 23297 char error_message[1024] = { 0 }; 23298 if (!is_object3d(primitives,colors,opacities,true,error_message)) 23299 throw CImgInstanceException(_cimg_instance 23300 "object3dtoCImg3d() : Invalid specified 3d object (%u,%u) (%s).", 23301 cimg_instance,_width,primitives._width,error_message); 23302 CImg<floatT> res(1,_size_object3dtoCImg3d(primitives,colors,opacities)); 23303 float *ptrd = res._data; 23304 23305 // Put magick number. 23306 *(ptrd++) = 'C' + 0.5f; *(ptrd++) = 'I' + 0.5f; *(ptrd++) = 'm' + 0.5f; 23307 *(ptrd++) = 'g' + 0.5f; *(ptrd++) = '3' + 0.5f; *(ptrd++) = 'd' + 0.5f; 23308 23309 // Put number of vertices and primitives. 23310 *(ptrd++) = (float)_width; 23311 *(ptrd++) = (float)primitives._width; 23312 23313 // Put vertex data. 23314 if (is_empty() || !primitives) return res; 23315 const T *ptrx = data(0,0), *ptry = data(0,1), *ptrz = data(0,2); 23316 cimg_forX(*this,p) { *(ptrd++) = (float)*(ptrx++); *(ptrd++) = (float)*(ptry++); *(ptrd++) = (float)*(ptrz++); } 23317 23318 // Put primitive data. 23319 cimglist_for(primitives,p) { 23320 *(ptrd++) = (float)primitives[p].size(); 23321 const tp *ptrp = primitives[p]._data; 23322 cimg_foroff(primitives[p],i) *(ptrd++) = (float)*(ptrp++); 23323 } 23324 23325 // Put color/texture data. 23326 const unsigned int csiz = cimg::min(colors._width,primitives._width); 23327 for (int c = 0; c<(int)csiz; ++c) { 23328 const CImg<tc>& color = colors[c]; 23329 const tc *ptrc = color._data; 23330 if (color.size()==3) { *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*ptrc; } 23331 else { 23332 *(ptrd++) = -128.0f; 23333 int shared_ind = -1; 23334 if (color.is_shared()) for (int i = 0; i<c; ++i) if (ptrc==colors[i]._data) { shared_ind = i; break; } 23335 if (shared_ind<0) { 23336 *(ptrd++) = (float)color._width; 23337 *(ptrd++) = (float)color._height; 23338 *(ptrd++) = (float)color._spectrum; 23339 cimg_foroff(color,l) *(ptrd++) = (float)*(ptrc++); 23340 } else { 23341 *(ptrd++) = (float)shared_ind; 23342 *(ptrd++) = 0; 23343 *(ptrd++) = 0; 23344 } 23345 } 23346 } 23347 const int csiz2 = primitives._width - colors._width; 23348 for (int c = 0; c<csiz2; ++c) { *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; *(ptrd++) = 200.0f; } 23349 23350 // Put opacity data. 23351 ptrd = _object3dtoCImg3d(opacities,ptrd); 23352 const unsigned int osiz = primitives._width - opacities._width; 23353 for (unsigned int o = 0; o<osiz; ++o) *(ptrd++) = 1.0f; 23354 return res; 23355 } 23356 23357 template<typename to> 23358 float* _object3dtoCImg3d(const CImgList<to>& opacities, float *ptrd) const { 23359 cimglist_for(opacities,o) { 23360 const CImg<to>& opacity = opacities[o]; 23361 const to *ptro = opacity._data; 23362 if (opacity.size()==1) *(ptrd++) = (float)*ptro; 23363 else { 23364 *(ptrd++) = -128.0f; 23365 int shared_ind = -1; 23366 if (opacity.is_shared()) for (int i = 0; i<o; ++i) if (ptro==opacities[i]._data) { shared_ind = i; break; } 23367 if (shared_ind<0) { 23368 *(ptrd++) = (float)opacity._width; 23369 *(ptrd++) = (float)opacity._height; 23370 *(ptrd++) = (float)opacity._spectrum; 23371 cimg_foroff(opacity,l) *(ptrd++) = (float)*(ptro++); 23372 } else { 23373 *(ptrd++) = (float)shared_ind; 23374 *(ptrd++) = 0; 23375 *(ptrd++) = 0; 23376 } 23377 } 23378 } 23379 return ptrd; 23380 } 23381 23382 template<typename to> 23383 float* _object3dtoCImg3d(const CImg<to>& opacities, float *ptrd) const { 23384 const to *ptro = opacities._data; 23385 cimg_foroff(opacities,o) *(ptrd++) = (float)*(ptro++); 23386 return ptrd; 23387 } 23388 23389 template<typename tp, typename tc, typename to> 23390 unsigned int _size_object3dtoCImg3d(const CImgList<tp>& primitives, 23391 const CImgList<tc>& colors, 23392 const CImgList<to>& opacities) const { 23393 unsigned int siz = 8 + 3*width(); 23394 cimglist_for(primitives,p) siz+=primitives[p].size() + 1; 23395 for (int c = cimg::min(primitives._width,colors._width)-1; c>=0; --c) { 23396 if (colors[c].is_shared()) siz+=4; 23397 else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4+csiz:3; } 23398 } 23399 if (colors._width<primitives._width) siz+=3*(primitives._width - colors._width); 23400 cimglist_for(opacities,o) { 23401 if (opacities[o].is_shared()) siz+=4; 23402 else { const unsigned int osiz = opacities[o].size(); siz+=(osiz!=1)?4+osiz:1; } 23403 } 23404 siz+=primitives._width - opacities._width; 23405 return siz; 23406 } 23407 23408 template<typename tp, typename tc, typename to> 23409 unsigned int _size_object3dtoCImg3d(const CImgList<tp>& primitives, 23410 const CImgList<tc>& colors, 23411 const CImg<to>& opacities) const { 23412 unsigned int siz = 8 + 3*width(); 23413 cimglist_for(primitives,p) siz+=primitives[p].size() + 1; 23414 for (int c = cimg::min(primitives._width,colors._width)-1; c>=0; --c) { 23415 const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4+csiz:3; 23416 } 23417 if (colors._width<primitives._width) siz+=3*(primitives._width - colors._width); 23418 siz+=opacities.size(); 23419 return siz; 23420 } 23421 23422 template<typename tp, typename tc> 23423 CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives, 23424 const CImgList<tc>& colors) const { 23425 CImgList<T> opacities; 23426 return get_object3dtoCImg3d(primitives,colors,opacities); 23427 } 23428 23429 template<typename tp> 23430 CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives) const { 23431 CImgList<T> colors, opacities; 23432 return get_object3dtoCImg3d(primitives,colors,opacities); 23433 } 23434 23435 CImg<floatT> get_object3dtoCImg3d() const { 23436 CImgList<T> opacities, colors; 23437 CImgList<uintT> primitives(width(),1,1,1,1); 23438 cimglist_for(primitives,p) primitives(p,0) = p; 23439 return get_object3dtoCImg3d(primitives,colors,opacities); 23440 } 23441 23442 //! Convert a CImg3d (one-column image) into a 3d object. 23443 template<typename tp, typename tc, typename to> 23444 CImg<T> get_CImg3dtoobject3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImgList<to>& opacities) const { 23445 char error_message[1024] = { 0 }; 23446 if (!is_CImg3d(true,error_message)) 23447 throw CImgInstanceException(_cimg_instance 23448 "CImg3dtoobject3d() : Instance image is not a CImg3d (%s).", 23449 cimg_instance,error_message); 23450 const T *ptrs = _data + 6; 23451 const unsigned int nb_points = (unsigned int)*(ptrs++), nb_primitives = (unsigned int)*(ptrs++); 23452 const CImg<T> points = CImg<T>(ptrs,3,nb_points,1,1,true).get_transpose(); 23453 ptrs+=3*nb_points; 23454 primitives.assign(nb_primitives); 23455 cimglist_for(primitives,p) { 23456 const unsigned int nb_inds = (unsigned int)*(ptrs++); 23457 primitives[p].assign(ptrs,1,nb_inds,1,1,false); 23458 ptrs+=nb_inds; 23459 } 23460 colors.assign(nb_primitives); 23461 cimglist_for(colors,c) { 23462 if ((int)*ptrs==-128) { 23463 ++ptrs; 23464 const unsigned int w = (unsigned int)*(ptrs++), h = (unsigned int)*(ptrs++), s = (unsigned int)*(ptrs++); 23465 if (!h && !s) colors[c].assign(colors[w],true); 23466 else { colors[c].assign(ptrs,w,h,1,s,false); ptrs+=w*h*s; } 23467 } else { colors[c].assign(ptrs,1,3,1,1,false); ptrs+=3; } 23468 } 23469 opacities.assign(nb_primitives); 23470 cimglist_for(opacities,o) { 23471 if ((int)*ptrs==-128) { 23472 ++ptrs; 23473 const unsigned int w = (unsigned int)*(ptrs++), h = (unsigned int)*(ptrs++), s = (unsigned int)*(ptrs++); 23474 if (!h && !s) opacities[o].assign(opacities[w],true); 23475 else { opacities[o].assign(ptrs,w,h,1,s,false); ptrs+=w*h*s; } 23476 } else opacities[o].assign(1,1,1,1,*(ptrs++)); 23477 } 23478 return points; 23479 } 23480 23481 template<typename tp, typename tc, typename to> 23482 CImg<T>& CImg3dtoobject3d(CImgList<tp>& primitives, CImgList<tc>& colors, CImgList<to>& opacities) { 23483 return get_CImg3dtoobject3d(primitives,colors,opacities).move_to(*this); 23484 } 23485 23486 //@} 23487 //--------------------------- 23488 // 23489 //! \name Drawing Functions 23490 //@{ 23491 //--------------------------- 23492 23493 // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose. 23494 // Pre-requisites : x0<x1, y-coordinate is valid, col is valid. 23495 template<typename tc> 23496 CImg<T>& _draw_scanline(const int x0, const int x1, const int y, 23497 const tc *const color, const float opacity=1, 23498 const float brightness=1, const bool init=false) { 23499 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 23500 static float nopacity = 0, copacity = 0; 23501 static unsigned int whd = 0; 23502 static const tc *col = 0; 23503 if (init) { 23504 nopacity = cimg::abs(opacity); 23505 copacity = 1 - cimg::max(opacity,0); 23506 whd = _width*_height*_depth; 23507 } else { 23508 const int nx0 = x0>0?x0:0, nx1 = x1<width()?x1:width()-1, dx = nx1 - nx0; 23509 if (dx>=0) { 23510 col = color; 23511 const unsigned int off = whd-dx-1; 23512 T *ptrd = data(nx0,y); 23513 if (opacity>=1) { // ** Opaque drawing ** 23514 if (brightness==1) { // Brightness==1 23515 if (sizeof(T)!=1) cimg_forC(*this,c) { 23516 const T val = (T)*(col++); 23517 for (int x = dx; x>=0; --x) *(ptrd++) = val; 23518 ptrd+=off; 23519 } else cimg_forC(*this,c) { 23520 const T val = (T)*(col++); 23521 std::memset(ptrd,(int)val,dx+1); 23522 ptrd+=whd; 23523 } 23524 } else if (brightness<1) { // Brightness<1 23525 if (sizeof(T)!=1) cimg_forC(*this,c) { 23526 const T val = (T)(*(col++)*brightness); 23527 for (int x = dx; x>=0; --x) *(ptrd++) = val; 23528 ptrd+=off; 23529 } else cimg_forC(*this,c) { 23530 const T val = (T)(*(col++)*brightness); 23531 std::memset(ptrd,(int)val,dx+1); 23532 ptrd+=whd; 23533 } 23534 } else { // Brightness>1 23535 if (sizeof(T)!=1) cimg_forC(*this,c) { 23536 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval); 23537 for (int x = dx; x>=0; --x) *(ptrd++) = val; 23538 ptrd+=off; 23539 } else cimg_forC(*this,c) { 23540 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval); 23541 std::memset(ptrd,(int)val,dx+1); 23542 ptrd+=whd; 23543 } 23544 } 23545 } else { // ** Transparent drawing ** 23546 if (brightness==1) { // Brightness==1 23547 cimg_forC(*this,c) { 23548 const T val = (T)*(col++); 23549 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } 23550 ptrd+=off; 23551 } 23552 } else if (brightness<=1) { // Brightness<1 23553 cimg_forC(*this,c) { 23554 const T val = (T)(*(col++)*brightness); 23555 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } 23556 ptrd+=off; 23557 } 23558 } else { // Brightness>1 23559 cimg_forC(*this,c) { 23560 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval); 23561 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; } 23562 ptrd+=off; 23563 } 23564 } 23565 } 23566 } 23567 } 23568 return *this; 23569 } 23570 23571 template<typename tc> 23572 CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) { 23573 return _draw_scanline(0,0,0,color,opacity,0,true); 23574 } 23575 23576 //! Draw a 2d colored point (pixel). 23577 /** 23578 \param x0 X-coordinate of the point. 23579 \param y0 Y-coordinate of the point. 23580 \param color Pointer to \c spectrum() consecutive values, defining the color values. 23581 \param opacity Drawing opacity (optional). 23582 \note 23583 - Clipping is supported. 23584 - To set pixel values without clipping needs, you should use the faster CImg::operator()() function. 23585 \par Example: 23586 \code 23587 CImg<unsigned char> img(100,100,1,3,0); 23588 const unsigned char color[] = { 255,128,64 }; 23589 img.draw_point(50,50,color); 23590 \endcode 23591 **/ 23592 template<typename tc> 23593 CImg<T>& draw_point(const int x0, const int y0, 23594 const tc *const color, const float opacity=1) { 23595 return draw_point(x0,y0,0,color,opacity); 23596 } 23597 23598 //! Draw a 3d colored point (voxel). 23599 template<typename tc> 23600 CImg<T>& draw_point(const int x0, const int y0, const int z0, 23601 const tc *const color, const float opacity=1) { 23602 if (!color) 23603 throw CImgArgumentException(_cimg_instance 23604 "draw_point() : Specified color is (null).", 23605 cimg_instance); 23606 23607 if (is_empty()) return *this; 23608 if (x0>=0 && y0>=0 && z0>=0 && x0<width() && y0<height() && z0<depth()) { 23609 const unsigned int whd = _width*_height*_depth; 23610 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 23611 T *ptrd = data(x0,y0,z0,0); 23612 const tc *col = color; 23613 if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } 23614 else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } 23615 } 23616 return *this; 23617 } 23618 23619 // Draw a cloud of colored points. 23620 template<typename t, typename tc> 23621 CImg<T>& draw_point(const CImg<t>& points, 23622 const tc *const color, const float opacity=1) { 23623 if (is_empty() || !points) return *this; 23624 switch (points._height) { 23625 case 0 : case 1 : 23626 throw CImgArgumentException(_cimg_instance 23627 "draw_point() : Invalid specified point set (%u,%u,%u,%u,%p).", 23628 cimg_instance, 23629 points._width,points._height,points._depth,points._spectrum,points._data); 23630 case 2 : { 23631 cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),color,opacity); 23632 } break; 23633 default : { 23634 cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),(int)points(i,2),color,opacity); 23635 } 23636 } 23637 return *this; 23638 } 23639 23640 //! Draw a 2d colored line. 23641 /** 23642 \param x0 X-coordinate of the starting line point. 23643 \param y0 Y-coordinate of the starting line point. 23644 \param x1 X-coordinate of the ending line point. 23645 \param y1 Y-coordinate of the ending line point. 23646 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 23647 \param opacity Drawing opacity (optional). 23648 \param pattern An integer whose bits describe the line pattern (optional). 23649 \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional). 23650 \note 23651 - Clipping is supported. 23652 - Line routine uses Bresenham's algorithm. 23653 - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern. 23654 \par Example: 23655 \code 23656 CImg<unsigned char> img(100,100,1,3,0); 23657 const unsigned char color[] = { 255,128,64 }; 23658 img.draw_line(40,40,80,70,color); 23659 \endcode 23660 **/ 23661 template<typename tc> 23662 CImg<T>& draw_line(const int x0, const int y0, 23663 const int x1, const int y1, 23664 const tc *const color, const float opacity=1, 23665 const unsigned int pattern=~0U, const bool init_hatch=true) { 23666 if (!color) 23667 throw CImgArgumentException(_cimg_instance 23668 "draw_line() : Specified color is (null).", 23669 cimg_instance); 23670 23671 if (is_empty()) return *this; 23672 static unsigned int hatch = ~0U - (~0U>>1); 23673 if (init_hatch) hatch = ~0U - (~0U>>1); 23674 const bool xdir = x0<x1, ydir = y0<y1; 23675 int 23676 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1, 23677 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, 23678 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, 23679 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, 23680 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; 23681 if (xright<0 || xleft>=width()) return *this; 23682 if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; } 23683 if (xright>=width()) { yright-=(xright - width())*(yright - yleft)/(xright - xleft); xright = width()-1; } 23684 if (ydown<0 || yup>=height()) return *this; 23685 if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; } 23686 if (ydown>=height()) { xdown-=(ydown - height())*(xdown - xup)/(ydown - yup); ydown = height()-1; } 23687 T *ptrd0 = data(nx0,ny0); 23688 int dx = xright - xleft, dy = ydown - yup; 23689 const bool steep = dy>dx; 23690 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); 23691 const int 23692 offx = (nx0<nx1?1:-1)*(steep?_width:1), 23693 offy = (ny0<ny1?1:-1)*(steep?1:_width), 23694 wh = _width*_height; 23695 if (opacity>=1) { 23696 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 23697 if (pattern&hatch) { 23698 T *ptrd = ptrd0; const tc* col = color; 23699 cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } 23700 } 23701 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 23702 ptrd0+=offx; 23703 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23704 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 23705 T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } 23706 ptrd0+=offx; 23707 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23708 } 23709 } else { 23710 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 23711 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 23712 if (pattern&hatch) { 23713 T *ptrd = ptrd0; const tc* col = color; 23714 cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } 23715 } 23716 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 23717 ptrd0+=offx; 23718 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23719 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 23720 T *ptrd = ptrd0; const tc* col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } 23721 ptrd0+=offx; 23722 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23723 } 23724 } 23725 return *this; 23726 } 23727 23728 //! Draw a 2d colored line, with z-buffering. 23729 template<typename tc> 23730 CImg<T>& draw_line(CImg<floatT>& zbuffer, 23731 const int x0, const int y0, const float z0, 23732 const int x1, const int y1, const float z1, 23733 const tc *const color, const float opacity=1, 23734 const unsigned int pattern=~0U, const bool init_hatch=true) { 23735 if (!color) 23736 throw CImgArgumentException(_cimg_instance 23737 "draw_line() : Specified color is (null).", 23738 cimg_instance); 23739 if (!is_sameXY(zbuffer)) 23740 throw CImgArgumentException(_cimg_instance 23741 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 23742 cimg_instance, 23743 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 23744 23745 if (is_empty() || z0<=0 || z1<=0) return *this; 23746 static unsigned int hatch = ~0U - (~0U>>1); 23747 if (init_hatch) hatch = ~0U - (~0U>>1); 23748 const bool xdir = x0<x1, ydir = y0<y1; 23749 int 23750 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1, 23751 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, 23752 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, 23753 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, 23754 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; 23755 float 23756 Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0, 23757 &zleft = xdir?nz0:nz1, 23758 &zright = xdir?nz1:nz0, 23759 &zup = ydir?nz0:nz1, 23760 &zdown = ydir?nz1:nz0; 23761 if (xright<0 || xleft>=width()) return *this; 23762 if (xleft<0) { 23763 const int D = xright - xleft; 23764 yleft-=xleft*(yright - yleft)/D; 23765 zleft-=xleft*(zright - zleft)/D; 23766 xleft = 0; 23767 } 23768 if (xright>=width()) { 23769 const int d = xright - width(), D = xright - xleft; 23770 yright-=d*(yright - yleft)/D; 23771 zright-=d*(zright - zleft)/D; 23772 xright = width()-1; 23773 } 23774 if (ydown<0 || yup>=height()) return *this; 23775 if (yup<0) { 23776 const int D = ydown - yup; 23777 xup-=yup*(xdown - xup)/D; 23778 zup-=yup*(zdown - zup)/D; 23779 yup = 0; 23780 } 23781 if (ydown>=height()) { 23782 const int d = ydown - height(), D = ydown - yup; 23783 xdown-=d*(xdown - xup)/D; 23784 zdown-=d*(zdown - zup)/D; 23785 ydown = height()-1; 23786 } 23787 T *ptrd0 = data(nx0,ny0); 23788 float *ptrz = zbuffer.data(nx0,ny0); 23789 int dx = xright - xleft, dy = ydown - yup; 23790 const bool steep = dy>dx; 23791 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); 23792 const int 23793 offx = (nx0<nx1?1:-1)*(steep?_width:1), 23794 offy = (ny0<ny1?1:-1)*(steep?1:_width), 23795 wh = _width*_height, 23796 ndx = dx>0?dx:1; 23797 if (opacity>=1) { 23798 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 23799 const float z = Z0 + x*dz/ndx; 23800 if (z>=*ptrz && pattern&hatch) { 23801 *ptrz = z; 23802 T *ptrd = ptrd0; const tc *col = color; 23803 cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } 23804 } 23805 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 23806 ptrd0+=offx; ptrz+=offx; 23807 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 23808 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 23809 const float z = Z0 + x*dz/ndx; 23810 if (z>=*ptrz) { 23811 *ptrz = z; 23812 T *ptrd = ptrd0; const tc *col = color; 23813 cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=wh; } 23814 } 23815 ptrd0+=offx; ptrz+=offx; 23816 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 23817 } 23818 } else { 23819 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 23820 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 23821 const float z = Z0 + x*dz/ndx; 23822 if (z>=*ptrz && pattern&hatch) { 23823 *ptrz = z; 23824 T *ptrd = ptrd0; const tc *col = color; 23825 cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } 23826 } 23827 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 23828 ptrd0+=offx; ptrz+=offx; 23829 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 23830 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 23831 const float z = Z0 + x*dz/ndx; 23832 if (z>=*ptrz) { 23833 *ptrz = z; 23834 T *ptrd = ptrd0; const tc *col = color; 23835 cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; } 23836 } 23837 ptrd0+=offx; ptrz+=offx; 23838 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 23839 } 23840 } 23841 return *this; 23842 } 23843 23844 //! Draw a 3d colored line. 23845 template<typename tc> 23846 CImg<T>& draw_line(const int x0, const int y0, const int z0, 23847 const int x1, const int y1, const int z1, 23848 const tc *const color, const float opacity=1, 23849 const unsigned int pattern=~0U, const bool init_hatch=true) { 23850 if (!color) 23851 throw CImgArgumentException(_cimg_instance 23852 "draw_line() : Specified color is (null).", 23853 cimg_instance); 23854 23855 if (is_empty()) return *this; 23856 static unsigned int hatch = ~0U - (~0U>>1); 23857 if (init_hatch) hatch = ~0U - (~0U>>1); 23858 int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1; 23859 if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); 23860 if (nx1<0 || nx0>=width()) return *this; 23861 if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; } 23862 if (nx1>=width()) { const int d = nx1-width(), D = 1 + nx1 - nx0; ny1+=d*(1 + ny0 - ny1)/D; nz1+=d*(1 + nz0 - nz1)/D; nx1 = width()-1; } 23863 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); 23864 if (ny1<0 || ny0>=height()) return *this; 23865 if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; } 23866 if (ny1>=height()) { const int d = ny1-height(), D = 1 + ny1 - ny0; nx1+=d*(1 + nx0 - nx1)/D; nz1+=d*(1 + nz0 - nz1)/D; ny1 = height()-1; } 23867 if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); 23868 if (nz1<0 || nz0>=depth()) return *this; 23869 if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; } 23870 if (nz1>=depth()) { const int d = nz1-depth(), D = 1 + nz1 - nz0; nx1+=d*(1 + nx0 - nx1)/D; ny1+=d*(1 + ny0 - ny1)/D; nz1 = depth()-1; } 23871 const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whd = _width*_height*_depth; 23872 const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax; 23873 float x = (float)nx0, y = (float)ny0, z = (float)nz0; 23874 if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) { 23875 if (!(~pattern) || (~pattern && pattern&hatch)) { 23876 T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z); 23877 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } 23878 } 23879 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); } 23880 } else { 23881 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 23882 for (unsigned int t = 0; t<=dmax; ++t) { 23883 if (!(~pattern) || (~pattern && pattern&hatch)) { 23884 T* ptrd = data((unsigned int)x,(unsigned int)y,(unsigned int)z); 23885 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } 23886 } 23887 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); } 23888 } 23889 } 23890 return *this; 23891 } 23892 23893 //! Draw a 2d textured line. 23894 /** 23895 \param x0 X-coordinate of the starting line point. 23896 \param y0 Y-coordinate of the starting line point. 23897 \param x1 X-coordinate of the ending line point. 23898 \param y1 Y-coordinate of the ending line point. 23899 \param texture Texture image defining the pixel colors. 23900 \param tx0 X-coordinate of the starting texture point. 23901 \param ty0 Y-coordinate of the starting texture point. 23902 \param tx1 X-coordinate of the ending texture point. 23903 \param ty1 Y-coordinate of the ending texture point. 23904 \param opacity Drawing opacity (optional). 23905 \param pattern An integer whose bits describe the line pattern (optional). 23906 \param init_hatch Flag telling if the hash variable must be reinitialized (optional). 23907 \note 23908 - Clipping is supported but not for texture coordinates. 23909 - Line routine uses the well known Bresenham's algorithm. 23910 \par Example: 23911 \code 23912 CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm"); 23913 const unsigned char color[] = { 255,128,64 }; 23914 img.draw_line(40,40,80,70,texture,0,0,255,255); 23915 \endcode 23916 **/ 23917 template<typename tc> 23918 CImg<T>& draw_line(const int x0, const int y0, 23919 const int x1, const int y1, 23920 const CImg<tc>& texture, 23921 const int tx0, const int ty0, 23922 const int tx1, const int ty1, 23923 const float opacity=1, 23924 const unsigned int pattern=~0U, const bool init_hatch=true) { 23925 if (texture._depth>1 || texture._spectrum<_spectrum) 23926 throw CImgArgumentException(_cimg_instance 23927 "draw_line() : Invalid specified texture (%u,%u,%u,%u,%p).", 23928 cimg_instance, 23929 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 23930 23931 if (is_empty()) return *this; 23932 if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); 23933 static unsigned int hatch = ~0U - (~0U>>1); 23934 if (init_hatch) hatch = ~0U - (~0U>>1); 23935 const bool xdir = x0<x1, ydir = y0<y1; 23936 int 23937 dtx = tx1-tx0, dty = ty1-ty0, 23938 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1, 23939 tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1, 23940 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, 23941 &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0, 23942 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0, 23943 &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0; 23944 if (xright<0 || xleft>=width()) return *this; 23945 if (xleft<0) { 23946 const int D = xright - xleft; 23947 yleft-=xleft*(yright - yleft)/D; 23948 txleft-=xleft*(txright - txleft)/D; 23949 tyleft-=xleft*(tyright - tyleft)/D; 23950 xleft = 0; 23951 } 23952 if (xright>=width()) { 23953 const int d = xright - width(), D = xright - xleft; 23954 yright-=d*(yright - yleft)/D; 23955 txright-=d*(txright - txleft)/D; 23956 tyright-=d*(tyright - tyleft)/D; 23957 xright = width()-1; 23958 } 23959 if (ydown<0 || yup>=height()) return *this; 23960 if (yup<0) { 23961 const int D = ydown - yup; 23962 xup-=yup*(xdown - xup)/D; 23963 txup-=yup*(txdown - txup)/D; 23964 tyup-=yup*(tydown - tyup)/D; 23965 yup = 0; 23966 } 23967 if (ydown>=height()) { 23968 const int d = ydown - height(), D = ydown - yup; 23969 xdown-=d*(xdown - xup)/D; 23970 txdown-=d*(txdown - txup)/D; 23971 tydown-=d*(tydown - tyup)/D; 23972 ydown = height()-1; 23973 } 23974 T *ptrd0 = data(nx0,ny0); 23975 int dx = xright - xleft, dy = ydown - yup; 23976 const bool steep = dy>dx; 23977 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); 23978 const int 23979 offx = (nx0<nx1?1:-1)*(steep?_width:1), 23980 offy = (ny0<ny1?1:-1)*(steep?1:_width), 23981 wh = _width*_height, 23982 ndx = dx>0?dx:1; 23983 if (opacity>=1) { 23984 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 23985 if (pattern&hatch) { 23986 T *ptrd = ptrd0; 23987 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; 23988 cimg_forC(*this,c) { *ptrd = (T)texture(tx,ty,0,c); ptrd+=wh; } 23989 } 23990 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 23991 ptrd0+=offx; 23992 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23993 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 23994 T *ptrd = ptrd0; 23995 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; 23996 cimg_forC(*this,c) { *ptrd = (T)texture(tx,ty,0,c); ptrd+=wh; } 23997 ptrd0+=offx; 23998 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 23999 } 24000 } else { 24001 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 24002 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 24003 T *ptrd = ptrd0; 24004 if (pattern&hatch) { 24005 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; 24006 cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture(tx,ty,0,c) + *ptrd*copacity); ptrd+=wh; } 24007 } 24008 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 24009 ptrd0+=offx; 24010 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24011 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 24012 T *ptrd = ptrd0; 24013 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx; 24014 cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture(tx,ty,0,c) + *ptrd*copacity); ptrd+=wh; } 24015 ptrd0+=offx; 24016 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24017 } 24018 } 24019 return *this; 24020 } 24021 24022 //! Draw a 2d textured line, with perspective correction. 24023 template<typename tc> 24024 CImg<T>& draw_line(const int x0, const int y0, const float z0, 24025 const int x1, const int y1, const float z1, 24026 const CImg<tc>& texture, 24027 const int tx0, const int ty0, 24028 const int tx1, const int ty1, 24029 const float opacity=1, 24030 const unsigned int pattern=~0U, const bool init_hatch=true) { 24031 if (texture._depth>1 || texture._spectrum<_spectrum) 24032 throw CImgArgumentException(_cimg_instance 24033 "draw_line() : Invalid specified texture (%u,%u,%u,%u,%p).", 24034 cimg_instance, 24035 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 24036 24037 if (is_empty() && z0<=0 && z1<=0) return *this; 24038 if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); 24039 static unsigned int hatch = ~0U - (~0U>>1); 24040 if (init_hatch) hatch = ~0U - (~0U>>1); 24041 const bool xdir = x0<x1, ydir = y0<y1; 24042 int 24043 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1, 24044 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, 24045 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, 24046 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, 24047 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; 24048 float 24049 Tx0 = tx0/z0, Tx1 = tx1/z1, 24050 Ty0 = ty0/z0, Ty1 = ty1/z1, 24051 Z0 = 1/z0, Z1 = 1/z1, 24052 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0, 24053 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1, 24054 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, 24055 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0, 24056 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, 24057 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0; 24058 if (xright<0 || xleft>=width()) return *this; 24059 if (xleft<0) { 24060 const int D = xright - xleft; 24061 yleft-=xleft*(yright - yleft)/D; 24062 zleft-=xleft*(zright - zleft)/D; 24063 txleft-=xleft*(txright - txleft)/D; 24064 tyleft-=xleft*(tyright - tyleft)/D; 24065 xleft = 0; 24066 } 24067 if (xright>=width()) { 24068 const int d = xright - width(), D = xright - xleft; 24069 yright-=d*(yright - yleft)/D; 24070 zright-=d*(zright - zleft)/D; 24071 txright-=d*(txright - txleft)/D; 24072 tyright-=d*(tyright - tyleft)/D; 24073 xright = width()-1; 24074 } 24075 if (ydown<0 || yup>=height()) return *this; 24076 if (yup<0) { 24077 const int D = ydown - yup; 24078 xup-=yup*(xdown - xup)/D; 24079 zup-=yup*(zdown - zup)/D; 24080 txup-=yup*(txdown - txup)/D; 24081 tyup-=yup*(tydown - tyup)/D; 24082 yup = 0; 24083 } 24084 if (ydown>=height()) { 24085 const int d = ydown - height(), D = ydown - yup; 24086 xdown-=d*(xdown - xup)/D; 24087 zdown-=d*(zdown - zup)/D; 24088 txdown-=d*(txdown - txup)/D; 24089 tydown-=d*(tydown - tyup)/D; 24090 ydown = height()-1; 24091 } 24092 T *ptrd0 = data(nx0,ny0); 24093 int dx = xright - xleft, dy = ydown - yup; 24094 const bool steep = dy>dx; 24095 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); 24096 const int 24097 offx = (nx0<nx1?1:-1)*(steep?_width:1), 24098 offy = (ny0<ny1?1:-1)*(steep?1:_width), 24099 wh = _width*_height, 24100 ndx = dx>0?dx:1; 24101 if (opacity>=1) { 24102 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 24103 if (pattern&hatch) { 24104 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24105 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } 24106 } 24107 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 24108 ptrd0+=offx; 24109 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24110 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 24111 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24112 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } 24113 ptrd0+=offx; 24114 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24115 } 24116 } else { 24117 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 24118 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 24119 if (pattern&hatch) { 24120 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24121 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; } 24122 } 24123 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 24124 ptrd0+=offx; 24125 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24126 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 24127 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24128 T *ptrd = ptrd0; 24129 cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; } 24130 ptrd0+=offx; 24131 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; } 24132 } 24133 } 24134 return *this; 24135 } 24136 24137 //! Draw a 2d textured line, with z-buffering and perspective correction. 24138 template<typename tc> 24139 CImg<T>& draw_line(CImg<floatT>& zbuffer, 24140 const int x0, const int y0, const float z0, 24141 const int x1, const int y1, const float z1, 24142 const CImg<tc>& texture, 24143 const int tx0, const int ty0, 24144 const int tx1, const int ty1, 24145 const float opacity=1, 24146 const unsigned int pattern=~0U, const bool init_hatch=true) { 24147 if (!is_sameXY(zbuffer)) 24148 throw CImgArgumentException(_cimg_instance 24149 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 24150 cimg_instance, 24151 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 24152 24153 if (texture._depth>1 || texture._spectrum<_spectrum) 24154 throw CImgArgumentException(_cimg_instance 24155 "draw_line() : Invalid specified texture (%u,%u,%u,%u,%p).", 24156 cimg_instance, 24157 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 24158 24159 if (is_empty() || z0<=0 || z1<=0) return *this; 24160 if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); 24161 static unsigned int hatch = ~0U - (~0U>>1); 24162 if (init_hatch) hatch = ~0U - (~0U>>1); 24163 const bool xdir = x0<x1, ydir = y0<y1; 24164 int 24165 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1, 24166 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, 24167 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, 24168 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, 24169 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; 24170 float 24171 Tx0 = tx0/z0, Tx1 = tx1/z1, 24172 Ty0 = ty0/z0, Ty1 = ty1/z1, 24173 Z0 = 1/z0, Z1 = 1/z1, 24174 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0, 24175 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1, 24176 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, 24177 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0, 24178 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, 24179 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0; 24180 if (xright<0 || xleft>=width()) return *this; 24181 if (xleft<0) { 24182 const int D = xright - xleft; 24183 yleft-=xleft*(yright - yleft)/D; 24184 zleft-=xleft*(zright - zleft)/D; 24185 txleft-=xleft*(txright - txleft)/D; 24186 tyleft-=xleft*(tyright - tyleft)/D; 24187 xleft = 0; 24188 } 24189 if (xright>=width()) { 24190 const int d = xright - width(), D = xright - xleft; 24191 yright-=d*(yright - yleft)/D; 24192 zright-=d*(zright - zleft)/D; 24193 txright-=d*(txright - txleft)/D; 24194 tyright-=d*(tyright - tyleft)/D; 24195 xright = width()-1; 24196 } 24197 if (ydown<0 || yup>=height()) return *this; 24198 if (yup<0) { 24199 const int D = ydown - yup; 24200 xup-=yup*(xdown - xup)/D; 24201 zup-=yup*(zdown - zup)/D; 24202 txup-=yup*(txdown - txup)/D; 24203 tyup-=yup*(tydown - tyup)/D; 24204 yup = 0; 24205 } 24206 if (ydown>=height()) { 24207 const int d = ydown - height(), D = ydown - yup; 24208 xdown-=d*(xdown - xup)/D; 24209 zdown-=d*(zdown - zup)/D; 24210 txdown-=d*(txdown - txup)/D; 24211 tydown-=d*(tydown - tyup)/D; 24212 ydown = height()-1; 24213 } 24214 T *ptrd0 = data(nx0,ny0); 24215 float *ptrz = zbuffer.data(nx0,ny0); 24216 int dx = xright - xleft, dy = ydown - yup; 24217 const bool steep = dy>dx; 24218 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy); 24219 const int 24220 offx = (nx0<nx1?1:-1)*(steep?_width:1), 24221 offy = (ny0<ny1?1:-1)*(steep?1:_width), 24222 wh = _width*_height, 24223 ndx = dx>0?dx:1; 24224 if (opacity>=1) { 24225 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 24226 if (pattern&hatch) { 24227 const float z = Z0 + x*dz/ndx; 24228 if (z>=*ptrz) { 24229 *ptrz = z; 24230 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24231 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } 24232 } 24233 } 24234 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 24235 ptrd0+=offx; ptrz+=offx; 24236 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 24237 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 24238 const float z = Z0 + x*dz/ndx; 24239 if (z>=*ptrz) { 24240 *ptrz = z; 24241 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24242 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,c); ptrd+=wh; } 24243 } 24244 ptrd0+=offx; ptrz+=offx; 24245 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 24246 } 24247 } else { 24248 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 24249 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) { 24250 if (pattern&hatch) { 24251 const float z = Z0 + x*dz/ndx; 24252 if (z>=*ptrz) { 24253 *ptrz = z; 24254 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24255 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; } 24256 } 24257 } 24258 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); 24259 ptrd0+=offx; ptrz+=offx; 24260 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; } 24261 } else for (int error = dx>>1, x = 0; x<=dx; ++x) { 24262 const float z = Z0 + x*dz/ndx; 24263 if (z>=*ptrz) { 24264 *ptrz = z; 24265 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx; 24266 T *ptrd = ptrd0; cimg_forC(*this,c) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,c) + *ptrd*copacity); ptrd+=wh; } 24267 } 24268 ptrd0+=offx; ptrz+=offx; 24269 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; } 24270 } 24271 } 24272 return *this; 24273 } 24274 24275 //! Draw a set of consecutive colored lines in the instance image. 24276 /** 24277 \param points Coordinates of vertices, stored as a list of vectors. 24278 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 24279 \param opacity Drawing opacity (optional). 24280 \param pattern An integer whose bits describe the line pattern (optional). 24281 \param init_hatch If set to true, init hatch motif. 24282 \note 24283 - This function uses several call to the single CImg::draw_line() procedure, 24284 depending on the vectors size in \p points. 24285 \par Example: 24286 \code 24287 CImg<unsigned char> img(100,100,1,3,0); 24288 const unsigned char color[] = { 255,128,64 }; 24289 CImgList<int> points; 24290 points.insert(CImg<int>::vector(0,0)). 24291 .insert(CImg<int>::vector(70,10)). 24292 .insert(CImg<int>::vector(80,60)). 24293 .insert(CImg<int>::vector(10,90)); 24294 img.draw_line(points,color); 24295 \endcode 24296 **/ 24297 template<typename t, typename tc> 24298 CImg<T>& draw_line(const CImg<t>& points, 24299 const tc *const color, const float opacity=1, 24300 const unsigned int pattern=~0U, const bool init_hatch=true) { 24301 if (is_empty() || !points || points._width<2) return *this; 24302 bool ninit_hatch = init_hatch; 24303 switch (points._height) { 24304 case 0 : case 1 : 24305 throw CImgArgumentException(_cimg_instance 24306 "draw_line() : Invalid specified point set (%u,%u,%u,%u,%p).", 24307 cimg_instance, 24308 points._width,points._height,points._depth,points._spectrum,points._data); 24309 24310 case 2 : { 24311 const int x0 = (int)points(0,0), y0 = (int)points(0,1); 24312 int ox = x0, oy = y0; 24313 for (unsigned int i = 1; i<points._width; ++i) { 24314 const int x = (int)points(i,0), y = (int)points(i,1); 24315 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch); 24316 ninit_hatch = false; 24317 ox = x; oy = y; 24318 } 24319 } break; 24320 default : { 24321 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2); 24322 int ox = x0, oy = y0, oz = z0; 24323 for (unsigned int i = 1; i<points._width; ++i) { 24324 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2); 24325 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch); 24326 ninit_hatch = false; 24327 ox = x; oy = y; oz = z; 24328 } 24329 } 24330 } 24331 return *this; 24332 } 24333 24334 //! Draw a colored arrow in the instance image. 24335 /** 24336 \param x0 X-coordinate of the starting arrow point (tail). 24337 \param y0 Y-coordinate of the starting arrow point (tail). 24338 \param x1 X-coordinate of the ending arrow point (head). 24339 \param y1 Y-coordinate of the ending arrow point (head). 24340 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 24341 \param angle Aperture angle of the arrow head (optional). 24342 \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional). 24343 \param opacity Drawing opacity (optional). 24344 \param pattern An integer whose bits describe the line pattern (optional). 24345 \note 24346 - Clipping is supported. 24347 **/ 24348 template<typename tc> 24349 CImg<T>& draw_arrow(const int x0, const int y0, 24350 const int x1, const int y1, 24351 const tc *const color, const float opacity=1, 24352 const float angle=30, const float length=-10, 24353 const unsigned int pattern=~0U) { 24354 if (is_empty()) return *this; 24355 const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v, 24356 deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f, 24357 l = (length>=0)?length:-length*(float)std::sqrt(sq)/100; 24358 if (sq>0) { 24359 const float 24360 cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg), 24361 cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg); 24362 const int 24363 xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl), 24364 xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr), 24365 xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2; 24366 draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); 24367 } else draw_point(x0,y0,color,opacity); 24368 return *this; 24369 } 24370 24371 //! Draw a cubic spline curve in the instance image. 24372 /** 24373 \param x0 X-coordinate of the starting curve point 24374 \param y0 Y-coordinate of the starting curve point 24375 \param u0 X-coordinate of the starting velocity 24376 \param v0 Y-coordinate of the starting velocity 24377 \param x1 X-coordinate of the ending curve point 24378 \param y1 Y-coordinate of the ending curve point 24379 \param u1 X-coordinate of the ending velocity 24380 \param v1 Y-coordinate of the ending velocity 24381 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 24382 \param precision Curve drawing precision (optional). 24383 \param opacity Drawing opacity (optional). 24384 \param pattern An integer whose bits describe the line pattern (optional). 24385 \param init_hatch If \c true, init hatch motif. 24386 \note 24387 - The curve is a 2d cubic Bezier spline, from the set of specified starting/ending points 24388 and corresponding velocity vectors. 24389 - The spline is drawn as a serie of connected segments. The \p precision parameter sets the 24390 average number of pixels in each drawn segment. 24391 - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), (\p xb,\p yb), (\p x1,\p y1) } 24392 where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point and (\p xa,\p ya), (\p xb,\p yb) are two 24393 \e control points. 24394 The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as 24395 \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb). 24396 \par Example: 24397 \code 24398 CImg<unsigned char> img(100,100,1,3,0); 24399 const unsigned char color[] = { 255,255,255 }; 24400 img.draw_spline(30,30,0,100,90,40,0,-100,color); 24401 \endcode 24402 **/ 24403 template<typename tc> 24404 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0, 24405 const int x1, const int y1, const float u1, const float v1, 24406 const tc *const color, const float opacity=1, 24407 const float precision=4, const unsigned int pattern=~0U, 24408 const bool init_hatch=true) { 24409 if (!color) 24410 throw CImgArgumentException(_cimg_instance 24411 "draw_spline() : Specified color is (null).", 24412 cimg_instance); 24413 24414 if (is_empty()) return *this; 24415 bool ninit_hatch = init_hatch; 24416 const float 24417 dx = (float)(x1 - x0), 24418 dy = (float)(y1 - y0), 24419 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)), 24420 ax = -2*dx + u0 + u1, 24421 bx = 3*dx - 2*u0 - u1, 24422 ay = -2*dy + v0 + v1, 24423 by = 3*dy - 2*v0 - v1, 24424 xprecision = dmax>0?precision/dmax:1.0f, 24425 tmax = 1 + (dmax>0?xprecision:0.0f); 24426 int ox = x0, oy = y0; 24427 for (float t = 0; t<tmax; t+=xprecision) { 24428 const float 24429 t2 = t*t, 24430 t3 = t2*t; 24431 const int 24432 nx = (int)(ax*t3 + bx*t2 + u0*t + x0), 24433 ny = (int)(ay*t3 + by*t2 + v0*t + y0); 24434 draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch); 24435 ninit_hatch = false; 24436 ox = nx; oy = ny; 24437 } 24438 return *this; 24439 } 24440 24441 //! Draw a cubic spline curve in the instance image (for volumetric images). 24442 /** 24443 \note 24444 - Similar to CImg::draw_spline() for a 3d spline in a volumetric image. 24445 **/ 24446 template<typename tc> 24447 CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0, 24448 const int x1, const int y1, const int z1, const float u1, const float v1, const float w1, 24449 const tc *const color, const float opacity=1, 24450 const float precision=4, const unsigned int pattern=~0U, 24451 const bool init_hatch=true) { 24452 if (!color) 24453 throw CImgArgumentException(_cimg_instance 24454 "draw_spline() : Specified color is (null).", 24455 cimg_instance); 24456 24457 if (is_empty()) return *this; 24458 bool ninit_hatch = init_hatch; 24459 const float 24460 dx = (float)(x1 - x0), 24461 dy = (float)(y1 - y0), 24462 dz = (float)(z1 - z0), 24463 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)), 24464 ax = -2*dx + u0 + u1, 24465 bx = 3*dx - 2*u0 - u1, 24466 ay = -2*dy + v0 + v1, 24467 by = 3*dy - 2*v0 - v1, 24468 az = -2*dz + w0 + w1, 24469 bz = 3*dz - 2*w0 - w1, 24470 xprecision = dmax>0?precision/dmax:1.0f, 24471 tmax = 1 + (dmax>0?xprecision:0.0f); 24472 int ox = x0, oy = y0, oz = z0; 24473 for (float t = 0; t<tmax; t+=xprecision) { 24474 const float 24475 t2 = t*t, 24476 t3 = t2*t; 24477 const int 24478 nx = (int)(ax*t3 + bx*t2 + u0*t + x0), 24479 ny = (int)(ay*t3 + by*t2 + v0*t + y0), 24480 nz = (int)(az*t3 + bz*t2 + w0*t + z0); 24481 draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch); 24482 ninit_hatch = false; 24483 ox = nx; oy = ny; oz = nz; 24484 } 24485 return *this; 24486 } 24487 24488 //! Draw a cubic spline curve in the instance image. 24489 /** 24490 \param x0 X-coordinate of the starting curve point 24491 \param y0 Y-coordinate of the starting curve point 24492 \param u0 X-coordinate of the starting velocity 24493 \param v0 Y-coordinate of the starting velocity 24494 \param x1 X-coordinate of the ending curve point 24495 \param y1 Y-coordinate of the ending curve point 24496 \param u1 X-coordinate of the ending velocity 24497 \param v1 Y-coordinate of the ending velocity 24498 \param texture Texture image defining line pixel colors. 24499 \param tx0 X-coordinate of the starting texture point. 24500 \param ty0 Y-coordinate of the starting texture point. 24501 \param tx1 X-coordinate of the ending texture point. 24502 \param ty1 Y-coordinate of the ending texture point. 24503 \param precision Curve drawing precision (optional). 24504 \param opacity Drawing opacity (optional). 24505 \param pattern An integer whose bits describe the line pattern (optional). 24506 \param init_hatch if \c true, reinit hatch motif. 24507 **/ 24508 template<typename t> 24509 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0, 24510 const int x1, const int y1, const float u1, const float v1, 24511 const CImg<t>& texture, 24512 const int tx0, const int ty0, const int tx1, const int ty1, 24513 const float opacity=1, 24514 const float precision=4, const unsigned int pattern=~0U, 24515 const bool init_hatch=true) { 24516 if (texture._depth>1 || texture._spectrum<_spectrum) 24517 throw CImgArgumentException(_cimg_instance 24518 "draw_line() : Invalid specified texture (%u,%u,%u,%u,%p).", 24519 cimg_instance, 24520 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 24521 24522 if (is_empty()) return *this; 24523 if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch); 24524 bool ninit_hatch = true; 24525 const float 24526 dx = (float)(x1 - x0), 24527 dy = (float)(y1 - y0), 24528 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)), 24529 ax = -2*dx + u0 + u1, 24530 bx = 3*dx - 2*u0 - u1, 24531 ay = -2*dy + v0 + v1, 24532 by = 3*dy - 2*v0 - v1, 24533 xprecision = dmax>0?precision/dmax:1.0f, 24534 tmax = 1 + (dmax>0?xprecision:0.0f); 24535 int ox = x0, oy = y0, otx = tx0, oty = ty0; 24536 for (float t1 = 0; t1<tmax; t1+=xprecision) { 24537 const float 24538 t2 = t1*t1, 24539 t3 = t2*t1; 24540 const int 24541 nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0), 24542 ny = (int)(ay*t3 + by*t2 + v0*t1 + y0), 24543 ntx = tx0 + (int)((tx1-tx0)*t1/tmax), 24544 nty = ty0 + (int)((ty1-ty0)*t1/tmax); 24545 draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch); 24546 ninit_hatch = false; 24547 ox = nx; oy = ny; otx = ntx; oty = nty; 24548 } 24549 return *this; 24550 } 24551 24552 // Draw a set of connected spline curves in the instance image (internal). 24553 template<typename tp, typename tt, typename tc> 24554 CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents, 24555 const tc *const color, const float opacity=1, 24556 const bool close_set=false, const float precision=4, 24557 const unsigned int pattern=~0U, const bool init_hatch=true) { 24558 if (is_empty() || !points || !tangents || points._width<2 || tangents._width<2) return *this; 24559 bool ninit_hatch = init_hatch; 24560 switch (points._height) { 24561 case 0 : case 1 : 24562 throw CImgArgumentException(_cimg_instance 24563 "draw_spline() : Invalid specified point set (%u,%u,%u,%u,%p).", 24564 cimg_instance, 24565 points._width,points._height,points._depth,points._spectrum,points._data); 24566 24567 case 2 : { 24568 const int x0 = (int)points(0,0), y0 = (int)points(0,1); 24569 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1); 24570 int ox = x0, oy = y0; 24571 float ou = u0, ov = v0; 24572 for (unsigned int i = 1; i<points._width; ++i) { 24573 const int x = (int)points(i,0), y = (int)points(i,1); 24574 const float u = (float)tangents(i,0), v = (float)tangents(i,1); 24575 draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch); 24576 ninit_hatch = false; 24577 ox = x; oy = y; ou = u; ov = v; 24578 } 24579 if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false); 24580 } break; 24581 default : { 24582 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2); 24583 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2); 24584 int ox = x0, oy = y0, oz = z0; 24585 float ou = u0, ov = v0, ow = w0; 24586 for (unsigned int i = 1; i<points._width; ++i) { 24587 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2); 24588 const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2); 24589 draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch); 24590 ninit_hatch = false; 24591 ox = x; oy = y; oz = z; ou = u; ov = v; ow = w; 24592 } 24593 if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false); 24594 } 24595 } 24596 return *this; 24597 } 24598 24599 //! Draw a set of consecutive colored splines in the instance image. 24600 template<typename tp, typename tc> 24601 CImg<T>& draw_spline(const CImg<tp>& points, 24602 const tc *const color, const float opacity=1, 24603 const bool close_set=false, const float precision=4, 24604 const unsigned int pattern=~0U, const bool init_hatch=true) { 24605 if (is_empty() || !points || points._width<2) return *this; 24606 CImg<Tfloat> tangents; 24607 switch (points._height) { 24608 case 0 : case 1 : 24609 throw CImgArgumentException(_cimg_instance 24610 "draw_spline() : Invalid specified point set (%u,%u,%u,%u,%p).", 24611 cimg_instance, 24612 points._width,points._height,points._depth,points._spectrum,points._data); 24613 case 2 : { 24614 tangents.assign(points._width,points._height); 24615 cimg_forX(points,p) { 24616 const unsigned int 24617 p0 = close_set?(p+points._width-1)%points._width:(p?p-1:0), 24618 p1 = close_set?(p+1)%points._width:(p+1<points._width?p+1:p); 24619 const float 24620 x = (float)points(p,0), 24621 y = (float)points(p,1), 24622 x0 = (float)points(p0,0), 24623 y0 = (float)points(p0,1), 24624 x1 = (float)points(p1,0), 24625 y1 = (float)points(p1,1), 24626 u0 = x - x0, 24627 v0 = y - y0, 24628 n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0), 24629 u1 = x1 - x, 24630 v1 = y1 - y, 24631 n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1), 24632 u = u0/n0 + u1/n1, 24633 v = v0/n0 + v1/n1, 24634 n = 1e-8f + (float)std::sqrt(u*u + v*v), 24635 fact = 0.5f*(n0 + n1); 24636 tangents(p,0) = (Tfloat)(fact*u/n); 24637 tangents(p,1) = (Tfloat)(fact*v/n); 24638 } 24639 } break; 24640 default : { 24641 tangents.assign(points._width,points._height); 24642 cimg_forX(points,p) { 24643 const unsigned int 24644 p0 = close_set?(p+points._width-1)%points._width:(p?p-1:0), 24645 p1 = close_set?(p+1)%points._width:(p+1<points._width?p+1:p); 24646 const float 24647 x = (float)points(p,0), 24648 y = (float)points(p,1), 24649 z = (float)points(p,2), 24650 x0 = (float)points(p0,0), 24651 y0 = (float)points(p0,1), 24652 z0 = (float)points(p0,2), 24653 x1 = (float)points(p1,0), 24654 y1 = (float)points(p1,1), 24655 z1 = (float)points(p1,2), 24656 u0 = x - x0, 24657 v0 = y - y0, 24658 w0 = z - z0, 24659 n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0 + w0*w0), 24660 u1 = x1 - x, 24661 v1 = y1 - y, 24662 w1 = z1 - z, 24663 n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1 + w1*w1), 24664 u = u0/n0 + u1/n1, 24665 v = v0/n0 + v1/n1, 24666 w = w0/n0 + w1/n1, 24667 n = 1e-8f + (float)std::sqrt(u*u + v*v + w*w), 24668 fact = 0.5f*(n0 + n1); 24669 tangents(p,0) = (Tfloat)(fact*u/n); 24670 tangents(p,1) = (Tfloat)(fact*v/n); 24671 tangents(p,2) = (Tfloat)(fact*w/n); 24672 } 24673 } 24674 } 24675 return draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch); 24676 } 24677 24678 // Inner macro for drawing triangles. 24679 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \ 24680 for (int y = y0<0?0:y0, \ 24681 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ 24682 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ 24683 _sxn=1, \ 24684 _sxr=1, \ 24685 _sxl=1, \ 24686 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ 24687 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ 24688 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ 24689 _dyn = y2-y1, \ 24690 _dyr = y2-y0, \ 24691 _dyl = y1-y0, \ 24692 _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ 24693 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ 24694 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ 24695 cimg::min((int)(img)._height-y-1,y2-y)), \ 24696 _errn = _dyn/2, \ 24697 _errr = _dyr/2, \ 24698 _errl = _dyl/2, \ 24699 _rxn = _dyn?(x2-x1)/_dyn:0, \ 24700 _rxr = _dyr?(x2-x0)/_dyr:0, \ 24701 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ 24702 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \ 24703 _counter>=0; --_counter, ++y, \ 24704 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ 24705 xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \ 24706 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) 24707 24708 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \ 24709 for (int y = y0<0?0:y0, \ 24710 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ 24711 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \ 24712 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ 24713 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \ 24714 _sxn=1, _scn=1, \ 24715 _sxr=1, _scr=1, \ 24716 _sxl=1, _scl=1, \ 24717 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ 24718 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ 24719 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ 24720 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \ 24721 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \ 24722 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \ 24723 _dyn = y2-y1, \ 24724 _dyr = y2-y0, \ 24725 _dyl = y1-y0, \ 24726 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ 24727 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ 24728 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ 24729 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \ 24730 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \ 24731 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \ 24732 cimg::min((int)(img)._height-y-1,y2-y)), \ 24733 _errn = _dyn/2, _errcn = _errn, \ 24734 _errr = _dyr/2, _errcr = _errr, \ 24735 _errl = _dyl/2, _errcl = _errl, \ 24736 _rxn = _dyn?(x2-x1)/_dyn:0, \ 24737 _rcn = _dyn?(c2-c1)/_dyn:0, \ 24738 _rxr = _dyr?(x2-x0)/_dyr:0, \ 24739 _rcr = _dyr?(c2-c0)/_dyr:0, \ 24740 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ 24741 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ 24742 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \ 24743 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \ 24744 _counter>=0; --_counter, ++y, \ 24745 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ 24746 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \ 24747 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \ 24748 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ 24749 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ 24750 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) 24751 24752 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \ 24753 for (int y = y0<0?0:y0, \ 24754 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ 24755 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ 24756 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ 24757 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ 24758 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ 24759 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ 24760 _sxn=1, _stxn=1, _styn=1, \ 24761 _sxr=1, _stxr=1, _styr=1, \ 24762 _sxl=1, _stxl=1, _styl=1, \ 24763 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ 24764 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ 24765 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ 24766 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ 24767 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ 24768 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ 24769 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ 24770 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ 24771 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ 24772 _dyn = y2-y1, \ 24773 _dyr = y2-y0, \ 24774 _dyl = y1-y0, \ 24775 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ 24776 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ 24777 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ 24778 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ 24779 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ 24780 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ 24781 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ 24782 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ 24783 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ 24784 cimg::min((int)(img)._height-y-1,y2-y)), \ 24785 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \ 24786 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \ 24787 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \ 24788 _rxn = _dyn?(x2-x1)/_dyn:0, \ 24789 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ 24790 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ 24791 _rxr = _dyr?(x2-x0)/_dyr:0, \ 24792 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ 24793 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ 24794 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ 24795 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ 24796 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ 24797 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ 24798 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ 24799 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ 24800 _counter>=0; --_counter, ++y, \ 24801 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ 24802 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ 24803 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ 24804 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ 24805 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ 24806 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ 24807 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ 24808 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\ 24809 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) 24810 24811 #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \ 24812 for (int y = y0<0?0:y0, \ 24813 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ 24814 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \ 24815 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ 24816 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ 24817 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ 24818 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \ 24819 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ 24820 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ 24821 _sxn=1, _scn=1, _stxn=1, _styn=1, \ 24822 _sxr=1, _scr=1, _stxr=1, _styr=1, \ 24823 _sxl=1, _scl=1, _stxl=1, _styl=1, \ 24824 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \ 24825 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \ 24826 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \ 24827 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \ 24828 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \ 24829 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \ 24830 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ 24831 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ 24832 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ 24833 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ 24834 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ 24835 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ 24836 _dyn = y2-y1, \ 24837 _dyr = y2-y0, \ 24838 _dyl = y1-y0, \ 24839 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ 24840 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ 24841 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ 24842 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \ 24843 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \ 24844 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \ 24845 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ 24846 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ 24847 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ 24848 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ 24849 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ 24850 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ 24851 cimg::min((int)(img)._height-y-1,y2-y)), \ 24852 _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \ 24853 _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \ 24854 _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \ 24855 _rxn = _dyn?(x2-x1)/_dyn:0, \ 24856 _rcn = _dyn?(c2-c1)/_dyn:0, \ 24857 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ 24858 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ 24859 _rxr = _dyr?(x2-x0)/_dyr:0, \ 24860 _rcr = _dyr?(c2-c0)/_dyr:0, \ 24861 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ 24862 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ 24863 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ 24864 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ 24865 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \ 24866 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \ 24867 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ 24868 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ 24869 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ 24870 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \ 24871 _counter>=0; --_counter, ++y, \ 24872 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ 24873 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \ 24874 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ 24875 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ 24876 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \ 24877 txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ 24878 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ 24879 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ 24880 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \ 24881 _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ 24882 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ 24883 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) 24884 24885 #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \ 24886 for (int y = y0<0?0:y0, \ 24887 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \ 24888 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \ 24889 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \ 24890 lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \ 24891 lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \ 24892 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \ 24893 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \ 24894 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \ 24895 lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \ 24896 lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \ 24897 _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \ 24898 _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \ 24899 _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \ 24900 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \ 24901 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \ 24902 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \ 24903 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \ 24904 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \ 24905 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \ 24906 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \ 24907 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \ 24908 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \ 24909 _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \ 24910 _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \ 24911 _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \ 24912 _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \ 24913 _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \ 24914 _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \ 24915 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \ 24916 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \ 24917 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \ 24918 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \ 24919 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \ 24920 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \ 24921 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \ 24922 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \ 24923 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \ 24924 _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \ 24925 _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \ 24926 _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \ 24927 _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \ 24928 _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \ 24929 _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \ 24930 cimg::min((int)(img)._height-y-1,y2-y)), \ 24931 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \ 24932 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \ 24933 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \ 24934 _rxn = _dyn?(x2-x1)/_dyn:0, \ 24935 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \ 24936 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \ 24937 _rlxn = _dyn?(lx2-lx1)/_dyn:0, \ 24938 _rlyn = _dyn?(ly2-ly1)/_dyn:0, \ 24939 _rxr = _dyr?(x2-x0)/_dyr:0, \ 24940 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \ 24941 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \ 24942 _rlxr = _dyr?(lx2-lx0)/_dyr:0, \ 24943 _rlyr = _dyr?(ly2-ly0)/_dyr:0, \ 24944 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \ 24945 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \ 24946 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \ 24947 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \ 24948 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \ 24949 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \ 24950 _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \ 24951 (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \ 24952 _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \ 24953 (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \ 24954 _counter>=0; --_counter, ++y, \ 24955 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \ 24956 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \ 24957 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \ 24958 lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \ 24959 lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \ 24960 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \ 24961 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \ 24962 lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \ 24963 lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \ 24964 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \ 24965 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \ 24966 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \ 24967 _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \ 24968 _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \ 24969 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl)) 24970 24971 // Draw a colored triangle (inner routine, uses bresenham's algorithm). 24972 template<typename tc> 24973 CImg<T>& _draw_triangle(const int x0, const int y0, 24974 const int x1, const int y1, 24975 const int x2, const int y2, 24976 const tc *const color, const float opacity, 24977 const float brightness) { 24978 _draw_scanline(color,opacity); 24979 const float nbrightness = brightness<0?0:(brightness>2?2:brightness); 24980 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; 24981 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); 24982 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2); 24983 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2); 24984 if (ny0<height() && ny2>=0) { 24985 if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0) 24986 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness); 24987 else 24988 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness); 24989 } 24990 return *this; 24991 } 24992 24993 //! Draw a 2d filled colored triangle. 24994 template<typename tc> 24995 CImg<T>& draw_triangle(const int x0, const int y0, 24996 const int x1, const int y1, 24997 const int x2, const int y2, 24998 const tc *const color, const float opacity=1) { 24999 if (!color) 25000 throw CImgArgumentException(_cimg_instance 25001 "draw_triangle : Specified color is (null).", 25002 cimg_instance); 25003 25004 if (is_empty()) return *this; 25005 _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1); 25006 return *this; 25007 } 25008 25009 //! Draw a 2d outlined colored triangle. 25010 template<typename tc> 25011 CImg<T>& draw_triangle(const int x0, const int y0, 25012 const int x1, const int y1, 25013 const int x2, const int y2, 25014 const tc *const color, const float opacity, 25015 const unsigned int pattern) { 25016 if (!color) 25017 throw CImgArgumentException(_cimg_instance 25018 "draw_triangle : Specified color is (null).", 25019 cimg_instance); 25020 25021 if (is_empty()) return *this; 25022 draw_line(x0,y0,x1,y1,color,opacity,pattern,true). 25023 draw_line(x1,y1,x2,y2,color,opacity,pattern,false). 25024 draw_line(x2,y2,x0,y0,color,opacity,pattern,false); 25025 return *this; 25026 } 25027 25028 //! Draw a 2d filled colored triangle, with z-buffering. 25029 template<typename tc> 25030 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 25031 const int x0, const int y0, const float z0, 25032 const int x1, const int y1, const float z1, 25033 const int x2, const int y2, const float z2, 25034 const tc *const color, const float opacity=1, 25035 const float brightness=1) { 25036 if (!color) 25037 throw CImgArgumentException(_cimg_instance 25038 "draw_triangle() : Specified color is (null).", 25039 cimg_instance); 25040 if (!is_sameXY(zbuffer)) 25041 throw CImgArgumentException(_cimg_instance 25042 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 25043 cimg_instance, 25044 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 25045 25046 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 25047 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25048 const float 25049 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), 25050 nbrightness = brightness<0?0:(brightness>2?2:brightness); 25051 const int whd = _width*_height*_depth, offx = _spectrum*whd; 25052 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; 25053 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 25054 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); 25055 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2); 25056 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2); 25057 if (ny0>=height() || ny2<0) return *this; 25058 float 25059 pzl = (nz1 - nz0)/(ny1 - ny0), 25060 pzr = (nz2 - nz0)/(ny2 - ny0), 25061 pzn = (nz2 - nz1)/(ny2 - ny1), 25062 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 25063 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); 25064 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { 25065 if (y==ny1) { zl = nz1; pzl = pzn; } 25066 int xleft = xleft0, xright = xright0; 25067 float zleft = zl, zright = zr; 25068 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright); 25069 const int dx = xright - xleft; 25070 const float pentez = (zright - zleft)/dx; 25071 if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx; 25072 if (xleft<0) xleft = 0; 25073 if (xright>=width()-1) xright = width()-1; 25074 T* ptrd = data(xleft,y,0,0); 25075 float *ptrz = zbuffer.data(xleft,y); 25076 if (opacity>=1) { 25077 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25078 if (zleft>=*ptrz) { 25079 *ptrz = zleft; 25080 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } 25081 ptrd-=offx; 25082 } 25083 zleft+=pentez; 25084 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25085 if (zleft>=*ptrz) { 25086 *ptrz = zleft; 25087 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whd; } 25088 ptrd-=offx; 25089 } 25090 zleft+=pentez; 25091 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25092 if (zleft>=*ptrz) { 25093 *ptrz = zleft; 25094 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whd; } 25095 ptrd-=offx; 25096 } 25097 zleft+=pentez; 25098 } 25099 } else { 25100 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25101 if (zleft>=*ptrz) { 25102 *ptrz = zleft; 25103 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whd; } 25104 ptrd-=offx; 25105 } 25106 zleft+=pentez; 25107 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25108 if (zleft>=*ptrz) { 25109 *ptrz = zleft; 25110 const tc *col = color; cimg_forC(*this,c) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whd; } 25111 ptrd-=offx; 25112 } 25113 zleft+=pentez; 25114 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25115 if (zleft>=*ptrz) { 25116 *ptrz = zleft; 25117 const tc *col = color; 25118 cimg_forC(*this,c) { 25119 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); 25120 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25121 ptrd+=whd; 25122 } 25123 ptrd-=offx; 25124 } 25125 zleft+=pentez; 25126 } 25127 } 25128 zr+=pzr; zl+=pzl; 25129 } 25130 return *this; 25131 } 25132 25133 //! Draw a 2d Gouraud-shaded colored triangle. 25134 /** 25135 \param x0 = X-coordinate of the first corner in the instance image. 25136 \param y0 = Y-coordinate of the first corner in the instance image. 25137 \param x1 = X-coordinate of the second corner in the instance image. 25138 \param y1 = Y-coordinate of the second corner in the instance image. 25139 \param x2 = X-coordinate of the third corner in the instance image. 25140 \param y2 = Y-coordinate of the third corner in the instance image. 25141 \param color = array of spectrum() values of type \c T, defining the global drawing color. 25142 \param brightness0 = brightness of the first corner (in [0,2]). 25143 \param brightness1 = brightness of the second corner (in [0,2]). 25144 \param brightness2 = brightness of the third corner (in [0,2]). 25145 \param opacity = opacity of the drawing. 25146 \note Clipping is supported. 25147 **/ 25148 template<typename tc> 25149 CImg<T>& draw_triangle(const int x0, const int y0, 25150 const int x1, const int y1, 25151 const int x2, const int y2, 25152 const tc *const color, 25153 const float brightness0, 25154 const float brightness1, 25155 const float brightness2, 25156 const float opacity=1) { 25157 if (!color) 25158 throw CImgArgumentException(_cimg_instance 25159 "draw_triangle : Specified color is (null).", 25160 cimg_instance); 25161 25162 if (is_empty()) return *this; 25163 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25164 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 25165 const int whd = _width*_height*_depth, offx = _spectrum*whd-1; 25166 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 25167 nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), 25168 nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), 25169 nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); 25170 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1); 25171 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2); 25172 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2); 25173 if (ny0>=height() || ny2<0) return *this; 25174 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { 25175 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; 25176 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright); 25177 const int 25178 dx = xright - xleft, 25179 dc = cright>cleft?cright - cleft:cleft - cright, 25180 rc = dx?(cright - cleft)/dx:0, 25181 sc = cright>cleft?1:-1, 25182 ndc = dc-(dx?dx*(dc/dx):0); 25183 int errc = dx>>1; 25184 if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx; 25185 if (xleft<0) xleft = 0; 25186 if (xright>=width()-1) xright = width()-1; 25187 T* ptrd = data(xleft,y); 25188 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 25189 const tc *col = color; 25190 cimg_forC(*this,c) { 25191 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); 25192 ptrd+=whd; 25193 } 25194 ptrd-=offx; 25195 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 25196 } else for (int x = xleft; x<=xright; ++x) { 25197 const tc *col = color; 25198 cimg_forC(*this,c) { 25199 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); 25200 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25201 ptrd+=whd; 25202 } 25203 ptrd-=offx; 25204 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 25205 } 25206 } 25207 return *this; 25208 } 25209 25210 //! Draw a 2d Gouraud-shaded colored triangle, with z-buffering. 25211 template<typename tc> 25212 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 25213 const int x0, const int y0, const float z0, 25214 const int x1, const int y1, const float z1, 25215 const int x2, const int y2, const float z2, 25216 const tc *const color, 25217 const float brightness0, 25218 const float brightness1, 25219 const float brightness2, 25220 const float opacity=1) { 25221 if (!color) 25222 throw CImgArgumentException(_cimg_instance 25223 "draw_triangle() : Specified color is (null).", 25224 cimg_instance); 25225 if (!is_sameXY(zbuffer)) 25226 throw CImgArgumentException(_cimg_instance 25227 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 25228 cimg_instance, 25229 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 25230 25231 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 25232 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25233 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 25234 const int whd = _width*_height*_depth, offx = _spectrum*whd; 25235 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 25236 nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), 25237 nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), 25238 nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); 25239 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 25240 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1); 25241 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2); 25242 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2); 25243 if (ny0>=height() || ny2<0) return *this; 25244 float 25245 pzl = (nz1 - nz0)/(ny1 - ny0), 25246 pzr = (nz2 - nz0)/(ny2 - ny0), 25247 pzn = (nz2 - nz1)/(ny2 - ny1), 25248 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 25249 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); 25250 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { 25251 if (y==ny1) { zl = nz1; pzl = pzn; } 25252 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0; 25253 float zleft = zl, zright = zr; 25254 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright); 25255 const int 25256 dx = xright - xleft, 25257 dc = cright>cleft?cright - cleft:cleft - cright, 25258 rc = dx?(cright-cleft)/dx:0, 25259 sc = cright>cleft?1:-1, 25260 ndc = dc-(dx?dx*(dc/dx):0); 25261 const float pentez = (zright - zleft)/dx; 25262 int errc = dx>>1; 25263 if (xleft<0 && dx) { 25264 cleft-=xleft*(cright - cleft)/dx; 25265 zleft-=xleft*(zright - zleft)/dx; 25266 } 25267 if (xleft<0) xleft = 0; 25268 if (xright>=width()-1) xright = width()-1; 25269 T *ptrd = data(xleft,y); 25270 float *ptrz = zbuffer.data(xleft,y); 25271 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { 25272 if (zleft>=*ptrz) { 25273 *ptrz = zleft; 25274 const tc *col = color; 25275 cimg_forC(*this,c) { 25276 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); 25277 ptrd+=whd; 25278 } 25279 ptrd-=offx; 25280 } 25281 zleft+=pentez; 25282 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 25283 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { 25284 if (zleft>=*ptrz) { 25285 *ptrz = zleft; 25286 const tc *col = color; 25287 cimg_forC(*this,c) { 25288 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256); 25289 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25290 ptrd+=whd; 25291 } 25292 ptrd-=offx; 25293 } 25294 zleft+=pentez; 25295 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 25296 } 25297 zr+=pzr; zl+=pzl; 25298 } 25299 return *this; 25300 } 25301 25302 //! Draw a colored triangle with interpolated colors. 25303 template<typename tc1, typename tc2, typename tc3> 25304 CImg<T>& draw_triangle(const int x0, const int y0, 25305 const int x1, const int y1, 25306 const int x2, const int y2, 25307 const tc1 *const color1, 25308 const tc2 *const color2, 25309 const tc3 *const color3, 25310 const float opacity=1) { 25311 const unsigned char one = 1; 25312 cimg_forC(*this,c) get_shared_channel(c).draw_triangle(x0,y0,x1,y1,x2,y2,&one,color1[c],color2[c],color3[c],opacity); 25313 return *this; 25314 } 25315 25316 //! Draw a 2d textured triangle. 25317 /** 25318 \param x0 = X-coordinate of the first corner in the instance image. 25319 \param y0 = Y-coordinate of the first corner in the instance image. 25320 \param x1 = X-coordinate of the second corner in the instance image. 25321 \param y1 = Y-coordinate of the second corner in the instance image. 25322 \param x2 = X-coordinate of the third corner in the instance image. 25323 \param y2 = Y-coordinate of the third corner in the instance image. 25324 \param texture = texture image used to fill the triangle. 25325 \param tx0 = X-coordinate of the first corner in the texture image. 25326 \param ty0 = Y-coordinate of the first corner in the texture image. 25327 \param tx1 = X-coordinate of the second corner in the texture image. 25328 \param ty1 = Y-coordinate of the second corner in the texture image. 25329 \param tx2 = X-coordinate of the third corner in the texture image. 25330 \param ty2 = Y-coordinate of the third corner in the texture image. 25331 \param opacity = opacity of the drawing. 25332 \param brightness = brightness of the drawing (in [0,2]). 25333 \note Clipping is supported, but texture coordinates do not support clipping. 25334 **/ 25335 template<typename tc> 25336 CImg<T>& draw_triangle(const int x0, const int y0, 25337 const int x1, const int y1, 25338 const int x2, const int y2, 25339 const CImg<tc>& texture, 25340 const int tx0, const int ty0, 25341 const int tx1, const int ty1, 25342 const int tx2, const int ty2, 25343 const float opacity=1, 25344 const float brightness=1) { 25345 if (texture._depth>1 || texture._spectrum<_spectrum) 25346 throw CImgArgumentException(_cimg_instance 25347 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 25348 cimg_instance, 25349 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 25350 25351 if (is_empty()) return *this; 25352 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); 25353 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25354 const float 25355 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), 25356 nbrightness = brightness<0?0:(brightness>2?2:brightness); 25357 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 25358 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 25359 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2; 25360 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); 25361 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2); 25362 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2); 25363 if (ny0>=height() || ny2<0) return *this; 25364 _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y, 25365 nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) { 25366 int 25367 xleft = xleft0, xright = xright0, 25368 txleft = txleft0, txright = txright0, 25369 tyleft = tyleft0, tyright = tyright0; 25370 if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright); 25371 const int 25372 dx = xright - xleft, 25373 dtx = txright>txleft?txright - txleft:txleft - txright, 25374 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, 25375 rtx = dx?(txright - txleft)/dx:0, 25376 rty = dx?(tyright - tyleft)/dx:0, 25377 stx = txright>txleft?1:-1, 25378 sty = tyright>tyleft?1:-1, 25379 ndtx = dtx - (dx?dx*(dtx/dx):0), 25380 ndty = dty - (dx?dx*(dty/dx):0); 25381 int errtx = dx>>1, errty = errtx; 25382 if (xleft<0 && dx) { 25383 txleft-=xleft*(txright - txleft)/dx; 25384 tyleft-=xleft*(tyright - tyleft)/dx; 25385 } 25386 if (xleft<0) xleft = 0; 25387 if (xright>=width()-1) xright = width()-1; 25388 T* ptrd = data(xleft,y,0,0); 25389 if (opacity>=1) { 25390 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { 25391 const tc *col = texture.data(txleft,tyleft); 25392 cimg_forC(*this,c) { 25393 *ptrd = (T)*col; 25394 ptrd+=whd; col+=twhd; 25395 } 25396 ptrd-=offx; 25397 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25398 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25399 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { 25400 const tc *col = texture.data(txleft,tyleft); 25401 cimg_forC(*this,c) { 25402 *ptrd = (T)(nbrightness**col); 25403 ptrd+=whd; col+=twhd; 25404 } 25405 ptrd-=offx; 25406 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25407 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25408 } else for (int x = xleft; x<=xright; ++x) { 25409 const tc *col = texture.data(txleft,tyleft); 25410 cimg_forC(*this,c) { 25411 *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); 25412 ptrd+=whd; col+=twhd; 25413 } 25414 ptrd-=offx; 25415 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25416 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25417 } 25418 } else { 25419 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { 25420 const tc *col = texture.data(txleft,tyleft); 25421 cimg_forC(*this,c) { 25422 *ptrd = (T)(nopacity**col + *ptrd*copacity); 25423 ptrd+=whd; col+=twhd; 25424 } 25425 ptrd-=offx; 25426 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25427 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25428 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { 25429 const tc *col = texture.data(txleft,tyleft); 25430 cimg_forC(*this,c) { 25431 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); 25432 ptrd+=whd; col+=twhd; 25433 } 25434 ptrd-=offx; 25435 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25436 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25437 } else for (int x = xleft; x<=xright; ++x) { 25438 const tc *col = texture.data(txleft,tyleft); 25439 cimg_forC(*this,c) { 25440 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); 25441 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25442 ptrd+=whd; col+=twhd; 25443 } 25444 ptrd-=offx; 25445 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 25446 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 25447 } 25448 } 25449 } 25450 return *this; 25451 } 25452 25453 //! Draw a 2d textured triangle, with perspective correction. 25454 template<typename tc> 25455 CImg<T>& draw_triangle(const int x0, const int y0, const float z0, 25456 const int x1, const int y1, const float z1, 25457 const int x2, const int y2, const float z2, 25458 const CImg<tc>& texture, 25459 const int tx0, const int ty0, 25460 const int tx1, const int ty1, 25461 const int tx2, const int ty2, 25462 const float opacity=1, 25463 const float brightness=1) { 25464 if (texture._depth>1 || texture._spectrum<_spectrum) 25465 throw CImgArgumentException(_cimg_instance 25466 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 25467 cimg_instance, 25468 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 25469 25470 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 25471 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); 25472 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25473 const float 25474 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), 25475 nbrightness = brightness<0?0:(brightness>2?2:brightness); 25476 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 25477 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; 25478 float 25479 ntx0 = tx0/z0, nty0 = ty0/z0, 25480 ntx1 = tx1/z1, nty1 = ty1/z1, 25481 ntx2 = tx2/z2, nty2 = ty2/z2, 25482 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 25483 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1); 25484 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2); 25485 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2); 25486 if (ny0>=height() || ny2<0) return *this; 25487 float 25488 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 25489 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 25490 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 25491 ptyl = (nty1 - nty0)/(ny1 - ny0), 25492 ptyr = (nty2 - nty0)/(ny2 - ny0), 25493 ptyn = (nty2 - nty1)/(ny2 - ny1), 25494 pzl = (nz1 - nz0)/(ny1 - ny0), 25495 pzr = (nz2 - nz0)/(ny2 - ny0), 25496 pzn = (nz2 - nz1)/(ny2 - ny1), 25497 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 25498 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 25499 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 25500 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 25501 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 25502 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 25503 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { 25504 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 25505 int xleft = xleft0, xright = xright0; 25506 float 25507 zleft = zl, zright = zr, 25508 txleft = txl, txright = txr, 25509 tyleft = tyl, tyright = tyr; 25510 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright); 25511 const int dx = xright - xleft; 25512 const float 25513 pentez = (zright - zleft)/dx, 25514 pentetx = (txright - txleft)/dx, 25515 pentety = (tyright - tyleft)/dx; 25516 if (xleft<0 && dx) { 25517 zleft-=xleft*(zright - zleft)/dx; 25518 txleft-=xleft*(txright - txleft)/dx; 25519 tyleft-=xleft*(tyright - tyleft)/dx; 25520 } 25521 if (xleft<0) xleft = 0; 25522 if (xright>=width()-1) xright = width()-1; 25523 T* ptrd = data(xleft,y,0,0); 25524 if (opacity>=1) { 25525 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { 25526 const float invz = 1/zleft; 25527 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25528 cimg_forC(*this,c) { 25529 *ptrd = (T)*col; 25530 ptrd+=whd; col+=twhd; 25531 } 25532 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25533 } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) { 25534 const float invz = 1/zleft; 25535 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25536 cimg_forC(*this,c) { 25537 *ptrd = (T)(nbrightness**col); 25538 ptrd+=whd; col+=twhd; 25539 } 25540 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25541 } else for (int x = xleft; x<=xright; ++x) { 25542 const float invz = 1/zleft; 25543 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25544 cimg_forC(*this,c) { 25545 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval); 25546 ptrd+=whd; col+=twhd; 25547 } 25548 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25549 } 25550 } else { 25551 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) { 25552 const float invz = 1/zleft; 25553 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25554 cimg_forC(*this,c) { 25555 *ptrd = (T)(nopacity**col + *ptrd*copacity); 25556 ptrd+=whd; col+=twhd; 25557 } 25558 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25559 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) { 25560 const float invz = 1/zleft; 25561 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25562 cimg_forC(*this,c) { 25563 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); 25564 ptrd+=whd; col+=twhd; 25565 } 25566 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25567 } else for (int x = xleft; x<=xright; ++x) { 25568 const float invz = 1/zleft; 25569 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25570 cimg_forC(*this,c) { 25571 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval); 25572 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25573 ptrd+=whd; col+=twhd; 25574 } 25575 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25576 } 25577 } 25578 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 25579 } 25580 return *this; 25581 } 25582 25583 //! Draw a 2d textured triangle, with z-buffering and perspective correction. 25584 template<typename tc> 25585 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 25586 const int x0, const int y0, const float z0, 25587 const int x1, const int y1, const float z1, 25588 const int x2, const int y2, const float z2, 25589 const CImg<tc>& texture, 25590 const int tx0, const int ty0, 25591 const int tx1, const int ty1, 25592 const int tx2, const int ty2, 25593 const float opacity=1, 25594 const float brightness=1) { 25595 if (!is_sameXY(zbuffer)) 25596 throw CImgArgumentException(_cimg_instance 25597 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 25598 cimg_instance, 25599 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 25600 25601 if (texture._depth>1 || texture._spectrum<_spectrum) 25602 throw CImgArgumentException(_cimg_instance 25603 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 25604 cimg_instance, 25605 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 25606 25607 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 25608 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); 25609 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25610 const float 25611 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), 25612 nbrightness = brightness<0?0:(brightness>2?2:brightness); 25613 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd; 25614 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; 25615 float 25616 ntx0 = tx0/z0, nty0 = ty0/z0, 25617 ntx1 = tx1/z1, nty1 = ty1/z1, 25618 ntx2 = tx2/z2, nty2 = ty2/z2, 25619 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 25620 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1); 25621 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2); 25622 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2); 25623 if (ny0>=height() || ny2<0) return *this; 25624 float 25625 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 25626 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 25627 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 25628 ptyl = (nty1 - nty0)/(ny1 - ny0), 25629 ptyr = (nty2 - nty0)/(ny2 - ny0), 25630 ptyn = (nty2 - nty1)/(ny2 - ny1), 25631 pzl = (nz1 - nz0)/(ny1 - ny0), 25632 pzr = (nz2 - nz0)/(ny2 - ny0), 25633 pzn = (nz2 - nz1)/(ny2 - ny1), 25634 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 25635 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 25636 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 25637 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 25638 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 25639 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 25640 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) { 25641 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 25642 int xleft = xleft0, xright = xright0; 25643 float 25644 zleft = zl, zright = zr, 25645 txleft = txl, txright = txr, 25646 tyleft = tyl, tyright = tyr; 25647 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright); 25648 const int dx = xright - xleft; 25649 const float 25650 pentez = (zright - zleft)/dx, 25651 pentetx = (txright - txleft)/dx, 25652 pentety = (tyright - tyleft)/dx; 25653 if (xleft<0 && dx) { 25654 zleft-=xleft*(zright - zleft)/dx; 25655 txleft-=xleft*(txright - txleft)/dx; 25656 tyleft-=xleft*(tyright - tyleft)/dx; 25657 } 25658 if (xleft<0) xleft = 0; 25659 if (xright>=width()-1) xright = width()-1; 25660 T *ptrd = data(xleft,y,0,0); 25661 float *ptrz = zbuffer.data(xleft,y); 25662 if (opacity>=1) { 25663 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25664 if (zleft>=*ptrz) { 25665 *ptrz = zleft; 25666 const float invz = 1/zleft; 25667 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25668 cimg_forC(*this,c) { 25669 *ptrd = (T)*col; 25670 ptrd+=whd; col+=twhd; 25671 } 25672 ptrd-=offx; 25673 } 25674 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25675 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25676 if (zleft>=*ptrz) { 25677 *ptrz = zleft; 25678 const float invz = 1/zleft; 25679 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25680 cimg_forC(*this,c) { 25681 *ptrd = (T)(nbrightness**col); 25682 ptrd+=whd; col+=twhd; 25683 } 25684 ptrd-=offx; 25685 } 25686 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25687 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25688 if (zleft>=*ptrz) { 25689 *ptrz = zleft; 25690 const float invz = 1/zleft; 25691 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25692 cimg_forC(*this,c) { 25693 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval); 25694 ptrd+=whd; col+=twhd; 25695 } 25696 ptrd-=offx; 25697 } 25698 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25699 } 25700 } else { 25701 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25702 if (zleft>=*ptrz) { 25703 *ptrz = zleft; 25704 const float invz = 1/zleft; 25705 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25706 cimg_forC(*this,c) { 25707 *ptrd = (T)(nopacity**col + *ptrd*copacity); 25708 ptrd+=whd; col+=twhd; 25709 } 25710 ptrd-=offx; 25711 } 25712 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25713 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25714 if (zleft>=*ptrz) { 25715 *ptrz = zleft; 25716 const float invz = 1/zleft; 25717 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25718 cimg_forC(*this,c) { 25719 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity); 25720 ptrd+=whd; col+=twhd; 25721 } 25722 ptrd-=offx; 25723 } 25724 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25725 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25726 if (zleft>=*ptrz) { 25727 *ptrz = zleft; 25728 const float invz = 1/zleft; 25729 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 25730 cimg_forC(*this,c) { 25731 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval); 25732 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25733 ptrd+=whd; col+=twhd; 25734 } 25735 ptrd-=offx; 25736 } 25737 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 25738 } 25739 } 25740 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 25741 } 25742 return *this; 25743 } 25744 25745 //! Draw a 2d Pseudo-Phong-shaded triangle. 25746 /** 25747 \param x0 = X-coordinate of the first corner in the instance image. 25748 \param y0 = Y-coordinate of the first corner in the instance image. 25749 \param x1 = X-coordinate of the second corner in the instance image. 25750 \param y1 = Y-coordinate of the second corner in the instance image. 25751 \param x2 = X-coordinate of the third corner in the instance image. 25752 \param y2 = Y-coordinate of the third corner in the instance image. 25753 \param color = array of spectrum() values of type \c T, defining the global drawing color. 25754 \param light = light image. 25755 \param lx0 = X-coordinate of the first corner in the light image. 25756 \param ly0 = Y-coordinate of the first corner in the light image. 25757 \param lx1 = X-coordinate of the second corner in the light image. 25758 \param ly1 = Y-coordinate of the second corner in the light image. 25759 \param lx2 = X-coordinate of the third corner in the light image. 25760 \param ly2 = Y-coordinate of the third corner in the light image. 25761 \param opacity = opacity of the drawing. 25762 \note Clipping is supported, but texture coordinates do not support clipping. 25763 **/ 25764 template<typename tc, typename tl> 25765 CImg<T>& draw_triangle(const int x0, const int y0, 25766 const int x1, const int y1, 25767 const int x2, const int y2, 25768 const tc *const color, 25769 const CImg<tl>& light, 25770 const int lx0, const int ly0, 25771 const int lx1, const int ly1, 25772 const int lx2, const int ly2, 25773 const float opacity=1) { 25774 if (!color) 25775 throw CImgArgumentException(_cimg_instance 25776 "draw_triangle : Specified color is (null).", 25777 cimg_instance); 25778 if (light._depth>1 || light._spectrum<_spectrum) 25779 throw CImgArgumentException(_cimg_instance 25780 "draw_triangle() : Invalid specified light texture (%u,%u,%u,%u,%p).", 25781 cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); 25782 25783 if (is_empty()) return *this; 25784 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 25785 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25786 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 25787 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 25788 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; 25789 const int whd = _width*_height*_depth, offx = _spectrum*whd-1; 25790 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1); 25791 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2); 25792 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2); 25793 if (ny0>=height() || ny2<0) return *this; 25794 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, 25795 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { 25796 int 25797 xleft = xleft0, xright = xright0, 25798 lxleft = lxleft0, lxright = lxright0, 25799 lyleft = lyleft0, lyright = lyright0; 25800 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright); 25801 const int 25802 dx = xright - xleft, 25803 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright, 25804 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, 25805 rlx = dx?(lxright - lxleft)/dx:0, 25806 rly = dx?(lyright - lyleft)/dx:0, 25807 slx = lxright>lxleft?1:-1, 25808 sly = lyright>lyleft?1:-1, 25809 ndlx = dlx - (dx?dx*(dlx/dx):0), 25810 ndly = dly - (dx?dx*(dly/dx):0); 25811 int errlx = dx>>1, errly = errlx; 25812 if (xleft<0 && dx) { 25813 lxleft-=xleft*(lxright - lxleft)/dx; 25814 lyleft-=xleft*(lyright - lyleft)/dx; 25815 } 25816 if (xleft<0) xleft = 0; 25817 if (xright>=width()-1) xright = width()-1; 25818 T* ptrd = data(xleft,y,0,0); 25819 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 25820 const tc *col = color; 25821 cimg_forC(*this,c) { 25822 const tl l = light(lxleft,lyleft,c); 25823 *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval)); 25824 ptrd+=whd; 25825 } 25826 ptrd-=offx; 25827 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 25828 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 25829 } else for (int x = xleft; x<=xright; ++x) { 25830 const tc *col = color; 25831 cimg_forC(*this,c) { 25832 const tl l = light(lxleft,lyleft,c); 25833 const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval)); 25834 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25835 ptrd+=whd; 25836 } 25837 ptrd-=offx; 25838 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 25839 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 25840 } 25841 } 25842 return *this; 25843 } 25844 25845 //! Draw a 2d Pseudo-Phong-shaded triangle, with z-buffering. 25846 template<typename tc, typename tl> 25847 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 25848 const int x0, const int y0, const float z0, 25849 const int x1, const int y1, const float z1, 25850 const int x2, const int y2, const float z2, 25851 const tc *const color, 25852 const CImg<tl>& light, 25853 const int lx0, const int ly0, 25854 const int lx1, const int ly1, 25855 const int lx2, const int ly2, 25856 const float opacity=1) { 25857 if (!color) 25858 throw CImgArgumentException(_cimg_instance 25859 "draw_triangle() : Specified color is (null).", 25860 cimg_instance); 25861 if (light._depth>1 || light._spectrum<_spectrum) 25862 throw CImgArgumentException(_cimg_instance 25863 "draw_triangle() : Invalid specified light texture (%u,%u,%u,%u,%p).", 25864 cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); 25865 if (!is_sameXY(zbuffer)) 25866 throw CImgArgumentException(_cimg_instance 25867 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 25868 cimg_instance, 25869 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 25870 25871 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 25872 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color, 25873 +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 25874 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 25875 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 25876 const int whd = _width*_height*_depth, offx = _spectrum*whd; 25877 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 25878 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; 25879 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 25880 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1); 25881 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2); 25882 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2); 25883 if (ny0>=height() || ny2<0) return *this; 25884 float 25885 pzl = (nz1 - nz0)/(ny1 - ny0), 25886 pzr = (nz2 - nz0)/(ny2 - ny0), 25887 pzn = (nz2 - nz1)/(ny2 - ny1), 25888 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 25889 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))); 25890 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, 25891 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { 25892 if (y==ny1) { zl = nz1; pzl = pzn; } 25893 int 25894 xleft = xleft0, xright = xright0, 25895 lxleft = lxleft0, lxright = lxright0, 25896 lyleft = lyleft0, lyright = lyright0; 25897 float zleft = zl, zright = zr; 25898 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright); 25899 const int 25900 dx = xright - xleft, 25901 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright, 25902 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, 25903 rlx = dx?(lxright - lxleft)/dx:0, 25904 rly = dx?(lyright - lyleft)/dx:0, 25905 slx = lxright>lxleft?1:-1, 25906 sly = lyright>lyleft?1:-1, 25907 ndlx = dlx - (dx?dx*(dlx/dx):0), 25908 ndly = dly - (dx?dx*(dly/dx):0); 25909 const float pentez = (zright - zleft)/dx; 25910 int errlx = dx>>1, errly = errlx; 25911 if (xleft<0 && dx) { 25912 zleft-=xleft*(zright - zleft)/dx; 25913 lxleft-=xleft*(lxright - lxleft)/dx; 25914 lyleft-=xleft*(lyright - lyleft)/dx; 25915 } 25916 if (xleft<0) xleft = 0; 25917 if (xright>=width()-1) xright = width()-1; 25918 T *ptrd = data(xleft,y,0,0); 25919 float *ptrz = zbuffer.data(xleft,y); 25920 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25921 if (zleft>=*ptrz) { 25922 *ptrz = zleft; 25923 const tc *col = color; 25924 cimg_forC(*this,c) { 25925 const tl l = light(lxleft,lyleft,c); 25926 const tc cval = *(col++); 25927 *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval); 25928 ptrd+=whd; 25929 } 25930 ptrd-=offx; 25931 } 25932 zleft+=pentez; 25933 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 25934 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 25935 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 25936 if (zleft>=*ptrz) { 25937 *ptrz = zleft; 25938 const tc *col = color; 25939 cimg_forC(*this,c) { 25940 const tl l = light(lxleft,lyleft,c); 25941 const tc cval = *(col++); 25942 const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval); 25943 *ptrd = (T)(nopacity*val + *ptrd*copacity); 25944 ptrd+=whd; 25945 } 25946 ptrd-=offx; 25947 } 25948 zleft+=pentez; 25949 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 25950 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 25951 } 25952 zr+=pzr; zl+=pzl; 25953 } 25954 return *this; 25955 } 25956 25957 //! Draw a 2d Gouraud-shaded textured triangle. 25958 /** 25959 \param x0 = X-coordinate of the first corner in the instance image. 25960 \param y0 = Y-coordinate of the first corner in the instance image. 25961 \param x1 = X-coordinate of the second corner in the instance image. 25962 \param y1 = Y-coordinate of the second corner in the instance image. 25963 \param x2 = X-coordinate of the third corner in the instance image. 25964 \param y2 = Y-coordinate of the third corner in the instance image. 25965 \param texture = texture image used to fill the triangle. 25966 \param tx0 = X-coordinate of the first corner in the texture image. 25967 \param ty0 = Y-coordinate of the first corner in the texture image. 25968 \param tx1 = X-coordinate of the second corner in the texture image. 25969 \param ty1 = Y-coordinate of the second corner in the texture image. 25970 \param tx2 = X-coordinate of the third corner in the texture image. 25971 \param ty2 = Y-coordinate of the third corner in the texture image. 25972 \param brightness0 = brightness value of the first corner. 25973 \param brightness1 = brightness value of the second corner. 25974 \param brightness2 = brightness value of the third corner. 25975 \param opacity = opacity of the drawing. 25976 \note Clipping is supported, but texture coordinates do not support clipping. 25977 **/ 25978 template<typename tc> 25979 CImg<T>& draw_triangle(const int x0, const int y0, 25980 const int x1, const int y1, 25981 const int x2, const int y2, 25982 const CImg<tc>& texture, 25983 const int tx0, const int ty0, 25984 const int tx1, const int ty1, 25985 const int tx2, const int ty2, 25986 const float brightness0, 25987 const float brightness1, 25988 const float brightness2, 25989 const float opacity=1) { 25990 if (texture._depth>1 || texture._spectrum<_spectrum) 25991 throw CImgArgumentException(_cimg_instance 25992 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 25993 cimg_instance, 25994 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 25995 25996 if (is_empty()) return *this; 25997 if (is_overlapped(texture)) 25998 return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity); 25999 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26000 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26001 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 26002 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26003 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, 26004 nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), 26005 nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), 26006 nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); 26007 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1); 26008 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2); 26009 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2); 26010 if (ny0>=height() || ny2<0) return *this; 26011 _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y, 26012 nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) { 26013 int 26014 xleft = xleft0, xright = xright0, 26015 cleft = cleft0, cright = cright0, 26016 txleft = txleft0, txright = txright0, 26017 tyleft = tyleft0, tyright = tyright0; 26018 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright); 26019 const int 26020 dx = xright - xleft, 26021 dc = cright>cleft?cright - cleft:cleft - cright, 26022 dtx = txright>txleft?txright - txleft:txleft - txright, 26023 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, 26024 rc = dx?(cright - cleft)/dx:0, 26025 rtx = dx?(txright - txleft)/dx:0, 26026 rty = dx?(tyright - tyleft)/dx:0, 26027 sc = cright>cleft?1:-1, 26028 stx = txright>txleft?1:-1, 26029 sty = tyright>tyleft?1:-1, 26030 ndc = dc - (dx?dx*(dc/dx):0), 26031 ndtx = dtx - (dx?dx*(dtx/dx):0), 26032 ndty = dty - (dx?dx*(dty/dx):0); 26033 int errc = dx>>1, errtx = errc, errty = errc; 26034 if (xleft<0 && dx) { 26035 cleft-=xleft*(cright - cleft)/dx; 26036 txleft-=xleft*(txright - txleft)/dx; 26037 tyleft-=xleft*(tyright - tyleft)/dx; 26038 } 26039 if (xleft<0) xleft = 0; 26040 if (xright>=width()-1) xright = width()-1; 26041 T* ptrd = data(xleft,y,0,0); 26042 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 26043 const tc *col = texture.data(txleft,tyleft); 26044 cimg_forC(*this,c) { 26045 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26046 ptrd+=whd; col+=twhd; 26047 } 26048 ptrd-=offx; 26049 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26050 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 26051 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 26052 } else for (int x = xleft; x<=xright; ++x) { 26053 const tc *col = texture.data(txleft,tyleft); 26054 cimg_forC(*this,c) { 26055 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26056 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26057 ptrd+=whd; col+=twhd; 26058 } 26059 ptrd-=offx; 26060 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26061 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 26062 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 26063 } 26064 } 26065 return *this; 26066 } 26067 26068 //! Draw a 2d Gouraud-shaded textured triangle, with perspective correction. 26069 template<typename tc> 26070 CImg<T>& draw_triangle(const int x0, const int y0, const float z0, 26071 const int x1, const int y1, const float z1, 26072 const int x2, const int y2, const float z2, 26073 const CImg<tc>& texture, 26074 const int tx0, const int ty0, 26075 const int tx1, const int ty1, 26076 const int tx2, const int ty2, 26077 const float brightness0, 26078 const float brightness1, 26079 const float brightness2, 26080 const float opacity=1) { 26081 if (texture._depth>1 || texture._spectrum<_spectrum) 26082 throw CImgArgumentException(_cimg_instance 26083 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 26084 cimg_instance, 26085 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 26086 26087 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 26088 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, 26089 brightness0,brightness1,brightness2,opacity); 26090 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26091 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26092 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 26093 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26094 nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), 26095 nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), 26096 nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); 26097 float 26098 ntx0 = tx0/z0, nty0 = ty0/z0, 26099 ntx1 = tx1/z1, nty1 = ty1/z1, 26100 ntx2 = tx2/z2, nty2 = ty2/z2, 26101 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 26102 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1); 26103 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2); 26104 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2); 26105 if (ny0>=height() || ny2<0) return *this; 26106 float 26107 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 26108 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 26109 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 26110 ptyl = (nty1 - nty0)/(ny1 - ny0), 26111 ptyr = (nty2 - nty0)/(ny2 - ny0), 26112 ptyn = (nty2 - nty1)/(ny2 - ny1), 26113 pzl = (nz1 - nz0)/(ny1 - ny0), 26114 pzr = (nz2 - nz0)/(ny2 - ny0), 26115 pzn = (nz2 - nz1)/(ny2 - ny1), 26116 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 26117 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 26118 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 26119 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 26120 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 26121 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 26122 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { 26123 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 26124 int 26125 xleft = xleft0, xright = xright0, 26126 cleft = cleft0, cright = cright0; 26127 float 26128 zleft = zl, zright = zr, 26129 txleft = txl, txright = txr, 26130 tyleft = tyl, tyright = tyr; 26131 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright); 26132 const int 26133 dx = xright - xleft, 26134 dc = cright>cleft?cright - cleft:cleft - cright, 26135 rc = dx?(cright - cleft)/dx:0, 26136 sc = cright>cleft?1:-1, 26137 ndc = dc - (dx?dx*(dc/dx):0); 26138 const float 26139 pentez = (zright - zleft)/dx, 26140 pentetx = (txright - txleft)/dx, 26141 pentety = (tyright - tyleft)/dx; 26142 int errc = dx>>1; 26143 if (xleft<0 && dx) { 26144 cleft-=xleft*(cright - cleft)/dx; 26145 zleft-=xleft*(zright - zleft)/dx; 26146 txleft-=xleft*(txright - txleft)/dx; 26147 tyleft-=xleft*(tyright - tyleft)/dx; 26148 } 26149 if (xleft<0) xleft = 0; 26150 if (xright>=width()-1) xright = width()-1; 26151 T* ptrd = data(xleft,y,0,0); 26152 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 26153 const float invz = 1/zleft; 26154 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26155 cimg_forC(*this,c) { 26156 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26157 ptrd+=whd; col+=twhd; 26158 } 26159 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26160 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26161 } else for (int x = xleft; x<=xright; ++x) { 26162 const float invz = 1/zleft; 26163 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26164 cimg_forC(*this,c) { 26165 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26166 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26167 ptrd+=whd; col+=twhd; 26168 } 26169 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26170 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26171 } 26172 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 26173 } 26174 return *this; 26175 } 26176 26177 //! Draw a 2d Gouraud-shaded textured triangle, with z-buffering and perspective correction. 26178 template<typename tc> 26179 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 26180 const int x0, const int y0, const float z0, 26181 const int x1, const int y1, const float z1, 26182 const int x2, const int y2, const float z2, 26183 const CImg<tc>& texture, 26184 const int tx0, const int ty0, 26185 const int tx1, const int ty1, 26186 const int tx2, const int ty2, 26187 const float brightness0, 26188 const float brightness1, 26189 const float brightness2, 26190 const float opacity=1) { 26191 if (!is_sameXY(zbuffer)) 26192 throw CImgArgumentException(_cimg_instance 26193 "draw_line() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 26194 cimg_instance, 26195 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 26196 26197 if (texture._depth>1 || texture._spectrum<_spectrum) 26198 throw CImgArgumentException(_cimg_instance 26199 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 26200 cimg_instance, 26201 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 26202 26203 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 26204 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, 26205 brightness0,brightness1,brightness2,opacity); 26206 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26207 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26208 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd; 26209 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26210 nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f), 26211 nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f), 26212 nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f); 26213 float 26214 ntx0 = tx0/z0, nty0 = ty0/z0, 26215 ntx1 = tx1/z1, nty1 = ty1/z1, 26216 ntx2 = tx2/z2, nty2 = ty2/z2, 26217 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 26218 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1); 26219 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2); 26220 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2); 26221 if (ny0>=height() || ny2<0) return *this; 26222 float 26223 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 26224 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 26225 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 26226 ptyl = (nty1 - nty0)/(ny1 - ny0), 26227 ptyr = (nty2 - nty0)/(ny2 - ny0), 26228 ptyn = (nty2 - nty1)/(ny2 - ny1), 26229 pzl = (nz1 - nz0)/(ny1 - ny0), 26230 pzr = (nz2 - nz0)/(ny2 - ny0), 26231 pzn = (nz2 - nz1)/(ny2 - ny1), 26232 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 26233 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 26234 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 26235 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 26236 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 26237 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 26238 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) { 26239 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 26240 int 26241 xleft = xleft0, xright = xright0, 26242 cleft = cleft0, cright = cright0; 26243 float 26244 zleft = zl, zright = zr, 26245 txleft = txl, txright = txr, 26246 tyleft = tyl, tyright = tyr; 26247 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright); 26248 const int 26249 dx = xright - xleft, 26250 dc = cright>cleft?cright - cleft:cleft - cright, 26251 rc = dx?(cright - cleft)/dx:0, 26252 sc = cright>cleft?1:-1, 26253 ndc = dc - (dx?dx*(dc/dx):0); 26254 const float 26255 pentez = (zright - zleft)/dx, 26256 pentetx = (txright - txleft)/dx, 26257 pentety = (tyright - tyleft)/dx; 26258 int errc = dx>>1; 26259 if (xleft<0 && dx) { 26260 cleft-=xleft*(cright - cleft)/dx; 26261 zleft-=xleft*(zright - zleft)/dx; 26262 txleft-=xleft*(txright - txleft)/dx; 26263 tyleft-=xleft*(tyright - tyleft)/dx; 26264 } 26265 if (xleft<0) xleft = 0; 26266 if (xright>=width()-1) xright = width()-1; 26267 T* ptrd = data(xleft,y); 26268 float *ptrz = zbuffer.data(xleft,y); 26269 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { 26270 if (zleft>=*ptrz) { 26271 *ptrz = zleft; 26272 const float invz = 1/zleft; 26273 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26274 cimg_forC(*this,c) { 26275 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26276 ptrd+=whd; col+=twhd; 26277 } 26278 ptrd-=offx; 26279 } 26280 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26281 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26282 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) { 26283 if (zleft>=*ptrz) { 26284 *ptrz = zleft; 26285 const float invz = 1/zleft; 26286 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26287 cimg_forC(*this,c) { 26288 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256); 26289 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26290 ptrd+=whd; col+=twhd; 26291 } 26292 ptrd-=offx; 26293 } 26294 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26295 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0); 26296 } 26297 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 26298 } 26299 return *this; 26300 } 26301 26302 //! Draw a 2d Pseudo-Phong-shaded textured triangle. 26303 /** 26304 \param x0 = X-coordinate of the first corner in the instance image. 26305 \param y0 = Y-coordinate of the first corner in the instance image. 26306 \param x1 = X-coordinate of the second corner in the instance image. 26307 \param y1 = Y-coordinate of the second corner in the instance image. 26308 \param x2 = X-coordinate of the third corner in the instance image. 26309 \param y2 = Y-coordinate of the third corner in the instance image. 26310 \param texture = texture image used to fill the triangle. 26311 \param tx0 = X-coordinate of the first corner in the texture image. 26312 \param ty0 = Y-coordinate of the first corner in the texture image. 26313 \param tx1 = X-coordinate of the second corner in the texture image. 26314 \param ty1 = Y-coordinate of the second corner in the texture image. 26315 \param tx2 = X-coordinate of the third corner in the texture image. 26316 \param ty2 = Y-coordinate of the third corner in the texture image. 26317 \param light = light image. 26318 \param lx0 = X-coordinate of the first corner in the light image. 26319 \param ly0 = Y-coordinate of the first corner in the light image. 26320 \param lx1 = X-coordinate of the second corner in the light image. 26321 \param ly1 = Y-coordinate of the second corner in the light image. 26322 \param lx2 = X-coordinate of the third corner in the light image. 26323 \param ly2 = Y-coordinate of the third corner in the light image. 26324 \param opacity = opacity of the drawing. 26325 \note Clipping is supported, but texture coordinates do not support clipping. 26326 **/ 26327 template<typename tc, typename tl> 26328 CImg<T>& draw_triangle(const int x0, const int y0, 26329 const int x1, const int y1, 26330 const int x2, const int y2, 26331 const CImg<tc>& texture, 26332 const int tx0, const int ty0, 26333 const int tx1, const int ty1, 26334 const int tx2, const int ty2, 26335 const CImg<tl>& light, 26336 const int lx0, const int ly0, 26337 const int lx1, const int ly1, 26338 const int lx2, const int ly2, 26339 const float opacity=1) { 26340 if (texture._depth>1 || texture._spectrum<_spectrum) 26341 throw CImgArgumentException(_cimg_instance 26342 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 26343 cimg_instance, 26344 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 26345 if (light._depth>1 || light._spectrum<_spectrum) 26346 throw CImgArgumentException(_cimg_instance 26347 "draw_triangle() : Invalid specified light texture (%u,%u,%u,%u,%p).", 26348 cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); 26349 26350 if (is_empty()) return *this; 26351 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26352 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26353 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26354 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26355 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 26356 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26357 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2, 26358 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; 26359 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1); 26360 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2); 26361 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2); 26362 if (ny0>=height() || ny2<0) return *this; 26363 _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y, 26364 nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) { 26365 int 26366 xleft = xleft0, xright = xright0, 26367 lxleft = lxleft0, lxright = lxright0, 26368 lyleft = lyleft0, lyright = lyright0, 26369 txleft = txleft0, txright = txright0, 26370 tyleft = tyleft0, tyright = tyright0; 26371 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright); 26372 const int 26373 dx = xright - xleft, 26374 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright, 26375 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, 26376 dtx = txright>txleft?txright - txleft:txleft - txright, 26377 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright, 26378 rlx = dx?(lxright - lxleft)/dx:0, 26379 rly = dx?(lyright - lyleft)/dx:0, 26380 rtx = dx?(txright - txleft)/dx:0, 26381 rty = dx?(tyright - tyleft)/dx:0, 26382 slx = lxright>lxleft?1:-1, 26383 sly = lyright>lyleft?1:-1, 26384 stx = txright>txleft?1:-1, 26385 sty = tyright>tyleft?1:-1, 26386 ndlx = dlx - (dx?dx*(dlx/dx):0), 26387 ndly = dly - (dx?dx*(dly/dx):0), 26388 ndtx = dtx - (dx?dx*(dtx/dx):0), 26389 ndty = dty - (dx?dx*(dty/dx):0); 26390 int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx; 26391 if (xleft<0 && dx) { 26392 lxleft-=xleft*(lxright - lxleft)/dx; 26393 lyleft-=xleft*(lyright - lyleft)/dx; 26394 txleft-=xleft*(txright - txleft)/dx; 26395 tyleft-=xleft*(tyright - tyleft)/dx; 26396 } 26397 if (xleft<0) xleft = 0; 26398 if (xright>=width()-1) xright = width()-1; 26399 T* ptrd = data(xleft,y,0,0); 26400 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 26401 const tc *col = texture.data(txleft,tyleft); 26402 cimg_forC(*this,c) { 26403 const tl l = light(lxleft,lyleft,c); 26404 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26405 ptrd+=whd; col+=twhd; 26406 } 26407 ptrd-=offx; 26408 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26409 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26410 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 26411 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 26412 } else for (int x = xleft; x<=xright; ++x) { 26413 const tc *col = texture.data(txleft,tyleft); 26414 cimg_forC(*this,c) { 26415 const tl l = light(lxleft,lyleft,c); 26416 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26417 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26418 ptrd+=whd; col+=twhd; 26419 } 26420 ptrd-=offx; 26421 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26422 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26423 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0); 26424 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0); 26425 } 26426 } 26427 return *this; 26428 } 26429 26430 //! Draw a 2d Pseudo-Phong-shaded textured triangle, with perspective correction. 26431 template<typename tc, typename tl> 26432 CImg<T>& draw_triangle(const int x0, const int y0, const float z0, 26433 const int x1, const int y1, const float z1, 26434 const int x2, const int y2, const float z2, 26435 const CImg<tc>& texture, 26436 const int tx0, const int ty0, 26437 const int tx1, const int ty1, 26438 const int tx2, const int ty2, 26439 const CImg<tl>& light, 26440 const int lx0, const int ly0, 26441 const int lx1, const int ly1, 26442 const int lx2, const int ly2, 26443 const float opacity=1) { 26444 if (texture._depth>1 || texture._spectrum<_spectrum) 26445 throw CImgArgumentException(_cimg_instance 26446 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 26447 cimg_instance, 26448 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 26449 if (light._depth>1 || light._spectrum<_spectrum) 26450 throw CImgArgumentException(_cimg_instance 26451 "draw_triangle() : Invalid specified light texture (%u,%u,%u,%u,%p).", 26452 cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); 26453 26454 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 26455 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26456 if (is_overlapped(light)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26457 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26458 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26459 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd-1; 26460 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26461 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; 26462 float 26463 ntx0 = tx0/z0, nty0 = ty0/z0, 26464 ntx1 = tx1/z1, nty1 = ty1/z1, 26465 ntx2 = tx2/z2, nty2 = ty2/z2, 26466 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 26467 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1); 26468 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2); 26469 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2); 26470 if (ny0>=height() || ny2<0) return *this; 26471 float 26472 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 26473 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 26474 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 26475 ptyl = (nty1 - nty0)/(ny1 - ny0), 26476 ptyr = (nty2 - nty0)/(ny2 - ny0), 26477 ptyn = (nty2 - nty1)/(ny2 - ny1), 26478 pzl = (nz1 - nz0)/(ny1 - ny0), 26479 pzr = (nz2 - nz0)/(ny2 - ny0), 26480 pzn = (nz2 - nz1)/(ny2 - ny1), 26481 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 26482 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 26483 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 26484 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 26485 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 26486 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 26487 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, 26488 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { 26489 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 26490 int 26491 xleft = xleft0, xright = xright0, 26492 lxleft = lxleft0, lxright = lxright0, 26493 lyleft = lyleft0, lyright = lyright0; 26494 float 26495 zleft = zl, zright = zr, 26496 txleft = txl, txright = txr, 26497 tyleft = tyl, tyright = tyr; 26498 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright); 26499 const int 26500 dx = xright - xleft, 26501 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright, 26502 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, 26503 rlx = dx?(lxright - lxleft)/dx:0, 26504 rly = dx?(lyright - lyleft)/dx:0, 26505 slx = lxright>lxleft?1:-1, 26506 sly = lyright>lyleft?1:-1, 26507 ndlx = dlx - (dx?dx*(dlx/dx):0), 26508 ndly = dly - (dx?dx*(dly/dx):0); 26509 const float 26510 pentez = (zright - zleft)/dx, 26511 pentetx = (txright - txleft)/dx, 26512 pentety = (tyright - tyleft)/dx; 26513 int errlx = dx>>1, errly = errlx; 26514 if (xleft<0 && dx) { 26515 zleft-=xleft*(zright - zleft)/dx; 26516 lxleft-=xleft*(lxright - lxleft)/dx; 26517 lyleft-=xleft*(lyright - lyleft)/dx; 26518 txleft-=xleft*(txright - txleft)/dx; 26519 tyleft-=xleft*(tyright - tyleft)/dx; 26520 } 26521 if (xleft<0) xleft = 0; 26522 if (xright>=width()-1) xright = width()-1; 26523 T* ptrd = data(xleft,y,0,0); 26524 if (opacity>=1) for (int x = xleft; x<=xright; ++x) { 26525 const float invz = 1/zleft; 26526 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26527 cimg_forC(*this,c) { 26528 const tl l = light(lxleft,lyleft,c); 26529 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26530 ptrd+=whd; col+=twhd; 26531 } 26532 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26533 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26534 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26535 } else for (int x = xleft; x<=xright; ++x) { 26536 const float invz = 1/zleft; 26537 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26538 cimg_forC(*this,c) { 26539 const tl l = light(lxleft,lyleft,c); 26540 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26541 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26542 ptrd+=whd; col+=twhd; 26543 } 26544 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26545 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26546 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26547 } 26548 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 26549 } 26550 return *this; 26551 } 26552 26553 //! Draw a 2d Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction. 26554 template<typename tc, typename tl> 26555 CImg<T>& draw_triangle(CImg<floatT>& zbuffer, 26556 const int x0, const int y0, const float z0, 26557 const int x1, const int y1, const float z1, 26558 const int x2, const int y2, const float z2, 26559 const CImg<tc>& texture, 26560 const int tx0, const int ty0, 26561 const int tx1, const int ty1, 26562 const int tx2, const int ty2, 26563 const CImg<tl>& light, 26564 const int lx0, const int ly0, 26565 const int lx1, const int ly1, 26566 const int lx2, const int ly2, 26567 const float opacity=1) { 26568 if (!is_sameXY(zbuffer)) 26569 throw CImgArgumentException(_cimg_instance 26570 "draw_triangle() : Instance and specified Z-buffer (%u,%u,%u,%u,%p) have different dimensions.", 26571 cimg_instance, 26572 zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); 26573 if (texture._depth>1 || texture._spectrum<_spectrum) 26574 throw CImgArgumentException(_cimg_instance 26575 "draw_triangle() : Invalid specified texture (%u,%u,%u,%u,%p).", 26576 cimg_instance, 26577 texture._width,texture._height,texture._depth,texture._spectrum,texture._data); 26578 if (light._depth>1 || light._spectrum<_spectrum) 26579 throw CImgArgumentException(_cimg_instance 26580 "draw_triangle() : Invalid specified light texture (%u,%u,%u,%u,%p).", 26581 cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); 26582 26583 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; 26584 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, 26585 +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26586 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, 26587 texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); 26588 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max()); 26589 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26590 const int whd = _width*_height*_depth, twhd = texture._width*texture._height*texture._depth, offx = _spectrum*whd; 26591 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2, 26592 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2; 26593 float 26594 ntx0 = tx0/z0, nty0 = ty0/z0, 26595 ntx1 = tx1/z1, nty1 = ty1/z1, 26596 ntx2 = tx2/z2, nty2 = ty2/z2, 26597 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2; 26598 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1); 26599 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2); 26600 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2); 26601 if (ny0>=height() || ny2<0) return *this; 26602 float 26603 ptxl = (ntx1 - ntx0)/(ny1 - ny0), 26604 ptxr = (ntx2 - ntx0)/(ny2 - ny0), 26605 ptxn = (ntx2 - ntx1)/(ny2 - ny1), 26606 ptyl = (nty1 - nty0)/(ny1 - ny0), 26607 ptyr = (nty2 - nty0)/(ny2 - ny0), 26608 ptyn = (nty2 - nty1)/(ny2 - ny1), 26609 pzl = (nz1 - nz0)/(ny1 - ny0), 26610 pzr = (nz2 - nz0)/(ny2 - ny0), 26611 pzn = (nz2 - nz1)/(ny2 - ny1), 26612 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)), 26613 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)), 26614 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)), 26615 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))), 26616 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))), 26617 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1))); 26618 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y, 26619 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) { 26620 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; } 26621 int 26622 xleft = xleft0, xright = xright0, 26623 lxleft = lxleft0, lxright = lxright0, 26624 lyleft = lyleft0, lyright = lyright0; 26625 float 26626 zleft = zl, zright = zr, 26627 txleft = txl, txright = txr, 26628 tyleft = tyl, tyright = tyr; 26629 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright); 26630 const int 26631 dx = xright - xleft, 26632 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright, 26633 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright, 26634 rlx = dx?(lxright - lxleft)/dx:0, 26635 rly = dx?(lyright - lyleft)/dx:0, 26636 slx = lxright>lxleft?1:-1, 26637 sly = lyright>lyleft?1:-1, 26638 ndlx = dlx - (dx?dx*(dlx/dx):0), 26639 ndly = dly - (dx?dx*(dly/dx):0); 26640 const float 26641 pentez = (zright - zleft)/dx, 26642 pentetx = (txright - txleft)/dx, 26643 pentety = (tyright - tyleft)/dx; 26644 int errlx = dx>>1, errly = errlx; 26645 if (xleft<0 && dx) { 26646 zleft-=xleft*(zright - zleft)/dx; 26647 lxleft-=xleft*(lxright - lxleft)/dx; 26648 lyleft-=xleft*(lyright - lyleft)/dx; 26649 txleft-=xleft*(txright - txleft)/dx; 26650 tyleft-=xleft*(tyright - tyleft)/dx; 26651 } 26652 if (xleft<0) xleft = 0; 26653 if (xright>=width()-1) xright = width()-1; 26654 T* ptrd = data(xleft,y); 26655 float *ptrz = zbuffer.data(xleft,y); 26656 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 26657 if (zleft>=*ptrz) { 26658 *ptrz = zleft; 26659 const float invz = 1/zleft; 26660 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26661 cimg_forC(*this,c) { 26662 const tl l = light(lxleft,lyleft,c); 26663 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26664 ptrd+=whd; col+=twhd; 26665 } 26666 ptrd-=offx; 26667 } 26668 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26669 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26670 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26671 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) { 26672 if (zleft>=*ptrz) { 26673 *ptrz = zleft; 26674 const float invz = 1/zleft; 26675 const tc *col = texture.data((int)(txleft*invz),(int)(tyleft*invz)); 26676 cimg_forC(*this,c) { 26677 const tl l = light(lxleft,lyleft,c); 26678 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval); 26679 *ptrd = (T)(nopacity*val + *ptrd*copacity); 26680 ptrd+=whd; col+=twhd; 26681 } 26682 ptrd-=offx; 26683 } 26684 zleft+=pentez; txleft+=pentetx; tyleft+=pentety; 26685 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0); 26686 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0); 26687 } 26688 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl; 26689 } 26690 return *this; 26691 } 26692 26693 //! Draw a 4d filled rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0,\c c0)-(\c x1,\c y1,\c z1,\c c1). 26694 /** 26695 \param x0 X-coordinate of the upper-left rectangle corner. 26696 \param y0 Y-coordinate of the upper-left rectangle corner. 26697 \param z0 Z-coordinate of the upper-left rectangle corner. 26698 \param c0 C-coordinate of the upper-left rectangle corner. 26699 \param x1 X-coordinate of the lower-right rectangle corner. 26700 \param y1 Y-coordinate of the lower-right rectangle corner. 26701 \param z1 Z-coordinate of the lower-right rectangle corner. 26702 \param c1 C-coordinate of the lower-right rectangle corner. 26703 \param val Scalar value used to fill the rectangle area. 26704 \param opacity Drawing opacity (optional). 26705 \note 26706 - Clipping is supported. 26707 **/ 26708 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int c0, 26709 const int x1, const int y1, const int z1, const int c1, 26710 const T val, const float opacity=1) { 26711 if (is_empty()) return *this; 26712 const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bc = (c0<c1); 26713 const int 26714 nx0 = bx?x0:x1, nx1 = bx?x1:x0, 26715 ny0 = by?y0:y1, ny1 = by?y1:y0, 26716 nz0 = bz?z0:z1, nz1 = bz?z1:z0, 26717 nc0 = bc?c0:c1, nc1 = bc?c1:c0; 26718 const int 26719 lX = (1 + nx1 - nx0) + (nx1>=width()?width() - 1 - nx1:0) + (nx0<0?nx0:0), 26720 lY = (1 + ny1 - ny0) + (ny1>=height()?height() - 1 - ny1:0) + (ny0<0?ny0:0), 26721 lZ = (1 + nz1 - nz0) + (nz1>=depth()?depth() - 1 - nz1:0) + (nz0<0?nz0:0), 26722 lC = (1 + nc1 - nc0) + (nc1>=spectrum()?spectrum() - 1 - nc1:0) + (nc0<0?nc0:0); 26723 const unsigned int offX = _width - lX, offY = _width*(_height - lY), offZ = _width*_height*(_depth - lZ); 26724 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 26725 T *ptrd = data(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nc0<0?0:nc0); 26726 if (lX>0 && lY>0 && lZ>0 && lC>0) 26727 for (int v = 0; v<lC; ++v) { 26728 for (int z = 0; z<lZ; ++z) { 26729 for (int y = 0; y<lY; ++y) { 26730 if (opacity>=1) { 26731 if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; } 26732 else { std::memset(ptrd,(int)val,lX); ptrd+=_width; } 26733 } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; } 26734 } 26735 ptrd+=offY; 26736 } 26737 ptrd+=offZ; 26738 } 26739 return *this; 26740 } 26741 26742 //! Draw a 3d filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1). 26743 /** 26744 \param x0 X-coordinate of the upper-left rectangle corner. 26745 \param y0 Y-coordinate of the upper-left rectangle corner. 26746 \param z0 Z-coordinate of the upper-left rectangle corner. 26747 \param x1 X-coordinate of the lower-right rectangle corner. 26748 \param y1 Y-coordinate of the lower-right rectangle corner. 26749 \param z1 Z-coordinate of the lower-right rectangle corner. 26750 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 26751 \param opacity Drawing opacity (optional). 26752 \note 26753 - Clipping is supported. 26754 **/ 26755 template<typename tc> 26756 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, 26757 const int x1, const int y1, const int z1, 26758 const tc *const color, const float opacity=1) { 26759 if (!color) 26760 throw CImgArgumentException(_cimg_instance 26761 "draw_rectangle : Specified color is (null).", 26762 cimg_instance); 26763 26764 if (is_empty()) return *this; 26765 cimg_forC(*this,c) draw_rectangle(x0,y0,z0,c,x1,y1,z1,c,color[c],opacity); 26766 return *this; 26767 } 26768 26769 //! Draw a 3d outlined colored rectangle in the instance image. 26770 template<typename tc> 26771 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, 26772 const int x1, const int y1, const int z1, 26773 const tc *const color, const float opacity, 26774 const unsigned int pattern) { 26775 return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true). 26776 draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false). 26777 draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false). 26778 draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false). 26779 draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true). 26780 draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false). 26781 draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false). 26782 draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false). 26783 draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true). 26784 draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true). 26785 draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true). 26786 draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true); 26787 } 26788 26789 //! Draw a 2d filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). 26790 /** 26791 \param x0 X-coordinate of the upper-left rectangle corner. 26792 \param y0 Y-coordinate of the upper-left rectangle corner. 26793 \param x1 X-coordinate of the lower-right rectangle corner. 26794 \param y1 Y-coordinate of the lower-right rectangle corner. 26795 \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. 26796 \param opacity Drawing opacity (optional). 26797 \note 26798 - Clipping is supported. 26799 **/ 26800 template<typename tc> 26801 CImg<T>& draw_rectangle(const int x0, const int y0, 26802 const int x1, const int y1, 26803 const tc *const color, const float opacity=1) { 26804 return draw_rectangle(x0,y0,0,x1,y1,_depth-1,color,opacity); 26805 } 26806 26807 //! Draw a 2d outlined colored rectangle. 26808 template<typename tc> 26809 CImg<T>& draw_rectangle(const int x0, const int y0, 26810 const int x1, const int y1, 26811 const tc *const color, const float opacity, 26812 const unsigned int pattern) { 26813 if (is_empty()) return *this; 26814 if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true); 26815 if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true); 26816 const bool bx = (x0<x1), by = (y0<y1); 26817 const int 26818 nx0 = bx?x0:x1, nx1 = bx?x1:x0, 26819 ny0 = by?y0:y1, ny1 = by?y1:y0; 26820 if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true). 26821 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false); 26822 return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true). 26823 draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false). 26824 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false). 26825 draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false); 26826 } 26827 26828 //! Draw a filled polygon in the instance image. 26829 template<typename t, typename tc> 26830 CImg<T>& draw_polygon(const CImg<t>& points, 26831 const tc *const color, const float opacity=1) { 26832 if (!color) 26833 throw CImgArgumentException(_cimg_instance 26834 "draw_polygon() : Specified color is (null).", 26835 cimg_instance); 26836 26837 if (is_empty() || !points || points._width<3) return *this; 26838 26839 // Normalize 2d input coordinates. 26840 CImg<intT> npoints(points._width,2); 26841 int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1); 26842 unsigned int nb_points = 1; 26843 for (unsigned int p = 1; p<points._width; ++p) { 26844 const int nx = (int)points(p,0), ny = (int)points(p,1); 26845 if (nx!=x || ny!=y) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; x = nx; y = ny; } 26846 } 26847 26848 if (nb_points==3) return draw_triangle((int)npoints(0,0),(int)npoints(0,1), 26849 (int)npoints(1,0),(int)npoints(1,1), 26850 (int)npoints(2,0),(int)npoints(2,1),color,opacity); 26851 // Draw polygon segments. 26852 _draw_scanline(color,opacity); 26853 int 26854 xmax = 0, xmin = (int)npoints.get_shared_points(0,nb_points-1,0).min_max(xmax), 26855 ymax = 0, ymin = (int)npoints.get_shared_points(0,nb_points-1,1).min_max(ymax); 26856 if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this; 26857 if (ymin==ymax) return _draw_scanline(xmin,xmax,ymin,color,opacity); 26858 const unsigned int 26859 nymin = ymin<0?0:(unsigned int)ymin, 26860 nymax = ymax>=height()?_height-1:(unsigned int)ymax, 26861 dy = 1 + nymax - nymin; 26862 CImg<intT> X(1+2*nb_points,dy,1,1,0), tmp; 26863 int cx = (int)npoints(0,0), cy = (int)npoints(0,1); 26864 unsigned int cp = 0; 26865 for (unsigned int p = 0; p<nb_points; ++p) { 26866 const unsigned int np = (p!=nb_points-1)?p+1:0, ap = (np!=nb_points-1)?np+1:0; 26867 const int 26868 nx = (int)npoints(np,0), ny = (int)npoints(np,1), ay = (int)npoints(ap,1), 26869 y0 = cy - nymin, y1 = ny - nymin; 26870 if (y0!=y1) { 26871 const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0; 26872 for (int x = cx, y = y0, _sx = 1, _sy = 1, 26873 _dx = nx>cx?nx-cx:((_sx=-1),cx-nx), 26874 _dy = y1>y0?y1-y0:((_sy=-1),y0-y1), 26875 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy), 26876 _err = _dx>>1, 26877 _rx = _dy?(nx-cx)/_dy:0; 26878 _counter>=countermin; 26879 --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0)) 26880 if (y>=0 && y<(int)dy) X(++X(0,y),y) = x; 26881 cp = np; cx = nx; cy = ny; 26882 } else { 26883 const int pp = (cp?cp-1:nb_points-1), py = (int)npoints(pp,1); 26884 if (y0>=0 && y0<(int)dy && (!p || (cy>py && ay>cy) || (cy<py && ay<cy))) X(++X(0,y0),y0) = nx; 26885 if (cy!=ay) { cp = np; cx = nx; cy = ny; } 26886 } 26887 } 26888 26889 // Draw polygon scanlines. 26890 for (int y = 0; y<(int)dy; ++y) { 26891 tmp.assign(X.data(1,y),X(0,y),1,1,1,true).sort(); 26892 for (int i = 1; i<=X(0,y); ) { 26893 const int xb = X(i++,y), xe = X(i++,y); 26894 _draw_scanline(xb,xe,nymin+y,color,opacity); 26895 } 26896 } 26897 26898 return *this; 26899 } 26900 26901 //! Draw a outlined polygon in the instance image. 26902 template<typename t, typename tc> 26903 CImg<T>& draw_polygon(const CImg<t>& points, 26904 const tc *const color, const float opacity, const unsigned int pattern) { 26905 if (is_empty() || !points || points._width<3) return *this; 26906 bool ninit_hatch = true; 26907 switch (points._height) { 26908 case 0 : case 1 : 26909 throw CImgArgumentException(_cimg_instance 26910 "draw_polygon() : Invalid specified point set.", 26911 cimg_instance); 26912 case 2 : { // 2d version. 26913 CImg<intT> npoints(points._width,2); 26914 int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1); 26915 unsigned int nb_points = 1; 26916 for (unsigned int p = 1; p<points._width; ++p) { 26917 const int nx = (int)points(p,0), ny = (int)points(p,1); 26918 if (nx!=x || ny!=y) { npoints(nb_points,0) = nx; npoints(nb_points++,1) = ny; x = nx; y = ny; } 26919 } 26920 const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1); 26921 int ox = x0, oy = y0; 26922 for (unsigned int i = 1; i<nb_points; ++i) { 26923 const int x = (int)npoints(i,0), y = (int)npoints(i,1); 26924 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch); 26925 ninit_hatch = false; 26926 ox = x; oy = y; 26927 } 26928 draw_line(ox,oy,x0,y0,color,opacity,pattern,false); 26929 } break; 26930 default : { // 3d version. 26931 CImg<intT> npoints(points._width,3); 26932 int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1), z = npoints(0,2) = (int)points(0,2); 26933 unsigned int nb_points = 1; 26934 for (unsigned int p = 1; p<points._width; ++p) { 26935 const int nx = (int)points(p,0), ny = (int)points(p,1), nz = (int)points(p,2); 26936 if (nx!=x || ny!=y || nz!=z) { npoints(nb_points,0) = nx; npoints(nb_points,1) = ny; npoints(nb_points++,2) = nz; x = nx; y = ny; z = nz; } 26937 } 26938 const int x0 = (int)npoints(0,0), y0 = (int)npoints(0,1), z0 = (int)npoints(0,2); 26939 int ox = x0, oy = y0, oz = z0; 26940 for (unsigned int i = 1; i<nb_points; ++i) { 26941 const int x = (int)npoints(i,0), y = (int)npoints(i,1), z = (int)npoints(i,2); 26942 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch); 26943 ninit_hatch = false; 26944 ox = x; oy = y; oz = z; 26945 } 26946 draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false); 26947 } 26948 } 26949 return *this; 26950 } 26951 26952 //! Draw a filled circle. 26953 /** 26954 \param x0 X-coordinate of the circle center. 26955 \param y0 Y-coordinate of the circle center. 26956 \param radius Circle radius. 26957 \param color Array of spectrum() values of type \c T, defining the drawing color. 26958 \param opacity Drawing opacity. 26959 \note 26960 - Circle version of the Bresenham's algorithm is used. 26961 **/ 26962 template<typename tc> 26963 CImg<T>& draw_circle(const int x0, const int y0, int radius, 26964 const tc *const color, const float opacity=1) { 26965 if (!color) 26966 throw CImgArgumentException(_cimg_instance 26967 "draw_circle : Specified color is (null).", 26968 cimg_instance); 26969 26970 if (is_empty()) return *this; 26971 _draw_scanline(color,opacity); 26972 if (radius<0 || x0-radius>=width() || y0+radius<0 || y0-radius>=height()) return *this; 26973 if (y0>=0 && y0<height()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity); 26974 for (int f = 1-radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) { 26975 if (f>=0) { 26976 const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y; 26977 if (y1>=0 && y1<height()) _draw_scanline(x1,x2,y1,color,opacity); 26978 if (y2>=0 && y2<height()) _draw_scanline(x1,x2,y2,color,opacity); 26979 f+=(ddFy+=2); --y; 26980 } 26981 const bool no_diag = y!=(x++); 26982 ++(f+=(ddFx+=2)); 26983 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x; 26984 if (no_diag) { 26985 if (y1>=0 && y1<height()) _draw_scanline(x1,x2,y1,color,opacity); 26986 if (y2>=0 && y2<height()) _draw_scanline(x1,x2,y2,color,opacity); 26987 } 26988 } 26989 return *this; 26990 } 26991 26992 //! Draw an outlined circle. 26993 /** 26994 \param x0 X-coordinate of the circle center. 26995 \param y0 Y-coordinate of the circle center. 26996 \param radius Circle radius. 26997 \param color Array of spectrum() values of type \c T, defining the drawing color. 26998 \param opacity Drawing opacity. 26999 **/ 27000 template<typename tc> 27001 CImg<T>& draw_circle(const int x0, const int y0, int radius, 27002 const tc *const color, const float opacity, 27003 const unsigned int) { 27004 if (!color) 27005 throw CImgArgumentException(_cimg_instance 27006 "draw_circle : Specified color is (null).", 27007 cimg_instance); 27008 27009 if (is_empty()) return *this; 27010 if (radius<0 || x0-radius>=width() || y0+radius<0 || y0-radius>=height()) return *this; 27011 if (!radius) return draw_point(x0,y0,color,opacity); 27012 draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity). 27013 draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity); 27014 if (radius==1) return *this; 27015 for (int f = 1-radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) { 27016 if (f>=0) { f+=(ddFy+=2); --y; } 27017 ++x; ++(f+=(ddFx+=2)); 27018 if (x!=y+1) { 27019 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x, x3 = x0-x, x4 = x0+x, y3 = y0-y, y4 = y0+y; 27020 draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity). 27021 draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity); 27022 if (x!=y) 27023 draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity). 27024 draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity); 27025 } 27026 } 27027 return *this; 27028 } 27029 27030 // Draw a 2d ellipse (inner routine). 27031 template<typename tc> 27032 CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, 27033 const tc *const color, const float opacity, 27034 const unsigned int pattern) { 27035 if (!color) 27036 throw CImgArgumentException(_cimg_instance 27037 "draw_ellipse : Specified color is (null).", 27038 cimg_instance); 27039 27040 if (is_empty()) return *this; 27041 _draw_scanline(color,opacity); 27042 const float 27043 nr1 = cimg::abs(r1), nr2 = cimg::abs(r2), 27044 nangle = (float)(angle*cimg::PI/180), 27045 u = (float)std::cos(nangle), 27046 v = (float)std::sin(nangle), 27047 rmax = cimg::max(nr1,nr2), 27048 l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2), 27049 l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2), 27050 a = l1*u*u + l2*v*v, 27051 b = u*v*(l1-l2), 27052 c = l1*v*v + l2*u*u; 27053 const int 27054 yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)), 27055 tymin = y0 - yb - 1, 27056 tymax = y0 + yb + 1, 27057 ymin = tymin<0?0:tymin, 27058 ymax = tymax>=height()?_height-1:tymax; 27059 int oxmin = 0, oxmax = 0; 27060 bool first_line = true; 27061 for (int y = ymin; y<=ymax; ++y) { 27062 const float 27063 Y = y-y0 + (y<y0?0.5f:-0.5f), 27064 delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax), 27065 sdelta = delta>0?(float)std::sqrt(delta)/a:0.0f, 27066 bY = b*Y/a, 27067 fxmin = x0-0.5f-bY-sdelta, 27068 fxmax = x0+0.5f-bY+sdelta; 27069 const int xmin = (int)fxmin, xmax = (int)fxmax; 27070 if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity); 27071 else { 27072 if (first_line) { 27073 if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity); 27074 else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity); 27075 first_line = false; 27076 } else { 27077 if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity); 27078 else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity); 27079 if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity); 27080 else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity); 27081 if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity); 27082 } 27083 } 27084 oxmin = xmin; oxmax = xmax; 27085 } 27086 return *this; 27087 } 27088 27089 //! Draw a filled ellipse. 27090 /** 27091 \param x0 = X-coordinate of the ellipse center. 27092 \param y0 = Y-coordinate of the ellipse center. 27093 \param r1 = First radius of the ellipse. 27094 \param r2 = Second radius of the ellipse. 27095 \param angle = Angle of the first radius. 27096 \param color = array of spectrum() values of type \c T, defining the drawing color. 27097 \param opacity = opacity of the drawing. 27098 **/ 27099 template<typename tc> 27100 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, 27101 const tc *const color, const float opacity=1) { 27102 return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U); 27103 } 27104 27105 //! Draw a filled ellipse. 27106 /** 27107 \param x0 = X-coordinate of the ellipse center. 27108 \param y0 = Y-coordinate of the ellipse center. 27109 \param tensor = Diffusion tensor describing the ellipse. 27110 \param color = array of spectrum() values of type \c T, defining the drawing color. 27111 \param opacity = opacity of the drawing. 27112 **/ 27113 template<typename t, typename tc> 27114 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor, 27115 const tc *const color, const float opacity=1) { 27116 CImgList<t> eig = tensor.get_symmetric_eigen(); 27117 const CImg<t> &val = eig[0], &vec = eig[1]; 27118 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity); 27119 } 27120 27121 //! Draw an outlined ellipse. 27122 /** 27123 \param x0 = X-coordinate of the ellipse center. 27124 \param y0 = Y-coordinate of the ellipse center. 27125 \param r1 = First radius of the ellipse. 27126 \param r2 = Second radius of the ellipse. 27127 \param ru = X-coordinate of the orientation vector related to the first radius. 27128 \param rv = Y-coordinate of the orientation vector related to the first radius. 27129 \param color = array of spectrum() values of type \c T, defining the drawing color. 27130 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. 27131 \param opacity = opacity of the drawing. 27132 **/ 27133 template<typename tc> 27134 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, 27135 const tc *const color, const float opacity, const unsigned int pattern) { 27136 if (pattern) _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,pattern); 27137 return *this; 27138 } 27139 27140 //! Draw an outlined ellipse. 27141 /** 27142 \param x0 = X-coordinate of the ellipse center. 27143 \param y0 = Y-coordinate of the ellipse center. 27144 \param tensor = Diffusion tensor describing the ellipse. 27145 \param color = array of spectrum() values of type \c T, defining the drawing color. 27146 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. 27147 \param opacity = opacity of the drawing. 27148 **/ 27149 template<typename t, typename tc> 27150 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor, 27151 const tc *const color, const float opacity, 27152 const unsigned int pattern) { 27153 CImgList<t> eig = tensor.get_symmetric_eigen(); 27154 const CImg<t> &val = eig[0], &vec = eig[1]; 27155 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern); 27156 } 27157 27158 //! Draw an image. 27159 /** 27160 \param sprite Sprite image. 27161 \param x0 X-coordinate of the sprite position. 27162 \param y0 Y-coordinate of the sprite position. 27163 \param z0 Z-coordinate of the sprite position. 27164 \param c0 C-coordinate of the sprite position. 27165 \param opacity Drawing opacity (optional). 27166 \note 27167 - Clipping is supported. 27168 **/ 27169 template<typename t> 27170 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0, 27171 const CImg<t>& sprite, const float opacity=1) { 27172 if (!sprite) 27173 throw CImgArgumentException(_cimg_instance 27174 "draw_image() : Empty specified sprite.", 27175 cimg_instance); 27176 27177 if (is_empty()) return *this; 27178 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); 27179 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); 27180 const int 27181 lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), 27182 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), 27183 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), 27184 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); 27185 const t 27186 *ptrs = sprite._data - 27187 (bx?x0:0) - 27188 (by?y0*sprite.width():0) - 27189 (bz?z0*sprite.width()*sprite.height():0) - 27190 (bc?c0*sprite.width()*sprite.height()*sprite.depth():0); 27191 const unsigned int 27192 offX = _width - lX, soffX = sprite._width - lX, 27193 offY = _width*(_height - lY), soffY = sprite._width*(sprite._height - lY), 27194 offZ = _width*_height*(_depth - lZ), soffZ = sprite._width*sprite._height*(sprite._depth - lZ); 27195 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 27196 if (lX>0 && lY>0 && lZ>0 && lC>0) { 27197 T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); 27198 for (int v = 0; v<lC; ++v) { 27199 for (int z = 0; z<lZ; ++z) { 27200 for (int y = 0; y<lY; ++y) { 27201 if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++); 27202 else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; } 27203 ptrd+=offX; ptrs+=soffX; 27204 } 27205 ptrd+=offY; ptrs+=soffY; 27206 } 27207 ptrd+=offZ; ptrs+=soffZ; 27208 } 27209 } 27210 return *this; 27211 } 27212 27213 // Optimized version (internal). 27214 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0, 27215 const CImg<T>& sprite, const float opacity=1) { 27216 if (!sprite) 27217 throw CImgArgumentException(_cimg_instance 27218 "draw_image() : Empty specified sprite.", 27219 cimg_instance); 27220 27221 if (is_empty()) return *this; 27222 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); 27223 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); 27224 const int 27225 lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), 27226 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), 27227 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), 27228 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); 27229 const T 27230 *ptrs = sprite._data - 27231 (bx?x0:0) - 27232 (by?y0*sprite.width():0) - 27233 (bz?z0*sprite.width()*sprite.height():0) - 27234 (bc?c0*sprite.width()*sprite.height()*sprite.depth():0); 27235 const unsigned int 27236 offX = _width - lX, soffX = sprite._width - lX, 27237 offY = _width*(_height - lY), soffY = sprite._width*(sprite._height - lY), 27238 offZ = _width*_height*(_depth - lZ), soffZ = sprite._width*sprite._height*(sprite._depth - lZ), 27239 slX = lX*sizeof(T); 27240 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 27241 if (lX>0 && lY>0 && lZ>0 && lC>0) { 27242 T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); 27243 for (int v = 0; v<lC; ++v) { 27244 for (int z = 0; z<lZ; ++z) { 27245 if (opacity>=1) for (int y = 0; y<lY; ++y) { std::memcpy(ptrd,ptrs,slX); ptrd+=_width; ptrs+=sprite._width; } 27246 else for (int y = 0; y<lY; ++y) { 27247 for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; } 27248 ptrd+=offX; ptrs+=soffX; 27249 } 27250 ptrd+=offY; ptrs+=soffY; 27251 } 27252 ptrd+=offZ; ptrs+=soffZ; 27253 } 27254 } 27255 return *this; 27256 } 27257 27258 //! Draw an image. 27259 template<typename t> 27260 CImg<T>& draw_image(const int x0, const int y0, const int z0, 27261 const CImg<t>& sprite, const float opacity=1) { 27262 return draw_image(x0,y0,z0,0,sprite,opacity); 27263 } 27264 27265 //! Draw an image. 27266 template<typename t> 27267 CImg<T>& draw_image(const int x0, const int y0, 27268 const CImg<t>& sprite, const float opacity=1) { 27269 return draw_image(x0,y0,0,sprite,opacity); 27270 } 27271 27272 //! Draw an image. 27273 template<typename t> 27274 CImg<T>& draw_image(const int x0, 27275 const CImg<t>& sprite, const float opacity=1) { 27276 return draw_image(x0,0,sprite,opacity); 27277 } 27278 27279 //! Draw an image. 27280 template<typename t> 27281 CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) { 27282 return draw_image(0,sprite,opacity); 27283 } 27284 27285 //! Draw a sprite image in the instance image (masked version). 27286 /** 27287 \param sprite Sprite image. 27288 \param mask Mask image. 27289 \param x0 X-coordinate of the sprite position in the instance image. 27290 \param y0 Y-coordinate of the sprite position in the instance image. 27291 \param z0 Z-coordinate of the sprite position in the instance image. 27292 \param c0 C-coordinate of the sprite position in the instance image. 27293 \param mask_valmax Maximum pixel value of the mask image \c mask (optional). 27294 \param opacity Drawing opacity. 27295 \note 27296 - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite. 27297 - Clipping is supported. 27298 - Dimensions along x,y and z of \p sprite and \p mask must be the same. 27299 **/ 27300 template<typename ti, typename tm> 27301 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int c0, 27302 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1, 27303 const float mask_valmax=1) { 27304 if (!sprite) 27305 throw CImgArgumentException(_cimg_instance 27306 "draw_image() : Empty specified sprite.", 27307 cimg_instance); 27308 if (!mask) 27309 throw CImgArgumentException(_cimg_instance 27310 "draw_image() : Empty specified mask.", 27311 cimg_instance); 27312 27313 if (is_empty()) return *this; 27314 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_valmax); 27315 if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_valmax); 27316 if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth) 27317 throw CImgArgumentException(_cimg_instance 27318 "draw_image() : Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have incompatible dimensions.", 27319 cimg_instance, 27320 sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data, 27321 mask._width,mask._height,mask._depth,mask._spectrum,mask._data); 27322 27323 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bc = (c0<0); 27324 const int 27325 lX = sprite.width() - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0) + (bx?x0:0), 27326 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), 27327 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), 27328 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); 27329 const int 27330 coff = -(bx?x0:0)-(by?y0*mask.width():0)-(bz?z0*mask.width()*mask.height():0)-(bc?c0*mask.width()*mask.height()*mask.depth():0), 27331 ssize = mask.width()*mask.height()*mask.depth(); 27332 const ti *ptrs = sprite._data + coff; 27333 const tm *ptrm = mask._data + coff; 27334 const unsigned int 27335 offX = _width - lX, soffX = sprite._width - lX, 27336 offY = _width*(_height - lY), soffY = sprite._width*(sprite._height - lY), 27337 offZ = _width*_height*(_depth - lZ), soffZ = sprite._width*sprite._height*(sprite._depth - lZ); 27338 if (lX>0 && lY>0 && lZ>0 && lC>0) { 27339 T *ptrd = data(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,c0<0?0:c0); 27340 for (int c = 0; c<lC; ++c) { 27341 ptrm = mask._data + (ptrm - mask._data)%ssize; 27342 for (int z = 0; z<lZ; ++z) { 27343 for (int y = 0; y<lY; ++y) { 27344 for (int x = 0; x<lX; ++x) { 27345 const float mopacity = (float)(*(ptrm++)*opacity), 27346 nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0); 27347 *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax); 27348 ++ptrd; 27349 } 27350 ptrd+=offX; ptrs+=soffX; ptrm+=soffX; 27351 } 27352 ptrd+=offY; ptrs+=soffY; ptrm+=soffY; 27353 } 27354 ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ; 27355 } 27356 } 27357 return *this; 27358 } 27359 27360 //! Draw an image. 27361 template<typename ti, typename tm> 27362 CImg<T>& draw_image(const int x0, const int y0, const int z0, 27363 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1, 27364 const float mask_valmax=1) { 27365 return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax); 27366 } 27367 27368 //! Draw an image. 27369 template<typename ti, typename tm> 27370 CImg<T>& draw_image(const int x0, const int y0, 27371 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1, 27372 const float mask_valmax=1) { 27373 return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax); 27374 } 27375 27376 //! Draw an image. 27377 template<typename ti, typename tm> 27378 CImg<T>& draw_image(const int x0, 27379 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1, 27380 const float mask_valmax=1) { 27381 return draw_image(x0,0,sprite,mask,opacity,mask_valmax); 27382 } 27383 27384 //! Draw an image. 27385 template<typename ti, typename tm> 27386 CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1, 27387 const float mask_valmax=1) { 27388 return draw_image(0,sprite,mask,opacity,mask_valmax); 27389 } 27390 27391 //! Draw a text. 27392 /** 27393 \param x0 X-coordinate of the text in the instance image. 27394 \param y0 Y-coordinate of the text in the instance image. 27395 \param foreground_color Array of spectrum() values of type \c T, defining the foreground color (0 means 'transparent'). 27396 \param background_color Array of spectrum() values of type \c T, defining the background color (0 means 'transparent'). 27397 \param font Font used for drawing text. 27398 \param opacity Drawing opacity. 27399 \param format 'printf'-style format string, followed by arguments. 27400 \note Clipping is supported. 27401 **/ 27402 template<typename tc1, typename tc2, typename t> 27403 CImg<T>& draw_text(const int x0, const int y0, 27404 const char *const text, 27405 const tc1 *const foreground_color, const tc2 *const background_color, 27406 const float opacity, const CImgList<t>& font, ...) { 27407 if (!font) return *this; 27408 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); 27409 std::vsprintf(tmp,text,ap); va_end(ap); 27410 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font); 27411 } 27412 27413 template<typename tc, typename t> 27414 CImg<T>& draw_text(const int x0, const int y0, 27415 const char *const text, 27416 const tc *const foreground_color, const int, 27417 const float opacity, const CImgList<t>& font, ...) { 27418 if (!font) return *this; 27419 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); 27420 std::vsprintf(tmp,text,ap); va_end(ap); 27421 return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font); 27422 } 27423 27424 template<typename tc, typename t> 27425 CImg<T>& draw_text(const int x0, const int y0, 27426 const char *const text, 27427 const int, const tc *const background_color, 27428 const float opacity, const CImgList<t>& font, ...) { 27429 if (!font) return *this; 27430 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font); 27431 std::vsprintf(tmp,text,ap); va_end(ap); 27432 return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font); 27433 } 27434 27435 //! Draw a text. 27436 /** 27437 \param x0 X-coordinate of the text in the instance image. 27438 \param y0 Y-coordinate of the text in the instance image. 27439 \param foreground_color Array of spectrum() values of type \c T, defining the foreground color (0 means 'transparent'). 27440 \param background_color Array of spectrum() values of type \c T, defining the background color (0 means 'transparent'). 27441 \param font_size Size of the font (exact match for 13,24,32,57). 27442 \param opacity Drawing opacity. 27443 \param format 'printf'-style format string, followed by arguments. 27444 \note Clipping is supported. 27445 **/ 27446 template<typename tc1, typename tc2> 27447 CImg<T>& draw_text(const int x0, const int y0, 27448 const char *const text, 27449 const tc1 *const foreground_color, const tc2 *const background_color, 27450 const float opacity=1, const unsigned int font_height=13, ...) { 27451 if (!font_height) return *this; 27452 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_height); std::vsprintf(tmp,text,ap); va_end(ap); 27453 static CImgList<floatT> font; 27454 const unsigned int 27455 ref_height = font_height<=13?13:font_height<=28?24:font_height<=32?32:57, 27456 padding_x = font_height<=18?1:font_height<=32?2:3; 27457 if (!font || font[0]._height!=font_height) { 27458 font = CImgList<floatT>::font(ref_height,true); 27459 font[0].assign(1,font_height); 27460 if (ref_height==font_height) cimglist_for(font,l) font[l].resize(font[l]._width + padding_x,-100,-100,-100,0); 27461 } 27462 if (ref_height!=font_height) for (const char *ptrs = tmp; *ptrs; ++ptrs) { 27463 const unsigned int _c = (unsigned int)(unsigned char)*ptrs; 27464 if (_c<font._width) { 27465 CImg<floatT> &c = font[_c]; 27466 if (c._height!=font_height) { 27467 c.resize(cimg::max(1U,c._width*font_height/c._height),font_height,-100,-100,c._height>font_height?2:5); 27468 c.resize(c._width + padding_x,-100,-100,-100,0); 27469 } 27470 } 27471 if (_c+256U<font._width) { 27472 CImg<floatT> &c = font[_c+256]; 27473 if (c._height!=font_height) { 27474 c.resize(cimg::max(1U,c._width*font_height/c._height),font_height,-100,-100,c._height>font_height?2:5); 27475 c.resize(c._width + padding_x,-100,-100,-100,0); 27476 } 27477 } 27478 } 27479 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font); 27480 } 27481 27482 template<typename tc> 27483 CImg<T>& draw_text(const int x0, const int y0, 27484 const char *const text, 27485 const tc *const foreground_color, const int background_color=0, 27486 const float opacity=1, const unsigned int font_height=13, ...) { 27487 if (!font_height) return *this; 27488 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_height); std::vsprintf(tmp,text,ap); va_end(ap); 27489 return draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font_height); 27490 } 27491 27492 template<typename tc> 27493 CImg<T>& draw_text(const int x0, const int y0, 27494 const char *const text, 27495 const int, const tc *const background_color, 27496 const float opacity=1, const unsigned int font_height=13, ...) { 27497 if (!font_height) return *this; 27498 char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_height); std::vsprintf(tmp,text,ap); va_end(ap); 27499 return draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font_height); 27500 } 27501 27502 // Draw a text (internal routine). 27503 template<typename tc1, typename tc2, typename t> 27504 CImg<T>& _draw_text(const int x0, const int y0, 27505 const char *const text, 27506 const tc1 *const foreground_color, const tc2 *const background_color, 27507 const float opacity, const CImgList<t>& font) { 27508 if (!text) return *this; 27509 if (!font) 27510 throw CImgArgumentException(_cimg_instance 27511 "draw_text() : Empty specified font.", 27512 cimg_instance); 27513 27514 const unsigned int text_length = std::strlen(text); 27515 if (is_empty()) { 27516 // If needed, pre-compute necessary size of the image 27517 int x = 0, y = 0, w = 0; 27518 unsigned char c = 0; 27519 for (unsigned int i = 0; i<text_length; ++i) { 27520 c = text[i]; 27521 switch (c) { 27522 case '\n' : y+=font[' ']._height; if (x>w) w = x; x = 0; break; 27523 case '\t' : x+=4*font[' ']._width; break; 27524 default : if (c<font._width) x+=font[c]._width; 27525 } 27526 } 27527 if (x!=0 || c=='\n') { 27528 if (x>w) w=x; 27529 y+=font[' ']._height; 27530 } 27531 assign(x0+w,y0+y,1,font[' ']._spectrum,0); 27532 if (background_color) cimg_forC(*this,c) get_shared_channel(c).fill((T)background_color[c]); 27533 } 27534 27535 int x = x0, y = y0; 27536 CImg<t> letter; 27537 for (unsigned int i = 0; i<text_length; ++i) { 27538 const unsigned char c = text[i]; 27539 switch (c) { 27540 case '\n' : y+=font[' ']._height; x = x0; break; 27541 case '\t' : x+=4*font[' ']._width; break; 27542 default : if (c<font._width) { 27543 letter = font[c]; 27544 const CImg<t>& mask = (c+256)<(int)font._width?font[c+256]:font[c]; 27545 if (foreground_color) 27546 for (unsigned int p = 0; p<letter._width*letter._height; ++p) 27547 if (mask(p)) cimg_forC(*this,c) letter(p,0,0,c) = (t)(letter(p,0,0,c)*foreground_color[c]); 27548 if (background_color) 27549 for (unsigned int p = 0; p<letter._width*letter._height; ++p) 27550 if (!mask(p)) cimg_forC(*this,c) letter(p,0,0,c) = (t)background_color[c]; 27551 if (!background_color && font._width>=512) draw_image(x,y,letter,mask,opacity,(T)1); 27552 else draw_image(x,y,letter,opacity); 27553 x+=letter._width; 27554 } 27555 } 27556 } 27557 return *this; 27558 } 27559 27560 //! Draw a vector field in the instance image, using a colormap. 27561 /** 27562 \param flow Image of 2d vectors used as input data. 27563 \param color Image of spectrum()-D vectors corresponding to the color of each arrow. 27564 \param sampling Length (in pixels) between each arrow. 27565 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length). 27566 \param opacity Opacity of the drawing. 27567 \param pattern Used pattern to draw lines. 27568 \note Clipping is supported. 27569 **/ 27570 template<typename t1, typename t2> 27571 CImg<T>& draw_quiver(const CImg<t1>& flow, 27572 const t2 *const color, const float opacity=1, 27573 const unsigned int sampling=25, const float factor=-20, 27574 const bool arrows=true, const unsigned int pattern=~0U) { 27575 return draw_quiver(flow,CImg<t2>(color,_spectrum,1,1,1,true),opacity,sampling,factor,arrows,pattern); 27576 } 27577 27578 //! Draw a vector field in the instance image, using a colormap. 27579 /** 27580 \param flow Image of 2d vectors used as input data. 27581 \param color Image of spectrum()-D vectors corresponding to the color of each arrow. 27582 \param sampling Length (in pixels) between each arrow. 27583 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length). 27584 \param opacity Opacity of the drawing. 27585 \param pattern Used pattern to draw lines. 27586 \note Clipping is supported. 27587 **/ 27588 template<typename t1, typename t2> 27589 CImg<T>& draw_quiver(const CImg<t1>& flow, 27590 const CImg<t2>& color, const float opacity=1, 27591 const unsigned int sampling=25, const float factor=-20, 27592 const bool arrows=true, const unsigned int pattern=~0U) { 27593 27594 if (is_empty()) return *this; 27595 27596 if (!flow || flow._spectrum!=2) 27597 throw CImgArgumentException(_cimg_instance 27598 "draw_quiver() : Invalid dimensions of specified flow (%u,%u,%u,%u,%p).", 27599 cimg_instance, 27600 flow._width,flow._height,flow._depth,flow._spectrum,flow._data); 27601 if (sampling<=0) 27602 throw CImgArgumentException(_cimg_instance 27603 "draw_quiver() : Invalid sampling value %g " 27604 "(should be >0)", 27605 cimg_instance, 27606 sampling); 27607 27608 const bool colorfield = (color._width==flow._width && color._height==flow._height && color._depth==1 && color._spectrum==_spectrum); 27609 if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,arrows,pattern); 27610 27611 float vmax,fact; 27612 if (factor<=0) { 27613 float m, M = (float)flow.get_norm(2).max_min(m); 27614 vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M)); 27615 fact = -factor; 27616 } else { fact = factor; vmax = 1; } 27617 27618 for (unsigned int y = sampling/2; y<_height; y+=sampling) 27619 for (unsigned int x = sampling/2; x<_width; x+=sampling) { 27620 const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height; 27621 float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax; 27622 if (arrows) { 27623 const int xx = x+(int)u, yy = y+(int)v; 27624 if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.0f,pattern); 27625 else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.0f,pattern); 27626 } else { 27627 if (colorfield) draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color.get_vector_at(X,Y)._data,opacity,pattern); 27628 else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color._data,opacity,pattern); 27629 } 27630 } 27631 27632 return *this; 27633 } 27634 27635 //! Draw a labeled horizontal axis on the instance image. 27636 /** 27637 \param xvalues Lower bound of the x-range. 27638 \param y Y-coordinate of the horizontal axis in the instance image. 27639 \param color Array of spectrum() values of type \c T, defining the drawing color. 27640 \param opacity Drawing opacity. 27641 \param pattern Drawing pattern. 27642 \param opacity_out Drawing opacity of 'outside' axes. 27643 \note if \c precision==0, precision of the labels is automatically computed. 27644 **/ 27645 template<typename t, typename tc> 27646 CImg<T>& draw_axis(const CImg<t>& xvalues, const int y, 27647 const tc *const color, const float opacity=1, 27648 const unsigned int pattern=~0U) { 27649 if (!is_empty()) { 27650 int siz = (int)xvalues.size()-1; 27651 if (siz<=0) draw_line(0,y,_width-1,y,color,opacity,pattern); 27652 else { 27653 if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,_width-1,y,color,opacity,30,5,pattern); 27654 else draw_arrow(_width-1,y,0,y,color,opacity,30,5,pattern); 27655 const int yt = (y+14)<height()?(y+3):(y-14); 27656 char txt[32] = { 0 }; 27657 cimg_foroff(xvalues,x) { 27658 std::sprintf(txt,"%g",(double)xvalues(x)); 27659 const int xi = (int)(x*(_width-1)/siz), xt = xi-(int)std::strlen(txt)*3; 27660 draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity). 27661 draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,13); 27662 } 27663 } 27664 } 27665 return *this; 27666 } 27667 27668 //! Draw a labeled vertical axis on the instance image. 27669 template<typename t, typename tc> 27670 CImg<T>& draw_axis(const int x, const CImg<t>& yvalues, 27671 const tc *const color, const float opacity=1, 27672 const unsigned int pattern=~0U) { 27673 if (!is_empty()) { 27674 int siz = (int)yvalues.size()-1; 27675 if (siz<=0) draw_line(x,0,x,_height-1,color,opacity,pattern); 27676 else { 27677 if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,_height-1,color,opacity,30,5,pattern); 27678 else draw_arrow(x,_height-1,x,0,color,opacity,30,5,pattern); 27679 char txt[32] = { 0 }; 27680 cimg_foroff(yvalues,y) { 27681 std::sprintf(txt,"%g",(double)yvalues(y)); 27682 const int 27683 yi = (int)(y*(_height-1)/siz), 27684 tmp = yi-5, 27685 nyi = tmp<0?0:(tmp>=height()-11?height()-11:tmp), 27686 xt = x-(int)std::strlen(txt)*7; 27687 draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity); 27688 if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,13); 27689 else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,13); 27690 } 27691 } 27692 } 27693 return *this; 27694 } 27695 27696 //! Draw a labeled horizontal+vertical axis on the instance image. 27697 template<typename tx, typename ty, typename tc> 27698 CImg<T>& draw_axes(const CImg<tx>& xvalues, const CImg<ty>& yvalues, 27699 const tc *const color, const float opacity=1, 27700 const unsigned int patternx=~0U, const unsigned int patterny=~0U) { 27701 if (!is_empty()) { 27702 const CImg<tx> nxvalues(xvalues._data,xvalues.size(),1,1,1,true); 27703 const int sizx = (int)xvalues.size()-1, wm1 = width()-1; 27704 if (sizx>0) { 27705 float ox = (float)nxvalues[0]; 27706 for (unsigned int x = 1; x<_width; ++x) { 27707 const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1); 27708 if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; } 27709 ox = nx; 27710 } 27711 } 27712 const CImg<ty> nyvalues(yvalues._data,yvalues.size(),1,1,1,true); 27713 const int sizy = (int)yvalues.size()-1, hm1 = height()-1; 27714 if (sizy>0) { 27715 float oy = (float)nyvalues[0]; 27716 for (unsigned int y = 1; y<_height; ++y) { 27717 const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1); 27718 if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; } 27719 oy = ny; 27720 } 27721 } 27722 } 27723 return *this; 27724 } 27725 27726 //! Draw a labeled horizontal+vertical axis on the instance image. 27727 template<typename tc> 27728 CImg<T>& draw_axes(const float x0, const float x1, const float y0, const float y1, 27729 const tc *const color, const float opacity=1, 27730 const int subdivisionx=-60, const int subdivisiony=-60, 27731 const float precisionx=0, const float precisiony=0, 27732 const unsigned int patternx=~0U, const unsigned int patterny=~0U) { 27733 if (!is_empty()) { 27734 const float 27735 dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0), 27736 px = (precisionx==0)?(float)std::pow(10.0,(int)std::log10(dx)-2.0):precisionx, 27737 py = (precisiony==0)?(float)std::pow(10.0,(int)std::log10(dy)-2.0):precisiony; 27738 draw_axes(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1).round(px), 27739 CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1).round(py), 27740 color,opacity,patternx,patterny); 27741 } 27742 return *this; 27743 } 27744 27745 //! Draw grid. 27746 template<typename tx, typename ty, typename tc> 27747 CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues, 27748 const tc *const color, const float opacity=1, 27749 const unsigned int patternx=~0U, const unsigned int patterny=~0U) { 27750 if (!is_empty()) { 27751 if (xvalues) cimg_foroff(xvalues,x) { 27752 const int xi = (int)xvalues[x]; 27753 if (xi>=0 && xi<width()) draw_line(xi,0,xi,_height-1,color,opacity,patternx); 27754 } 27755 if (yvalues) cimg_foroff(yvalues,y) { 27756 const int yi = (int)yvalues[y]; 27757 if (yi>=0 && yi<height()) draw_line(0,yi,_width-1,yi,color,opacity,patterny); 27758 } 27759 } 27760 return *this; 27761 } 27762 27763 //! Draw grid. 27764 template<typename tc> 27765 CImg<T>& draw_grid(const float deltax, const float deltay, 27766 const float offsetx, const float offsety, 27767 const bool invertx, const bool inverty, 27768 const tc *const color, const float opacity=1, 27769 const unsigned int patternx=~0U, const unsigned int patterny=~0U) { 27770 CImg<uintT> seqx, seqy; 27771 if (deltax!=0) { 27772 const float dx = deltax>0?deltax:_width*-deltax/100; 27773 const unsigned int nx = (unsigned int)(_width/dx); 27774 seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx)); 27775 if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)_width); 27776 if (invertx) cimg_foroff(seqx,x) seqx(x) = _width - 1 - seqx(x); 27777 } 27778 27779 if (deltay!=0) { 27780 const float dy = deltay>0?deltay:_height*-deltay/100; 27781 const unsigned int ny = (unsigned int)(_height/dy); 27782 seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny)); 27783 if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)_height); 27784 if (inverty) cimg_foroff(seqy,y) seqy(y) = _height - 1 - seqy(y); 27785 } 27786 return draw_grid(seqx,seqy,color,opacity,patternx,patterny); 27787 } 27788 27789 //! Draw a 1d graph on the instance image. 27790 /** 27791 \param data Image containing the graph values I = f(x). 27792 \param color Array of spectrum() values of type \c T, defining the drawing color. 27793 \param opacity Drawing opacity. 27794 27795 \param plot_type Define the type of the plot : 27796 - 0 = No plot. 27797 - 1 = Plot using segments. 27798 - 2 = Plot using cubic splines. 27799 - 3 = Plot with bars. 27800 \param vertex_type Define the type of points : 27801 - 0 = No points. 27802 - 1 = Point. 27803 - 2 = Straight cross. 27804 - 3 = Diagonal cross. 27805 - 4 = Filled circle. 27806 - 5 = Outlined circle. 27807 - 6 = Square. 27808 - 7 = Diamond. 27809 \param ymin Lower bound of the y-range. 27810 \param ymax Upper bound of the y-range. 27811 \param expand Expand plot along the X-axis. 27812 \param pattern Drawing pattern. 27813 \note 27814 - if \c ymin==ymax==0, the y-range is computed automatically from the input samples. 27815 **/ 27816 template<typename t, typename tc> 27817 CImg<T>& draw_graph(const CImg<t>& data, 27818 const tc *const color, const float opacity=1, 27819 const unsigned int plot_type=1, const int vertex_type=1, 27820 const double ymin=0, const double ymax=0, const bool expand=false, 27821 const unsigned int pattern=~0U) { 27822 if (!color) 27823 throw CImgArgumentException(_cimg_instance 27824 "draw_graph() : Specified color is (null).", 27825 cimg_instance); 27826 27827 if (is_empty() || _height<=1) return *this; 27828 const unsigned int siz = data.size(); 27829 tc *color1 = 0, *color2 = 0; 27830 if (plot_type==3) { 27831 color1 = new tc[_spectrum]; color2 = new tc[_spectrum]; 27832 cimg_forC(*this,c) { color1[c] = (tc)(color[c]*0.6f); color2[c] = (tc)(color[c]*0.3f); } 27833 } 27834 27835 double m = ymin, M = ymax; 27836 if (ymin==ymax) m = (double)data.max_min(M); 27837 if (m==M) { --m; ++M; } 27838 const float ca = (float)(M-m)/(_height-1); 27839 bool init_hatch = true; 27840 const unsigned int xp = expand?1:0; 27841 27842 // Draw graph edges 27843 switch (plot_type%4) { 27844 case 1 : { // Segments 27845 int oX = 0, oY = (int)((data[0]-m)/ca); 27846 for (unsigned int off = 1; off<siz; ++off) { 27847 const int 27848 X = (int)(off*_width/(siz-xp)), 27849 Y = (int)((data[off]-m)/ca); 27850 draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch); 27851 oX = X; oY = Y; 27852 init_hatch = false; 27853 } 27854 } break; 27855 case 2 : { // Spline 27856 const CImg<t> ndata(data._data,siz,1,1,1,true); 27857 int oY = (int)((data[0]-m)/ca); 27858 const int xmax = (int)(_width*(ndata._width-1-xp)/ndata._width); 27859 for (int x = 0; x<xmax; ++x) { 27860 const int Y = (int)((ndata._cubic_atX((float)x*(ndata._width-xp)/_width)-m)/ca); 27861 if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch); 27862 init_hatch = false; 27863 oY = Y; 27864 } 27865 } break; 27866 case 3 : { // Bars 27867 const int Y0 = (int)(-m/ca); 27868 int oX = 0; 27869 cimg_foroff(data,off) { 27870 const int 27871 X = (off+1)*_width/siz-1, 27872 Y = (int)((data[off]-m)/ca); 27873 draw_rectangle(oX,Y0,X,Y,color1,opacity). 27874 draw_line(oX,Y,oX,Y0,color2,opacity). 27875 draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity). 27876 draw_line(X,Y,X,Y0,color,opacity). 27877 draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity); 27878 oX = X+1; 27879 } 27880 } break; 27881 default : break; // No edges 27882 } 27883 27884 // Draw graph points 27885 switch (vertex_type%8) { 27886 case 1 : { // Point 27887 cimg_foroff(data,off) { 27888 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27889 draw_point(X,Y,color,opacity); 27890 } 27891 } break; 27892 case 2 : { // Straight Cross 27893 cimg_foroff(data,off) { 27894 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27895 draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity); 27896 } 27897 } break; 27898 case 3 : { // Diagonal Cross 27899 cimg_foroff(data,off) { 27900 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27901 draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity); 27902 } 27903 } break; 27904 case 4 : { // Filled Circle 27905 cimg_foroff(data,off) { 27906 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27907 draw_circle(X,Y,3,color,opacity); 27908 } 27909 } break; 27910 case 5 : { // Outlined circle 27911 cimg_foroff(data,off) { 27912 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27913 draw_circle(X,Y,3,color,opacity,0U); 27914 } 27915 } break; 27916 case 6 : { // Square 27917 cimg_foroff(data,off) { 27918 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27919 draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U); 27920 } 27921 } break; 27922 case 7 : { // Diamond 27923 cimg_foroff(data,off) { 27924 const int X = off*_width/(siz-xp), Y = (int)((data[off]-m)/ca); 27925 draw_line(X,Y-4,X+4,Y,color,opacity). 27926 draw_line(X+4,Y,X,Y+4,color,opacity). 27927 draw_line(X,Y+4,X-4,Y,color,opacity). 27928 draw_line(X-4,Y,X,Y-4,color,opacity); 27929 } 27930 } break; 27931 default : break; // No points 27932 } 27933 27934 if (color1) delete[] color1; if (color2) delete[] color2; 27935 return *this; 27936 } 27937 27938 //! Draw a 3d filled region starting from a point (\c x,\c y,\ z) in the instance image. 27939 /** 27940 \param x X-coordinate of the starting point of the region to fill. 27941 \param y Y-coordinate of the starting point of the region to fill. 27942 \param z Z-coordinate of the starting point of the region to fill. 27943 \param color An array of spectrum() values of type \c T, defining the drawing color. 27944 \param region Image that will contain the mask of the filled region mask, as an output. 27945 \param sigma Tolerance concerning neighborhood values. 27946 \param opacity Opacity of the drawing. 27947 \param high_connexity Tells if 8-connexity must be used (only for 2d images). 27948 \return \p region is initialized with the binary mask of the filled region. 27949 **/ 27950 template<typename tc, typename t> 27951 CImg<T>& draw_fill(const int x, const int y, const int z, 27952 const tc *const color, const float opacity, 27953 CImg<t>& region, const float sigma=0, 27954 const bool high_connexity=false) { 27955 27956 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \ 27957 res = true; \ 27958 const T *reference_col = reference_color._data + _spectrum, *ptrs = data(x,y,z) + siz; \ 27959 for (unsigned int i = _spectrum; res && i; --i) { ptrs-=whd; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \ 27960 region(x,y,z) = (t)(res?1:noregion); \ 27961 } 27962 27963 #define _cimg_draw_fill_set(x,y,z) { \ 27964 const tc *col = color; \ 27965 T *ptrd = data(x,y,z); \ 27966 if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } \ 27967 else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } \ 27968 } 27969 27970 #define _cimg_draw_fill_insert(x,y,z) { \ 27971 if (posr1>=remaining._height) remaining.resize(3,remaining._height<<1,1,1,0); \ 27972 unsigned int *ptrr = remaining.data(0,posr1); \ 27973 *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \ 27974 } 27975 27976 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \ 27977 const unsigned int tx = x, ty = y, tz = z; \ 27978 _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \ 27979 } 27980 27981 if (!color) 27982 throw CImgArgumentException(_cimg_instance 27983 "draw_fill() : Specified color is (null).", 27984 cimg_instance); 27985 27986 region.assign(_width,_height,_depth,1,(t)0); 27987 if (x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth()) { 27988 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 27989 const unsigned int whd = _width*_height*_depth, siz = _spectrum*whd, W1 = _width-1, H1 = _height-1, D1 = _depth-1; 27990 const bool is_threed = (_depth>1); 27991 const CImg<T> reference_color = get_vector_at(x,y,z); 27992 CImg<uintT> remaining(3,512,1,1,0); 27993 remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z; 27994 unsigned int posr0 = 0, posr1 = 1; 27995 region(x,y,z) = (t)1; 27996 const t noregion = ((t)1==(t)2)?(t)0:(t)(-1); 27997 if (is_threed) do { // 3d version of the filling algorithm 27998 const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++); 27999 if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; } 28000 bool cont, res; 28001 unsigned int nxc = xc; 28002 do { // X-backward 28003 _cimg_draw_fill_set(nxc,yc,zc); 28004 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0); 28005 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1); 28006 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0); 28007 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1); 28008 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false; 28009 } while (cont); 28010 nxc = xc; 28011 do { // X-forward 28012 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false; 28013 if (cont) { 28014 _cimg_draw_fill_set(nxc,yc,zc); 28015 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0); 28016 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1); 28017 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0); 28018 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1); 28019 } 28020 } while (cont); 28021 unsigned int nyc = yc; 28022 do { // Y-backward 28023 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false; 28024 if (cont) { 28025 _cimg_draw_fill_set(xc,nyc,zc); 28026 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0); 28027 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1); 28028 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0); 28029 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1); 28030 } 28031 } while (cont); 28032 nyc = yc; 28033 do { // Y-forward 28034 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false; 28035 if (cont) { 28036 _cimg_draw_fill_set(xc,nyc,zc); 28037 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0); 28038 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1); 28039 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0); 28040 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1); 28041 } 28042 } while (cont); 28043 unsigned int nzc = zc; 28044 do { // Z-backward 28045 if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false; 28046 if (cont) { 28047 _cimg_draw_fill_set(xc,yc,nzc); 28048 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0); 28049 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1); 28050 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0); 28051 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1); 28052 } 28053 } while (cont); 28054 nzc = zc; 28055 do { // Z-forward 28056 if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false; 28057 if (cont) { 28058 _cimg_draw_fill_set(xc,nyc,zc); 28059 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0); 28060 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1); 28061 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0); 28062 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1); 28063 } 28064 } while (cont); 28065 } while (posr1>posr0); 28066 else do { // 2d version of the filling algorithm 28067 const unsigned int *pcurr = remaining.data(0,posr0++), xc = *(pcurr++), yc = *(pcurr++); 28068 if (posr0>=512) { remaining.shift(0,-(int)posr0); posr1-=posr0; posr0 = 0; } 28069 bool cont, res; 28070 unsigned int nxc = xc; 28071 do { // X-backward 28072 _cimg_draw_fill_set(nxc,yc,0); 28073 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0); 28074 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1); 28075 if (high_connexity) { 28076 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0)); 28077 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0)); 28078 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1)); 28079 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1)); 28080 } 28081 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false; 28082 } while (cont); 28083 nxc = xc; 28084 do { // X-forward 28085 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false; 28086 if (cont) { 28087 _cimg_draw_fill_set(nxc,yc,0); 28088 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0); 28089 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1); 28090 if (high_connexity) { 28091 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0)); 28092 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0)); 28093 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1)); 28094 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1)); 28095 } 28096 } 28097 } while (cont); 28098 unsigned int nyc = yc; 28099 do { // Y-backward 28100 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false; 28101 if (cont) { 28102 _cimg_draw_fill_set(xc,nyc,0); 28103 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0); 28104 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1); 28105 if (high_connexity) { 28106 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0)); 28107 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0)); 28108 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1)); 28109 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1)); 28110 } 28111 } 28112 } while (cont); 28113 nyc = yc; 28114 do { // Y-forward 28115 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false; 28116 if (cont) { 28117 _cimg_draw_fill_set(xc,nyc,0); 28118 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0); 28119 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1); 28120 if (high_connexity) { 28121 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0)); 28122 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0)); 28123 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1)); 28124 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1)); 28125 } 28126 } 28127 } while (cont); 28128 } while (posr1>posr0); 28129 if (noregion) cimg_for(region,ptrd,t) if (*ptrd==noregion) *ptrd = (t)0; 28130 } 28131 return *this; 28132 } 28133 28134 //! Draw a 3d filled region starting from a point (\c x,\c y,\ z) in the instance image. 28135 /** 28136 \param x = X-coordinate of the starting point of the region to fill. 28137 \param y = Y-coordinate of the starting point of the region to fill. 28138 \param z = Z-coordinate of the starting point of the region to fill. 28139 \param color = an array of spectrum() values of type \c T, defining the drawing color. 28140 \param sigma = tolerance concerning neighborhood values. 28141 \param opacity = opacity of the drawing. 28142 **/ 28143 template<typename tc> 28144 CImg<T>& draw_fill(const int x, const int y, const int z, 28145 const tc *const color, const float opacity=1, 28146 const float sigma=0, const bool high_connexity=false) { 28147 CImg<boolT> tmp; 28148 return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity); 28149 } 28150 28151 //! Draw a 2d filled region starting from a point (\c x,\c y) in the instance image. 28152 /** 28153 \param x = X-coordinate of the starting point of the region to fill. 28154 \param y = Y-coordinate of the starting point of the region to fill. 28155 \param color = an array of spectrum() values of type \c T, defining the drawing color. 28156 \param sigma = tolerance concerning neighborhood values. 28157 \param opacity = opacity of the drawing. 28158 **/ 28159 template<typename tc> 28160 CImg<T>& draw_fill(const int x, const int y, 28161 const tc *const color, const float opacity=1, 28162 const float sigma=0, const bool high_connexity=false) { 28163 CImg<boolT> tmp; 28164 return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity); 28165 } 28166 28167 //! Draw a plasma random texture. 28168 /** 28169 \param x0 = X-coordinate of the upper-left corner of the plasma. 28170 \param y0 = Y-coordinate of the upper-left corner of the plasma. 28171 \param x1 = X-coordinate of the lower-right corner of the plasma. 28172 \param y1 = Y-coordinate of the lower-right corner of the plasma. 28173 \param alpha = Alpha-parameter of the plasma. 28174 \param beta = Beta-parameter of the plasma. 28175 \param opacity = opacity of the drawing. 28176 **/ 28177 CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1, 28178 const float alpha=1, const float beta=1, 28179 const float opacity=1) { 28180 if (!is_empty()) { 28181 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 28182 int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1; 28183 if (nx1<nx0) cimg::swap(nx0,nx1); 28184 if (ny1<ny0) cimg::swap(ny0,ny1); 28185 if (nx0<0) nx0 = 0; 28186 if (nx1>=width()) nx1 = _width-1; 28187 if (ny0<0) ny0 = 0; 28188 if (ny1>=height()) ny1 = _height-1; 28189 const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0); 28190 const Tfloat dc = (Tfloat)(std::sqrt((float)(dx*dx+dy*dy))*alpha + beta); 28191 Tfloat val = 0; 28192 cimg_forC(*this,c) { 28193 if (opacity>=1) { 28194 const Tfloat 28195 val0 = (Tfloat)((*this)(nx0,ny0,0,c)), val1 = (Tfloat)((*this)(nx1,ny0,0,c)), 28196 val2 = (Tfloat)((*this)(nx0,ny1,0,c)), val3 = (Tfloat)((*this)(nx1,ny1,0,c)); 28197 (*this)(xc,ny0,0,c) = (T)((val0+val1)/2); 28198 (*this)(xc,ny1,0,c) = (T)((val2+val3)/2); 28199 (*this)(nx0,yc,0,c) = (T)((val0+val2)/2); 28200 (*this)(nx1,yc,0,c) = (T)((val1+val3)/2); 28201 do { 28202 val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,c)) + 28203 (Tfloat)((*this)(nx1,ny0,0,c)) + 28204 (Tfloat)((*this)(nx1,ny1,0,c)) + 28205 (Tfloat)((*this)(nx0,ny1,0,c))) + 28206 dc*cimg::grand()); 28207 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max()); 28208 (*this)(xc,yc,0,c) = (T)val; 28209 } else { 28210 const Tfloat 28211 val0 = (Tfloat)((*this)(nx0,ny0,0,c)), val1 = (Tfloat)((*this)(nx1,ny0,0,c)), 28212 val2 = (Tfloat)((*this)(nx0,ny1,0,c)), val3 = (Tfloat)((*this)(nx1,ny1,0,c)); 28213 (*this)(xc,ny0,0,c) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,c))/2); 28214 (*this)(xc,ny1,0,c) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,c))/2); 28215 (*this)(nx0,yc,0,c) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,c))/2); 28216 (*this)(nx1,yc,0,c) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,c))/2); 28217 do { 28218 val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,c)) + 28219 (Tfloat)((*this)(nx1,ny0,0,c)) + 28220 (Tfloat)((*this)(nx1,ny1,0,c)) + 28221 (Tfloat)((*this)(nx0,ny1,0,c))) + 28222 dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,c)); 28223 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max()); 28224 (*this)(xc,yc,0,c) = (T)val; 28225 } 28226 } 28227 if (xc!=nx0 || yc!=ny0) { 28228 draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity); 28229 draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity); 28230 draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity); 28231 draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity); 28232 } 28233 } 28234 return *this; 28235 } 28236 28237 //! Draw a plasma random texture. 28238 /** 28239 \param alpha = Alpha-parameter of the plasma. 28240 \param beta = Beta-parameter of the plasma. 28241 \param opacity = opacity of the drawing. 28242 **/ 28243 CImg<T>& draw_plasma(const float alpha=1, const float beta=1, 28244 const float opacity=1) { 28245 return draw_plasma(0,0,_width-1,_height-1,alpha,beta,opacity); 28246 } 28247 28248 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm. 28249 template<typename tc> 28250 CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1, 28251 const CImg<tc>& color_palette, const float opacity=1, 28252 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, 28253 const unsigned int iteration_max=255, 28254 const bool normalized_iteration=false, 28255 const bool julia_set=false, 28256 const double paramr=0, const double parami=0) { 28257 if (is_empty()) return *this; 28258 CImg<tc> palette; 28259 if (color_palette) palette.assign(color_palette._data,color_palette.size()/color_palette._spectrum,1,1,color_palette._spectrum,true); 28260 if (palette && palette._spectrum!=_spectrum) 28261 throw CImgArgumentException(_cimg_instance 28262 "draw_mandelbrot() : Instance and specified color palette (%u,%u,%u,%u,%p) have incompatible dimensions.", 28263 cimg_instance, 28264 color_palette._width,color_palette._height,color_palette._depth,color_palette._spectrum,color_palette._data); 28265 28266 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)std::log(2.0); 28267 unsigned int iteration = 0; 28268 cimg_for_inXY(*this,x0,y0,x1,y1,p,q) { 28269 const double x = z0r + p*(z1r-z0r)/_width, y = z0i + q*(z1i-z0i)/_height; 28270 double zr, zi, cr, ci; 28271 if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; } 28272 else { zr = paramr; zi = parami; cr = x; ci = y; } 28273 for (iteration=1; zr*zr + zi*zi<=4 && iteration<=iteration_max; ++iteration) { 28274 const double temp = zr*zr - zi*zi + cr; 28275 zi = 2*zr*zi + ci; 28276 zr = temp; 28277 } 28278 if (iteration>iteration_max) { 28279 if (palette) { 28280 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette(0,c); 28281 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(0,c)*nopacity + (*this)(p,q,0,c)*copacity); 28282 } else { 28283 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)0; 28284 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)((*this)(p,q,0,c)*copacity); 28285 } 28286 } else if (normalized_iteration) { 28287 const float 28288 normz = (float)cimg::abs(zr*zr+zi*zi), 28289 niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2); 28290 if (palette) { 28291 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c); 28292 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette._linear_atX(niteration,c)*nopacity + (*this)(p,q,0,c)*copacity); 28293 } else { 28294 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)niteration; 28295 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(niteration*nopacity + (*this)(p,q,0,c)*copacity); 28296 } 28297 } else { 28298 if (palette) { 28299 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._atX(iteration,c); 28300 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(iteration,c)*nopacity + (*this)(p,q,0,c)*copacity); 28301 } else { 28302 if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)iteration; 28303 else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(iteration*nopacity + (*this)(p,q,0,c)*copacity); 28304 } 28305 } 28306 } 28307 return *this; 28308 } 28309 28310 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm. 28311 template<typename tc> 28312 CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1, 28313 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, 28314 const unsigned int iteration_max=255, 28315 const bool normalized_iteration=false, 28316 const bool julia_set=false, 28317 const double paramr=0, const double parami=0) { 28318 return draw_mandelbrot(0,0,_width-1,_height-1,color_palette,opacity, 28319 z0r,z0i,z1r,z1i,iteration_max,normalized_iteration,julia_set,paramr,parami); 28320 } 28321 28322 //! Draw a 1d gaussian function in the instance image. 28323 /** 28324 \param xc = X-coordinate of the gaussian center. 28325 \param sigma = Standard variation of the gaussian distribution. 28326 \param color = array of spectrum() values of type \c T, defining the drawing color. 28327 \param opacity = opacity of the drawing. 28328 **/ 28329 template<typename tc> 28330 CImg<T>& draw_gaussian(const float xc, const float sigma, 28331 const tc *const color, const float opacity=1) { 28332 if (!color) 28333 throw CImgArgumentException(_cimg_instance 28334 "draw_gaussian() : Specified color is (null).", 28335 cimg_instance); 28336 28337 if (is_empty()) return *this; 28338 const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 28339 const unsigned int whd = _width*_height*_depth; 28340 const tc *col = color; 28341 cimg_forX(*this,x) { 28342 const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2); 28343 T *ptrd = data(x,0,0,0); 28344 if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } 28345 else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } 28346 col-=_spectrum; 28347 } 28348 return *this; 28349 } 28350 28351 //! Draw an anisotropic 2d gaussian function. 28352 /** 28353 \param xc = X-coordinate of the gaussian center. 28354 \param yc = Y-coordinate of the gaussian center. 28355 \param tensor = 2x2 covariance matrix. 28356 \param color = array of spectrum() values of type \c T, defining the drawing color. 28357 \param opacity = opacity of the drawing. 28358 **/ 28359 template<typename t, typename tc> 28360 CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor, 28361 const tc *const color, const float opacity=1) { 28362 if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1) 28363 throw CImgArgumentException(_cimg_instance 28364 "draw_gaussian() : Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.", 28365 cimg_instance, 28366 tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); 28367 if (!color) 28368 throw CImgArgumentException(_cimg_instance 28369 "draw_gaussian() : Specified color is (null).", 28370 cimg_instance); 28371 28372 if (is_empty()) return *this; 28373 typedef typename CImg<t>::Tfloat tfloat; 28374 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0); 28375 const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1); 28376 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 28377 const unsigned int whd = _width*_height*_depth; 28378 const tc *col = color; 28379 float dy = -yc; 28380 cimg_forY(*this,y) { 28381 float dx = -xc; 28382 cimg_forX(*this,x) { 28383 const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy); 28384 T *ptrd = data(x,y,0,0); 28385 if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } 28386 else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } 28387 col-=_spectrum; 28388 ++dx; 28389 } 28390 ++dy; 28391 } 28392 return *this; 28393 } 28394 28395 //! Draw an anisotropic 2d gaussian function. 28396 template<typename tc> 28397 CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv, 28398 const tc *const color, const float opacity=1) { 28399 const double 28400 a = r1*ru*ru + r2*rv*rv, 28401 b = (r1-r2)*ru*rv, 28402 c = r1*rv*rv + r2*ru*ru; 28403 const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c); 28404 return draw_gaussian(xc,yc,tensor,color,opacity); 28405 } 28406 28407 //! Draw an isotropic 2d gaussian function. 28408 /** 28409 \param xc = X-coordinate of the gaussian center. 28410 \param yc = Y-coordinate of the gaussian center. 28411 \param sigma = standard variation of the gaussian distribution. 28412 \param color = array of spectrum() values of type \c T, defining the drawing color. 28413 \param opacity = opacity of the drawing. 28414 **/ 28415 template<typename tc> 28416 CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma, 28417 const tc *const color, const float opacity=1) { 28418 return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity); 28419 } 28420 28421 //! Draw an anisotropic 3d gaussian function. 28422 /** 28423 \param xc = X-coordinate of the gaussian center. 28424 \param yc = Y-coordinate of the gaussian center. 28425 \param zc = Z-coordinate of the gaussian center. 28426 \param tensor = 3x3 covariance matrix. 28427 \param color = array of spectrum() values of type \c T, defining the drawing color. 28428 \param opacity = opacity of the drawing. 28429 **/ 28430 template<typename t, typename tc> 28431 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor, 28432 const tc *const color, const float opacity=1) { 28433 if (is_empty()) return *this; 28434 typedef typename CImg<t>::Tfloat tfloat; 28435 if (tensor._width!=3 || tensor._height!=3 || tensor._depth!=1 || tensor._spectrum!=1) 28436 throw CImgArgumentException(_cimg_instance 28437 "draw_gaussian() : Specified tensor (%u,%u,%u,%u,%p) is not a 3x3 matrix.", 28438 cimg_instance, 28439 tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); 28440 28441 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0); 28442 const tfloat a = invT(0,0), b = 2*invT(1,0), c = 2*invT(2,0), d = invT(1,1), e = 2*invT(2,1), f = invT(2,2); 28443 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0); 28444 const unsigned int whd = _width*_height*_depth; 28445 const tc *col = color; 28446 cimg_forXYZ(*this,x,y,z) { 28447 const float 28448 dx = (x - xc), dy = (y - yc), dz = (z - zc), 28449 val = (float)std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz); 28450 T *ptrd = data(x,y,z,0); 28451 if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } 28452 else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } 28453 col-=_spectrum; 28454 } 28455 return *this; 28456 } 28457 28458 //! Draw an isotropic 3d gaussian function. 28459 /** 28460 \param xc = X-coordinate of the gaussian center. 28461 \param yc = Y-coordinate of the gaussian center. 28462 \param zc = Z-coordinate of the gaussian center. 28463 \param sigma = standard variation of the gaussian distribution. 28464 \param color = array of spectrum() values of type \c T, defining the drawing color. 28465 \param opacity = opacity of the drawing. 28466 **/ 28467 template<typename tc> 28468 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma, 28469 const tc *const color, const float opacity=1) { 28470 return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity); 28471 } 28472 28473 //! Draw a 3d object. 28474 /** 28475 \param X = X-coordinate of the 3d object position 28476 \param Y = Y-coordinate of the 3d object position 28477 \param Z = Z-coordinate of the 3d object position 28478 \param vertices = Image Nx3 describing 3d point coordinates 28479 \param primitives = List of P primitives 28480 \param colors = List of P color (or textures) 28481 \param opacities = Image or list of P opacities 28482 \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud) 28483 \param double_sided = Tell if object faces have two sides or are oriented. 28484 \param focale = length of the focale 28485 \param lightx = X-coordinate of the light 28486 \param lighty = Y-coordinate of the light 28487 \param lightz = Z-coordinate of the light 28488 \param specular_shine = Shininess of the object 28489 **/ 28490 template<typename tp, typename tf, typename tc, typename to> 28491 CImg<T>& draw_object3d(const float x0, const float y0, const float z0, 28492 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28493 const CImgList<tc>& colors, const CImg<to>& opacities, 28494 const unsigned int render_type=4, 28495 const bool double_sided=false, const float focale=500, 28496 const float lightx=0, const float lighty=0, const float lightz=-5000, 28497 const float specular_light=0.2f, const float specular_shine=0.1f, 28498 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28499 return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, 28500 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine); 28501 } 28502 28503 #ifdef cimg_use_board 28504 template<typename tp, typename tf, typename tc, typename to> 28505 CImg<T>& draw_object3d(LibBoard::Board& board, 28506 const float x0, const float y0, const float z0, 28507 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28508 const CImgList<tc>& colors, const CImg<to>& opacities, 28509 const unsigned int render_type=4, 28510 const bool double_sided=false, const float focale=500, 28511 const float lightx=0, const float lighty=0, const float lightz=-5000, 28512 const float specular_light=0.2f, const float specular_shine=0.1f, 28513 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28514 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, 28515 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine); 28516 } 28517 #endif 28518 28519 template<typename tp, typename tf, typename tc, typename to> 28520 CImg<T>& draw_object3d(const float x0, const float y0, const float z0, 28521 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28522 const CImgList<tc>& colors, const CImgList<to>& opacities, 28523 const unsigned int render_type=4, 28524 const bool double_sided=false, const float focale=500, 28525 const float lightx=0, const float lighty=0, const float lightz=-5000, 28526 const float specular_light=0.2f, const float specular_shine=0.1f, 28527 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28528 return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, 28529 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine); 28530 } 28531 28532 #ifdef cimg_use_board 28533 template<typename tp, typename tf, typename tc, typename to> 28534 CImg<T>& draw_object3d(LibBoard::Board& board, 28535 const float x0, const float y0, const float z0, 28536 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28537 const CImgList<tc>& colors, const CImgList<to>& opacities, 28538 const unsigned int render_type=4, 28539 const bool double_sided=false, const float focale=500, 28540 const float lightx=0, const float lighty=0, const float lightz=-5000, 28541 const float specular_light=0.2f, const float specular_shine=0.1f, 28542 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28543 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, 28544 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine); 28545 } 28546 #endif 28547 28548 //! Draw a 3d object. 28549 template<typename tp, typename tf, typename tc> 28550 CImg<T>& draw_object3d(const float x0, const float y0, const float z0, 28551 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28552 const CImgList<tc>& colors, 28553 const unsigned int render_type=4, 28554 const bool double_sided=false, const float focale=500, 28555 const float lightx=0, const float lighty=0, const float lightz=-5000, 28556 const float specular_light=0.2f, const float specular_shine=0.1f, 28557 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28558 static const CImg<floatT> opacities; 28559 return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities, 28560 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer); 28561 } 28562 28563 #ifdef cimg_use_board 28564 template<typename tp, typename tf, typename tc, typename to> 28565 CImg<T>& draw_object3d(LibBoard::Board& board, 28566 const float x0, const float y0, const float z0, 28567 const CImg<tp>& vertices, const CImgList<tf>& primitives, 28568 const CImgList<tc>& colors, 28569 const unsigned int render_type=4, 28570 const bool double_sided=false, const float focale=500, 28571 const float lightx=0, const float lighty=0, const float lightz=-5000, 28572 const float specular_light=0.2f, const float specular_shine=0.1f, 28573 CImg<floatT>& zbuffer=cimg_library::CImg<floatT>::empty()) { 28574 static const CImg<floatT> opacities; 28575 return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities, 28576 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer); 28577 } 28578 #endif 28579 28580 template<typename tc, typename to> 28581 void __draw_object3d(const unsigned int n_primitive, const CImgList<to>& opacities, const CImg<tc>& color, 28582 const int nx0, const int ny0, const CImg<T>& sprite, const float opac) { 28583 if (n_primitive<opacities._width && opacities[n_primitive].is_sameXY(color)) 28584 draw_image(nx0,ny0,sprite,opacities[n_primitive].get_resize(sprite._width,sprite._height,1,sprite._spectrum,1)); 28585 else draw_image(nx0,ny0,sprite,opac); 28586 } 28587 28588 template<typename tc, typename to> 28589 void __draw_object3d(const unsigned int, const CImg<to>&, const CImg<tc>&, 28590 const int nx0, const int ny0, const CImg<T>& sprite, const float opac) { 28591 draw_image(nx0,ny0,sprite,opac); 28592 } 28593 28594 template<typename tp, typename tf, typename tc, typename to> 28595 CImg<T>& _draw_object3d(void *const pboard, CImg<floatT>& zbuffer, 28596 const float X, const float Y, const float Z, 28597 const CImg<tp>& vertices, 28598 const CImgList<tf>& primitives, 28599 const CImgList<tc>& colors, 28600 const to& opacities, 28601 const unsigned int render_type, 28602 const bool double_sided, const float focale, 28603 const float lightx, const float lighty, const float lightz, 28604 const float specular_light, const float specular_shine) { 28605 if (is_empty() || !vertices || !primitives) return *this; 28606 char error_message[1024] = { 0 }; 28607 if (!vertices.is_object3d(primitives,colors,opacities,false,error_message)) 28608 throw CImgArgumentException(_cimg_instance 28609 "draw_object3d() : Invalid specified 3d object (%u,%u) (%s).", 28610 cimg_instance,vertices._width,primitives._width,error_message); 28611 #ifndef cimg_use_board 28612 if (pboard) return *this; 28613 #endif 28614 const float 28615 nspec = 1 - (specular_light<0.0f?0.0f:(specular_light>1.0f?1.0f:specular_light)), 28616 nspec2 = 1 + (specular_shine<0.0f?0.0f:specular_shine), 28617 nsl1 = (nspec2 - 1)/cimg::sqr(nspec - 1), 28618 nsl2 = 1 - 2*nsl1*nspec, 28619 nsl3 = nspec2 - nsl1 - nsl2; 28620 28621 // Create light texture for phong-like rendering. 28622 static CImg<floatT> light_texture; 28623 if (render_type==5) { 28624 if (colors._width>primitives._width) light_texture.assign(colors[primitives._width])/=255; 28625 else { 28626 static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0; 28627 if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine || light_texture._spectrum<_spectrum) { 28628 light_texture.assign(512,512); 28629 const float 28630 dlx = lightx - X, 28631 dly = lighty - Y, 28632 dlz = lightz - Z, 28633 nl = (float)std::sqrt(dlx*dlx+dly*dly+dlz*dlz), 28634 nlx = light_texture._width/2*(1+dlx/nl), 28635 nly = light_texture._height/2*(1+dly/nl), 28636 white[] = { 1 }; 28637 light_texture.draw_gaussian(nlx,nly,light_texture._width/3.0f,white); 28638 cimg_forXY(light_texture,x,y) { 28639 const float factor = light_texture(x,y); 28640 if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3); 28641 } 28642 light_texture.resize(-100,-100,1,cimg::max(4U,_spectrum)); 28643 olightx = lightx; 28644 olighty = lighty; 28645 olightz = lightz; 28646 ospecular_shine = specular_shine; 28647 } 28648 } 28649 } 28650 28651 // Compute 3d to 2d projection. 28652 CImg<floatT> projections(vertices._width,2); 28653 cimg_forX(projections,l) { 28654 const float 28655 x = (float)vertices(l,0), 28656 y = (float)vertices(l,1), 28657 z = (float)vertices(l,2); 28658 const float projectedz = z + Z + focale; 28659 projections(l,1) = Y + focale*y/projectedz; 28660 projections(l,0) = X + focale*x/projectedz; 28661 } 28662 28663 // Compute and sort visible primitives. 28664 CImg<uintT> visibles(primitives._width); 28665 CImg<floatT> zrange(primitives._width); 28666 unsigned int nb_visibles = 0; 28667 const float zmin = 1.5f - focale; 28668 cimglist_for(primitives,l) { 28669 const CImg<tf>& primitive = primitives[l]; 28670 switch (primitive.size()) { 28671 28672 case 1 : { // Point 28673 const unsigned int i0 = (unsigned int)primitive(0); 28674 const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)); 28675 if (z0>zmin && x0>=0 && x0<_width && y0>=0 && y0<_height) { 28676 visibles(nb_visibles) = (unsigned int)l; 28677 zrange(nb_visibles++) = z0; 28678 } 28679 } break; 28680 case 5 : { // Sphere 28681 const unsigned int 28682 i0 = (unsigned int)primitive(0), 28683 i1 = (unsigned int)primitive(1); 28684 const float 28685 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)), 28686 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)); 28687 float xm, xM, ym, yM; 28688 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } 28689 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } 28690 if (z0>zmin && z1>zmin && xM>=0 && xm<_width && yM>=0 && ym<_height) { 28691 visibles(nb_visibles) = (unsigned int)l; 28692 zrange(nb_visibles++) = 0.5f*(z0 + z1); 28693 } 28694 } break; 28695 case 2 : // Segment 28696 case 6 : { 28697 const unsigned int 28698 i0 = (unsigned int)primitive(0), 28699 i1 = (unsigned int)primitive(1); 28700 const float 28701 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)), 28702 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)); 28703 float xm, xM, ym, yM; 28704 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } 28705 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } 28706 if (z0>zmin && z1>zmin && xM>=0 && xm<_width && yM>=0 && ym<_height) { 28707 visibles(nb_visibles) = (unsigned int)l; 28708 zrange(nb_visibles++) = 0.5f*(z0 + z1); 28709 } 28710 } break; 28711 case 3 : // Triangle 28712 case 9 : { 28713 const unsigned int 28714 i0 = (unsigned int)primitive(0), 28715 i1 = (unsigned int)primitive(1), 28716 i2 = (unsigned int)primitive(2); 28717 const float 28718 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)), 28719 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)), 28720 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z + vertices(i2,2)); 28721 float xm, xM, ym, yM; 28722 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } 28723 if (x2<xm) xm = x2; 28724 if (x2>xM) xM = x2; 28725 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } 28726 if (y2<ym) ym = y2; 28727 if (y2>yM) yM = y2; 28728 if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<_width && yM>=0 && ym<_height) { 28729 const float d = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0); 28730 if (double_sided || d<0) { 28731 visibles(nb_visibles) = (unsigned int)l; 28732 zrange(nb_visibles++) = (z0 + z1 + z2)/3; 28733 } 28734 } 28735 } break; 28736 case 4 : // Rectangle 28737 case 12 : { 28738 const unsigned int 28739 i0 = (unsigned int)primitive(0), 28740 i1 = (unsigned int)primitive(1), 28741 i2 = (unsigned int)primitive(2), 28742 i3 = (unsigned int)primitive(3); 28743 const float 28744 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)), 28745 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)), 28746 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z + vertices(i2,2)), 28747 x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z + vertices(i3,2)); 28748 float xm, xM, ym, yM; 28749 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } 28750 if (x2<xm) xm = x2; 28751 if (x2>xM) xM = x2; 28752 if (x3<xm) xm = x3; 28753 if (x3>xM) xM = x3; 28754 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } 28755 if (y2<ym) ym = y2; 28756 if (y2>yM) yM = y2; 28757 if (y3<ym) ym = y3; 28758 if (y3>yM) yM = y3; 28759 if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<_width && yM>=0 && ym<_height) { 28760 const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0); 28761 if (double_sided || d<0) { 28762 visibles(nb_visibles) = (unsigned int)l; 28763 zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4; 28764 } 28765 } 28766 } break; 28767 default : 28768 throw CImgArgumentException(_cimg_instance 28769 "draw_object3d() : Invalid primitive[%u] with size %u " 28770 "(should have size 1,2,3,4,5,6,9 or 12).", 28771 cimg_instance, 28772 l,primitive.size()); 28773 } 28774 } 28775 if (nb_visibles<=0) return *this; 28776 CImg<uintT> permutations; 28777 CImg<floatT>(zrange._data,nb_visibles,1,1,1,true).sort(permutations,false); 28778 28779 // Compute light properties 28780 CImg<floatT> lightprops; 28781 switch (render_type) { 28782 case 3 : { // Flat Shading 28783 lightprops.assign(nb_visibles); 28784 cimg_forX(lightprops,l) { 28785 const CImg<tf>& primitive = primitives(visibles(permutations(l))); 28786 const unsigned int psize = primitive.size(); 28787 if (psize==3 || psize==4 || psize==9 || psize==12) { 28788 const unsigned int 28789 i0 = (unsigned int)primitive(0), 28790 i1 = (unsigned int)primitive(1), 28791 i2 = (unsigned int)primitive(2); 28792 const float 28793 x0 = (float)vertices(i0,0), y0 = (float)vertices(i0,1), z0 = (float)vertices(i0,2), 28794 x1 = (float)vertices(i1,0), y1 = (float)vertices(i1,1), z1 = (float)vertices(i1,2), 28795 x2 = (float)vertices(i2,0), y2 = (float)vertices(i2,1), z2 = (float)vertices(i2,2), 28796 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, 28797 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, 28798 nx = dy1*dz2 - dz1*dy2, 28799 ny = dz1*dx2 - dx1*dz2, 28800 nz = dx1*dy2 - dy1*dx2, 28801 norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), 28802 lx = X + (x0 + x1 + x2)/3 - lightx, 28803 ly = Y + (y0 + y1 + y2)/3 - lighty, 28804 lz = Z + (z0 + z1 + z2)/3 - lightz, 28805 nl = (float)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz), 28806 factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0); 28807 lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); 28808 } else lightprops[l] = 1; 28809 } 28810 } break; 28811 28812 case 4 : // Gouraud Shading 28813 case 5 : { // Phong-Shading 28814 CImg<floatT> vertices_normals(vertices._width,3,1,1,0); 28815 for (unsigned int l = 0; l<nb_visibles; ++l) { 28816 const CImg<tf>& primitive = primitives[visibles(l)]; 28817 const unsigned int psize = primitive.size(); 28818 const bool 28819 triangle_flag = (psize==3) || (psize==9), 28820 rectangle_flag = (psize==4) || (psize==12); 28821 if (triangle_flag || rectangle_flag) { 28822 const unsigned int 28823 i0 = (unsigned int)primitive(0), 28824 i1 = (unsigned int)primitive(1), 28825 i2 = (unsigned int)primitive(2), 28826 i3 = rectangle_flag?(unsigned int)primitive(3):0; 28827 const float 28828 x0 = (float)vertices(i0,0), y0 = (float)vertices(i0,1), z0 = (float)vertices(i0,2), 28829 x1 = (float)vertices(i1,0), y1 = (float)vertices(i1,1), z1 = (float)vertices(i1,2), 28830 x2 = (float)vertices(i2,0), y2 = (float)vertices(i2,1), z2 = (float)vertices(i2,2), 28831 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, 28832 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, 28833 nnx = dy1*dz2 - dz1*dy2, 28834 nny = dz1*dx2 - dx1*dz2, 28835 nnz = dx1*dy2 - dy1*dx2, 28836 norm = 1e-5f + (float)std::sqrt(nnx*nnx + nny*nny + nnz*nnz), 28837 nx = nnx/norm, 28838 ny = nny/norm, 28839 nz = nnz/norm; 28840 vertices_normals(i0,0)+=nx; vertices_normals(i0,1)+=ny; vertices_normals(i0,2)+=nz; 28841 vertices_normals(i1,0)+=nx; vertices_normals(i1,1)+=ny; vertices_normals(i1,2)+=nz; 28842 vertices_normals(i2,0)+=nx; vertices_normals(i2,1)+=ny; vertices_normals(i2,2)+=nz; 28843 if (rectangle_flag) { vertices_normals(i3,0)+=nx; vertices_normals(i3,1)+=ny; vertices_normals(i3,2)+=nz; } 28844 } 28845 } 28846 28847 if (double_sided) cimg_forX(vertices_normals,p) if (vertices_normals(p,2)>0) { 28848 vertices_normals(p,0) = -vertices_normals(p,0); 28849 vertices_normals(p,1) = -vertices_normals(p,1); 28850 vertices_normals(p,2) = -vertices_normals(p,2); 28851 } 28852 28853 if (render_type==4) { 28854 lightprops.assign(vertices._width); 28855 cimg_forX(lightprops,ll) { 28856 const float 28857 nx = vertices_normals(ll,0), 28858 ny = vertices_normals(ll,1), 28859 nz = vertices_normals(ll,2), 28860 norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), 28861 lx = (float)(X + vertices(ll,0) - lightx), 28862 ly = (float)(Y + vertices(ll,1) - lighty), 28863 lz = (float)(Z + vertices(ll,2) - lightz), 28864 nl = (float)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz), 28865 factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0); 28866 lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); 28867 } 28868 } else { 28869 const unsigned int 28870 lw2 = light_texture._width/2 - 1, 28871 lh2 = light_texture._height/2 - 1; 28872 lightprops.assign(vertices._width,2); 28873 cimg_forX(lightprops,ll) { 28874 const float 28875 nx = vertices_normals(ll,0), 28876 ny = vertices_normals(ll,1), 28877 nz = vertices_normals(ll,2), 28878 norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz), 28879 nnx = nx/norm, 28880 nny = ny/norm; 28881 lightprops(ll,0) = lw2*(1 + nnx); 28882 lightprops(ll,1) = lh2*(1 + nny); 28883 } 28884 } 28885 } break; 28886 } 28887 28888 // Draw visible primitives 28889 const CImg<tc> default_color(1,_spectrum,1,1,(tc)200); 28890 for (unsigned int l = 0; l<nb_visibles; ++l) { 28891 const unsigned int n_primitive = visibles(permutations(l)); 28892 const CImg<tf>& primitive = primitives[n_primitive]; 28893 const CImg<tc>& color = n_primitive<colors._width?colors[n_primitive]:default_color; 28894 const tc *const pcolor = color._data; 28895 const float opac = n_primitive<opacities.size()?opacities(n_primitive,0):1.0f; 28896 #ifdef cimg_use_board 28897 LibBoard::Board &board = *(LibBoard::Board*)pboard; 28898 #endif 28899 28900 switch (primitive.size()) { 28901 case 1 : { // Colored point or sprite 28902 const unsigned int n0 = (unsigned int)primitive[0]; 28903 const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1); 28904 if (color.size()==_spectrum) { // Colored point. 28905 draw_point(x0,y0,pcolor,opac); 28906 #ifdef cimg_use_board 28907 if (pboard) { 28908 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28909 board.fillCircle((float)x0,height()-(float)y0,0); 28910 } 28911 #endif 28912 } else { // Colored sprite. 28913 const float z = Z + vertices(n0,2); 28914 const int 28915 factor = (int)(focale*100/(z+focale)), 28916 sw = color._width*factor/200, 28917 sh = color._height*factor/200, 28918 nx0 = x0 - sw, ny0 = y0 - sh; 28919 if (x0+sw>=0 && nx0<width() && y0+sh>=0 && ny0<height()) { 28920 const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3); 28921 __draw_object3d(n_primitive,opacities,color,nx0,ny0,sprite,opac); 28922 #ifdef cimg_use_board 28923 if (pboard) { 28924 board.setPenColorRGBi(128,128,128); 28925 board.setFillColor(LibBoard::Color::None); 28926 board.drawRectangle((float)nx0,height()-(float)ny0,sw,sh); 28927 } 28928 #endif 28929 } 28930 } 28931 } break; 28932 case 2 : { // Colored line 28933 const unsigned int 28934 n0 = (unsigned int)primitive[0], 28935 n1 = (unsigned int)primitive[1]; 28936 const int 28937 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 28938 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); 28939 const float 28940 z0 = vertices(n0,2) + Z + focale, 28941 z1 = vertices(n1,2) + Z + focale; 28942 if (render_type) { 28943 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opac); 28944 else draw_line(x0,y0,x1,y1,pcolor,opac); 28945 #ifdef cimg_use_board 28946 if (pboard) { 28947 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28948 board.drawLine((float)x0,height()-(float)y0,x1,height()-(float)y1); 28949 } 28950 #endif 28951 } else { 28952 draw_point(x0,y0,pcolor,opac).draw_point(x1,y1,pcolor,opac); 28953 #ifdef cimg_use_board 28954 if (pboard) { 28955 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28956 board.drawCircle((float)x0,height()-(float)y0,0); 28957 board.drawCircle((float)x1,height()-(float)y1,0); 28958 } 28959 #endif 28960 } 28961 } break; 28962 case 5 : { // Colored sphere 28963 const unsigned int 28964 n0 = (unsigned int)primitive[0], 28965 n1 = (unsigned int)primitive[1]; 28966 const float 28967 Xc = 0.5f*((float)vertices(n0,0) + (float)vertices(n1,0)), 28968 Yc = 0.5f*((float)vertices(n0,1) + (float)vertices(n1,1)), 28969 Zc = 0.5f*((float)vertices(n0,2) + (float)vertices(n1,2)), 28970 zc = Z + Zc + focale, 28971 xc = X + focale*Xc/zc, 28972 yc = Y + focale*Yc/zc, 28973 radius = std::sqrt(cimg::sqr(Xc-vertices(n0,0)) + cimg::sqr(Yc-vertices(n0,1)) + cimg::sqr(Zc-vertices(n0,2)))*focale/zc; 28974 switch (render_type) { 28975 case 0 : 28976 draw_point((int)xc,(int)yc,pcolor,opac); 28977 #ifdef cimg_use_board 28978 if (pboard) { 28979 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28980 board.fillCircle(xc,height()-yc,0); 28981 } 28982 #endif 28983 break; 28984 case 1 : 28985 draw_circle((int)xc,(int)yc,(int)radius,pcolor,opac,~0U); 28986 #ifdef cimg_use_board 28987 if (pboard) { 28988 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28989 board.setFillColor(LibBoard::Color::None); 28990 board.drawCircle(xc,height()-yc,radius); 28991 } 28992 #endif 28993 break; 28994 default : 28995 draw_circle((int)xc,(int)yc,(int)radius,pcolor,opac); 28996 #ifdef cimg_use_board 28997 if (pboard) { 28998 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 28999 board.fillCircle(xc,height()-yc,radius); 29000 } 29001 #endif 29002 break; 29003 } 29004 } break; 29005 case 6 : { // Textured line 29006 const unsigned int 29007 n0 = (unsigned int)primitive[0], 29008 n1 = (unsigned int)primitive[1], 29009 tx0 = (unsigned int)primitive[2], 29010 ty0 = (unsigned int)primitive[3], 29011 tx1 = (unsigned int)primitive[4], 29012 ty1 = (unsigned int)primitive[5]; 29013 const int 29014 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 29015 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); 29016 const float 29017 z0 = vertices(n0,2) + Z + focale, 29018 z1 = vertices(n1,2) + Z + focale; 29019 if (render_type) { 29020 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac); 29021 else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac); 29022 #ifdef cimg_use_board 29023 if (pboard) { 29024 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29025 board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); 29026 } 29027 #endif 29028 } else { 29029 draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opac). 29030 draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opac); 29031 #ifdef cimg_use_board 29032 if (pboard) { 29033 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29034 board.drawCircle((float)x0,height()-(float)y0,0); 29035 board.drawCircle((float)x1,height()-(float)y1,0); 29036 } 29037 #endif 29038 } 29039 } break; 29040 case 3 : { // Colored triangle 29041 const unsigned int 29042 n0 = (unsigned int)primitive[0], 29043 n1 = (unsigned int)primitive[1], 29044 n2 = (unsigned int)primitive[2]; 29045 const int 29046 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 29047 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), 29048 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); 29049 const float 29050 z0 = vertices(n0,2) + Z + focale, 29051 z1 = vertices(n1,2) + Z + focale, 29052 z2 = vertices(n2,2) + Z + focale; 29053 switch (render_type) { 29054 case 0 : 29055 draw_point(x0,y0,pcolor,opac).draw_point(x1,y1,pcolor,opac).draw_point(x2,y2,pcolor,opac); 29056 #ifdef cimg_use_board 29057 if (pboard) { 29058 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29059 board.drawCircle((float)x0,height()-(float)y0,0); 29060 board.drawCircle((float)x1,height()-(float)y1,0); 29061 board.drawCircle((float)x2,height()-(float)y2,0); 29062 } 29063 #endif 29064 break; 29065 case 1 : 29066 if (zbuffer) 29067 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,pcolor,opac). 29068 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opac); 29069 else 29070 draw_line(x0,y0,x1,y1,pcolor,opac).draw_line(x0,y0,x2,y2,pcolor,opac). 29071 draw_line(x1,y1,x2,y2,pcolor,opac); 29072 #ifdef cimg_use_board 29073 if (pboard) { 29074 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29075 board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); 29076 board.drawLine((float)x0,height()-(float)y0,(float)x2,height()-(float)y2); 29077 board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29078 } 29079 #endif 29080 break; 29081 case 2 : 29082 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opac); 29083 else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opac); 29084 #ifdef cimg_use_board 29085 if (pboard) { 29086 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29087 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29088 } 29089 #endif 29090 break; 29091 case 3 : 29092 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opac,lightprops(l)); 29093 else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opac,lightprops(l)); 29094 #ifdef cimg_use_board 29095 if (pboard) { 29096 const float lp = cimg::min(lightprops(l),1); 29097 board.setPenColorRGBi((unsigned char)(color[0]*lp), 29098 (unsigned char)(color[1]*lp), 29099 (unsigned char)(color[2]*lp), 29100 (unsigned char)(opac*255)); 29101 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29102 } 29103 #endif 29104 break; 29105 case 4 : 29106 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opac); 29107 else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opac); 29108 #ifdef cimg_use_board 29109 if (pboard) { 29110 board.setPenColorRGBi((unsigned char)(color[0]), 29111 (unsigned char)(color[1]), 29112 (unsigned char)(color[2]), 29113 (unsigned char)(opac*255)); 29114 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprops(n0), 29115 (float)x1,height()-(float)y1,lightprops(n1), 29116 (float)x2,height()-(float)y2,lightprops(n2)); 29117 } 29118 #endif 29119 break; 29120 case 5 : { 29121 const unsigned int 29122 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), 29123 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), 29124 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1); 29125 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac); 29126 else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac); 29127 #ifdef cimg_use_board 29128 if (pboard) { 29129 const float 29130 l0 = light_texture((int)(light_texture.width()/2*(1+lightprops(n0,0))), (int)(light_texture.height()/2*(1+lightprops(n0,1)))), 29131 l1 = light_texture((int)(light_texture.width()/2*(1+lightprops(n1,0))), (int)(light_texture.height()/2*(1+lightprops(n1,1)))), 29132 l2 = light_texture((int)(light_texture.width()/2*(1+lightprops(n2,0))), (int)(light_texture.height()/2*(1+lightprops(n2,1)))); 29133 board.setPenColorRGBi((unsigned char)(color[0]), 29134 (unsigned char)(color[1]), 29135 (unsigned char)(color[2]), 29136 (unsigned char)(opac*255)); 29137 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, 29138 (float)x1,height()-(float)y1,l1, 29139 (float)x2,height()-(float)y2,l2); 29140 } 29141 #endif 29142 } break; 29143 } 29144 } break; 29145 case 4 : { // Colored rectangle 29146 const unsigned int 29147 n0 = (unsigned int)primitive[0], 29148 n1 = (unsigned int)primitive[1], 29149 n2 = (unsigned int)primitive[2], 29150 n3 = (unsigned int)primitive[3]; 29151 const int 29152 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 29153 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), 29154 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), 29155 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); 29156 const float 29157 z0 = vertices(n0,2) + Z + focale, 29158 z1 = vertices(n1,2) + Z + focale, 29159 z2 = vertices(n2,2) + Z + focale, 29160 z3 = vertices(n3,2) + Z + focale; 29161 switch (render_type) { 29162 case 0 : 29163 draw_point(x0,y0,pcolor,opac).draw_point(x1,y1,pcolor,opac). 29164 draw_point(x2,y2,pcolor,opac).draw_point(x3,y3,pcolor,opac); 29165 #ifdef cimg_use_board 29166 if (pboard) { 29167 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29168 board.drawCircle((float)x0,height()-(float)y0,0); 29169 board.drawCircle((float)x1,height()-(float)y1,0); 29170 board.drawCircle((float)x2,height()-(float)y2,0); 29171 board.drawCircle((float)x3,height()-(float)y3,0); 29172 } 29173 #endif 29174 break; 29175 case 1 : 29176 if (zbuffer) 29177 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opac). 29178 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,pcolor,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,pcolor,opac); 29179 else 29180 draw_line(x0,y0,x1,y1,pcolor,opac).draw_line(x1,y1,x2,y2,pcolor,opac). 29181 draw_line(x2,y2,x3,y3,pcolor,opac).draw_line(x3,y3,x0,y0,pcolor,opac); 29182 #ifdef cimg_use_board 29183 if (pboard) { 29184 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29185 board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); 29186 board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29187 board.drawLine((float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29188 board.drawLine((float)x3,height()-(float)y3,(float)x0,height()-(float)y0); 29189 } 29190 #endif 29191 break; 29192 case 2 : 29193 if (zbuffer) 29194 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opac).draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opac); 29195 else 29196 draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opac).draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opac); 29197 #ifdef cimg_use_board 29198 if (pboard) { 29199 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255)); 29200 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29201 board.fillTriangle((float)x0,height()-(float)y0,(float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29202 } 29203 #endif 29204 break; 29205 case 3 : 29206 if (zbuffer) 29207 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opac,lightprops(l)). 29208 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opac,lightprops(l)); 29209 else 29210 _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opac,lightprops(l)). 29211 _draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opac,lightprops(l)); 29212 #ifdef cimg_use_board 29213 if (pboard) { 29214 const float lp = cimg::min(lightprops(l),1); 29215 board.setPenColorRGBi((unsigned char)(color[0]*lp), 29216 (unsigned char)(color[1]*lp), 29217 (unsigned char)(color[2]*lp),(unsigned char)(opac*255)); 29218 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29219 board.fillTriangle((float)x0,height()-(float)y0,(float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29220 } 29221 #endif 29222 break; 29223 case 4 : { 29224 const float 29225 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), 29226 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); 29227 if (zbuffer) 29228 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,lightprop0,lightprop1,lightprop2,opac). 29229 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,lightprop0,lightprop2,lightprop3,opac); 29230 else 29231 draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprop0,lightprop1,lightprop2,opac). 29232 draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,lightprop0,lightprop2,lightprop3,opac); 29233 #ifdef cimg_use_board 29234 if (pboard) { 29235 board.setPenColorRGBi((unsigned char)(color[0]), 29236 (unsigned char)(color[1]), 29237 (unsigned char)(color[2]), 29238 (unsigned char)(opac*255)); 29239 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, 29240 (float)x1,height()-(float)y1,lightprop1, 29241 (float)x2,height()-(float)y2,lightprop2); 29242 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, 29243 (float)x2,height()-(float)y2,lightprop2, 29244 (float)x3,height()-(float)y3,lightprop3); 29245 } 29246 #endif 29247 } break; 29248 case 5 : { 29249 const unsigned int 29250 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), 29251 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), 29252 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), 29253 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); 29254 if (zbuffer) 29255 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). 29256 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); 29257 else 29258 draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). 29259 draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); 29260 #ifdef cimg_use_board 29261 if (pboard) { 29262 const float 29263 l0 = light_texture((int)(light_texture.width()/2*(1+lx0)), (int)(light_texture.height()/2*(1+ly0))), 29264 l1 = light_texture((int)(light_texture.width()/2*(1+lx1)), (int)(light_texture.height()/2*(1+ly1))), 29265 l2 = light_texture((int)(light_texture.width()/2*(1+lx2)), (int)(light_texture.height()/2*(1+ly2))), 29266 l3 = light_texture((int)(light_texture.width()/2*(1+lx3)), (int)(light_texture.height()/2*(1+ly3))); 29267 board.setPenColorRGBi((unsigned char)(color[0]), 29268 (unsigned char)(color[1]), 29269 (unsigned char)(color[2]), 29270 (unsigned char)(opac*255)); 29271 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, 29272 (float)x1,height()-(float)y1,l1, 29273 (float)x2,height()-(float)y2,l2); 29274 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, 29275 (float)x2,height()-(float)y2,l2, 29276 (float)x3,height()-(float)y3,l3); 29277 } 29278 #endif 29279 } break; 29280 } 29281 } break; 29282 case 9 : { // Textured triangle 29283 const unsigned int 29284 n0 = (unsigned int)primitive[0], 29285 n1 = (unsigned int)primitive[1], 29286 n2 = (unsigned int)primitive[2], 29287 tx0 = (unsigned int)primitive[3], 29288 ty0 = (unsigned int)primitive[4], 29289 tx1 = (unsigned int)primitive[5], 29290 ty1 = (unsigned int)primitive[6], 29291 tx2 = (unsigned int)primitive[7], 29292 ty2 = (unsigned int)primitive[8]; 29293 const int 29294 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 29295 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), 29296 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); 29297 const float 29298 z0 = vertices(n0,2) + Z + focale, 29299 z1 = vertices(n1,2) + Z + focale, 29300 z2 = vertices(n2,2) + Z + focale; 29301 switch (render_type) { 29302 case 0 : 29303 draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opac). 29304 draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opac). 29305 draw_point(x2,y2,color.get_vector_at(tx2,ty2)._data,opac); 29306 #ifdef cimg_use_board 29307 if (pboard) { 29308 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29309 board.drawCircle((float)x0,height()-(float)y0,0); 29310 board.drawCircle((float)x1,height()-(float)y1,0); 29311 board.drawCircle((float)x2,height()-(float)y2,0); 29312 } 29313 #endif 29314 break; 29315 case 1 : 29316 if (zbuffer) 29317 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac). 29318 draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac). 29319 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac); 29320 else 29321 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac). 29322 draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac). 29323 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac); 29324 #ifdef cimg_use_board 29325 if (pboard) { 29326 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29327 board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); 29328 board.drawLine((float)x0,height()-(float)y0,(float)x2,height()-(float)y2); 29329 board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29330 } 29331 #endif 29332 break; 29333 case 2 : 29334 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac); 29335 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac); 29336 #ifdef cimg_use_board 29337 if (pboard) { 29338 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29339 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29340 } 29341 #endif 29342 break; 29343 case 3 : 29344 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)); 29345 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)); 29346 #ifdef cimg_use_board 29347 if (pboard) { 29348 const float lp = cimg::min(lightprops(l),1); 29349 board.setPenColorRGBi((unsigned char)(128*lp), 29350 (unsigned char)(128*lp), 29351 (unsigned char)(128*lp), 29352 (unsigned char)(opac*255)); 29353 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29354 } 29355 #endif 29356 break; 29357 case 4 : 29358 if (zbuffer) 29359 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac); 29360 else 29361 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac); 29362 #ifdef cimg_use_board 29363 if (pboard) { 29364 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29365 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprops(n0), 29366 (float)x1,height()-(float)y1,lightprops(n1), 29367 (float)x2,height()-(float)y2,lightprops(n2)); 29368 } 29369 #endif 29370 break; 29371 case 5 : 29372 if (zbuffer) 29373 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, 29374 (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), 29375 (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), 29376 (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), 29377 opac); 29378 else 29379 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, 29380 (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), 29381 (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), 29382 (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), 29383 opac); 29384 #ifdef cimg_use_board 29385 if (pboard) { 29386 const float 29387 l0 = light_texture((int)(light_texture.width()/2*(1+lightprops(n0,0))), (int)(light_texture.height()/2*(1+lightprops(n0,1)))), 29388 l1 = light_texture((int)(light_texture.width()/2*(1+lightprops(n1,0))), (int)(light_texture.height()/2*(1+lightprops(n1,1)))), 29389 l2 = light_texture((int)(light_texture.width()/2*(1+lightprops(n2,0))), (int)(light_texture.height()/2*(1+lightprops(n2,1)))); 29390 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29391 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0,(float)x1,height()-(float)y1,l1,(float)x2,height()-(float)y2,l2); 29392 } 29393 #endif 29394 break; 29395 } 29396 } break; 29397 case 12 : { // Textured quadrangle 29398 const unsigned int 29399 n0 = (unsigned int)primitive[0], 29400 n1 = (unsigned int)primitive[1], 29401 n2 = (unsigned int)primitive[2], 29402 n3 = (unsigned int)primitive[3], 29403 tx0 = (unsigned int)primitive[4], 29404 ty0 = (unsigned int)primitive[5], 29405 tx1 = (unsigned int)primitive[6], 29406 ty1 = (unsigned int)primitive[7], 29407 tx2 = (unsigned int)primitive[8], 29408 ty2 = (unsigned int)primitive[9], 29409 tx3 = (unsigned int)primitive[10], 29410 ty3 = (unsigned int)primitive[11]; 29411 const int 29412 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), 29413 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), 29414 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), 29415 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); 29416 const float 29417 z0 = vertices(n0,2) + Z + focale, 29418 z1 = vertices(n1,2) + Z + focale, 29419 z2 = vertices(n2,2) + Z + focale, 29420 z3 = vertices(n3,2) + Z + focale; 29421 29422 switch (render_type) { 29423 case 0 : 29424 draw_point(x0,y0,color.get_vector_at(tx0,ty0)._data,opac). 29425 draw_point(x1,y1,color.get_vector_at(tx1,ty1)._data,opac). 29426 draw_point(x2,y2,color.get_vector_at(tx2,ty2)._data,opac). 29427 draw_point(x3,y3,color.get_vector_at(tx3,ty3)._data,opac); 29428 #ifdef cimg_use_board 29429 if (pboard) { 29430 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29431 board.drawCircle((float)x0,height()-(float)y0,0); 29432 board.drawCircle((float)x1,height()-(float)y1,0); 29433 board.drawCircle((float)x2,height()-(float)y2,0); 29434 board.drawCircle((float)x3,height()-(float)y3,0); 29435 } 29436 #endif 29437 break; 29438 case 1 : 29439 if (zbuffer) 29440 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac). 29441 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac). 29442 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac). 29443 draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac); 29444 else 29445 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac). 29446 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac). 29447 draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac). 29448 draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac); 29449 #ifdef cimg_use_board 29450 if (pboard) { 29451 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29452 board.drawLine((float)x0,height()-(float)y0,(float)x1,height()-(float)y1); 29453 board.drawLine((float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29454 board.drawLine((float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29455 board.drawLine((float)x3,height()-(float)y3,(float)x0,height()-(float)y0); 29456 } 29457 #endif 29458 break; 29459 case 2 : 29460 if (zbuffer) 29461 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac). 29462 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac); 29463 else 29464 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac). 29465 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac); 29466 #ifdef cimg_use_board 29467 if (pboard) { 29468 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29469 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29470 board.fillTriangle((float)x0,height()-(float)y0,(float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29471 } 29472 #endif 29473 break; 29474 case 3 : 29475 if (zbuffer) 29476 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)). 29477 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l)); 29478 else 29479 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)). 29480 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l)); 29481 #ifdef cimg_use_board 29482 if (pboard) { 29483 const float lp = cimg::min(lightprops(l),1); 29484 board.setPenColorRGBi((unsigned char)(128*lp), 29485 (unsigned char)(128*lp), 29486 (unsigned char)(128*lp), 29487 (unsigned char)(opac*255)); 29488 board.fillTriangle((float)x0,height()-(float)y0,(float)x1,height()-(float)y1,(float)x2,height()-(float)y2); 29489 board.fillTriangle((float)x0,height()-(float)y0,(float)x2,height()-(float)y2,(float)x3,height()-(float)y3); 29490 } 29491 #endif 29492 break; 29493 case 4 : { 29494 const float 29495 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), 29496 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); 29497 if (zbuffer) 29498 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac). 29499 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac); 29500 else 29501 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac). 29502 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac); 29503 #ifdef cimg_use_board 29504 if (pboard) { 29505 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29506 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, 29507 (float)x1,height()-(float)y1,lightprop1, 29508 (float)x2,height()-(float)y2,lightprop2); 29509 board.fillGouraudTriangle((float)x0,height()-(float)y0,lightprop0, 29510 (float)x2,height()-(float)y2,lightprop2, 29511 (float)x3,height()-(float)y3,lightprop3); 29512 } 29513 #endif 29514 } break; 29515 case 5 : { 29516 const unsigned int 29517 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), 29518 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), 29519 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), 29520 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); 29521 if (zbuffer) 29522 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). 29523 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); 29524 else 29525 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). 29526 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); 29527 #ifdef cimg_use_board 29528 if (pboard) { 29529 const float 29530 l0 = light_texture((int)(light_texture.width()/2*(1+lx0)), (int)(light_texture.height()/2*(1+ly0))), 29531 l1 = light_texture((int)(light_texture.width()/2*(1+lx1)), (int)(light_texture.height()/2*(1+ly1))), 29532 l2 = light_texture((int)(light_texture.width()/2*(1+lx2)), (int)(light_texture.height()/2*(1+ly2))), 29533 l3 = light_texture((int)(light_texture.width()/2*(1+lx3)), (int)(light_texture.height()/2*(1+ly3))); 29534 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255)); 29535 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, 29536 (float)x1,height()-(float)y1,l1, 29537 (float)x2,height()-(float)y2,l2); 29538 board.fillGouraudTriangle((float)x0,height()-(float)y0,l0, 29539 (float)x2,height()-(float)y2,l2, 29540 (float)x3,height()-(float)y3,l3); 29541 } 29542 #endif 29543 } break; 29544 } 29545 } break; 29546 } 29547 } 29548 return *this; 29549 } 29550 29551 //@} 29552 //--------------------------- 29553 // 29554 //! \name Data Input 29555 //@{ 29556 //--------------------------- 29557 29558 //! Simple interface to select a shape from an image. 29559 /** 29560 \param selection Array of 6 values containing the selection result 29561 \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle) 29562 \param disp Display window used to make the selection 29563 \param XYZ Initial XYZ position (for volumetric images only) 29564 \param color Color of the shape selector. 29565 **/ 29566 CImg<T>& select(CImgDisplay &disp, 29567 const int select_type=2, unsigned int *const XYZ=0, 29568 const unsigned char *const color=0) { 29569 return get_select(disp,select_type,XYZ,color).move_to(*this); 29570 } 29571 29572 //! Simple interface to select a shape from an image. 29573 CImg<T>& select(const char *const title, 29574 const int select_type=2, unsigned int *const XYZ=0, 29575 const unsigned char *const color=0) { 29576 return get_select(title,select_type,XYZ,color).move_to(*this); 29577 } 29578 29579 //! Simple interface to select a shape from an image. 29580 CImg<intT> get_select(CImgDisplay &disp, 29581 const int select_type=2, unsigned int *const XYZ=0, 29582 const unsigned char *const color=0) const { 29583 return _get_select(disp,0,select_type,XYZ,color,0,0,0); 29584 } 29585 29586 //! Simple interface to select a shape from an image. 29587 CImg<intT> get_select(const char *const title, 29588 const int select_type=2, unsigned int *const XYZ=0, 29589 const unsigned char *const color=0) const { 29590 CImgDisplay disp; 29591 return _get_select(disp,title,select_type,XYZ,color,0,0,0); 29592 } 29593 29594 CImg<intT> _get_select(CImgDisplay &disp, const char *const title, 29595 const int coords_type, unsigned int *const XYZ, 29596 const unsigned char *const color, 29597 const int origX, const int origY, const int origZ) const { 29598 if (is_empty()) 29599 throw CImgInstanceException(_cimg_instance 29600 "select() : Empty instance.", 29601 cimg_instance); 29602 if (!disp) { 29603 char ntitle[64] = { 0 }; if (!title) { std::sprintf(ntitle,"CImg<%s>",pixel_type()); } 29604 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:ntitle,1); 29605 } 29606 29607 const unsigned int 29608 old_normalization = disp.normalization(), 29609 hatch = 0x55555555; 29610 29611 bool old_is_resized = disp.is_resized(); 29612 disp._normalization = 0; 29613 disp.show().set_key(0).set_wheel(); 29614 29615 unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 }; 29616 if (color) std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,spectrum())); 29617 29618 int area = 0, clicked_area = 0, phase = 0, 29619 X0 = (int)((XYZ?XYZ[0]:_width/2)%_width), Y0 = (int)((XYZ?XYZ[1]:_height/2)%_height), Z0 = (int)((XYZ?XYZ[2]:_depth/2)%_depth), 29620 X1 =-1, Y1 = -1, Z1 = -1, 29621 X = -1, Y = -1, Z = -1, 29622 oX = X, oY = Y, oZ = Z; 29623 unsigned int old_button = 0, key = 0; 29624 29625 bool shape_selected = false, text_down = false; 29626 CImg<ucharT> visu, visu0; 29627 char text[1024] = { 0 }; 29628 29629 while (!key && !disp.is_closed() && !shape_selected) { 29630 29631 // Handle mouse motion and selection 29632 oX = X; oY = Y; oZ = Z; 29633 int mx = disp.mouse_x(), my = disp.mouse_y(); 29634 const int mX = mx*(_width+(_depth>1?_depth:0))/disp.width(), mY = my*(_height+(_depth>1?_depth:0))/disp.height(); 29635 29636 area = 0; 29637 if (mX<width() && mY<height()) { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; } 29638 if (mX<width() && mY>=height()) { area = 2; X = mX; Z = mY - _height; Y = phase?Y1:Y0; } 29639 if (mX>=width() && mY<height()) { area = 3; Y = mY; Z = mX - _width; X = phase?X1:X0; } 29640 29641 switch (key = disp.key()) { 29642 #if cimg_OS!=2 29643 case cimg::keyCTRLRIGHT : 29644 #endif 29645 case 0 : case cimg::keyCTRLLEFT : key = 0; break; 29646 case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(1); key = 0; } break; 29647 case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(-1); key = 0; } break; 29648 case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29649 disp.set_fullscreen(false).resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), 29650 CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). 29651 _is_resized = true; 29652 disp.set_key(key,false); key = 0; 29653 } break; 29654 case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29655 disp.set_fullscreen(false).resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; 29656 disp.set_key(key,false); key = 0; visu0.assign(); 29657 } break; 29658 case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29659 disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; 29660 disp.set_key(key,false); key = 0; visu0.assign(); 29661 } break; 29662 case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29663 disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; 29664 disp.set_key(key,false); key = 0; visu0.assign(); 29665 } break; 29666 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29667 static unsigned int snap_number = 0; 29668 char filename[32] = { 0 }; 29669 std::FILE *file; 29670 do { 29671 std::sprintf(filename,"CImg_%.4u.bmp",snap_number++); 29672 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 29673 } while (file); 29674 if (visu0) { 29675 visu.draw_text(0,0," Saving snapshot... ",foreground_color,background_color,1,13).display(disp); 29676 visu0.save(filename); 29677 visu.draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,1,13,filename).display(disp); 29678 } 29679 disp.set_key(key,false); key = 0; 29680 } break; 29681 case cimg::keyO : 29682 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 29683 static unsigned int snap_number = 0; 29684 char filename[32] = { 0 }; 29685 std::FILE *file; 29686 do { 29687 std::sprintf(filename,"CImg_%.4u.cimg",snap_number++); 29688 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 29689 } while (file); 29690 visu.draw_text(0,0," Saving instance... ",foreground_color,background_color,0.8f,13).display(disp); 29691 save(filename); 29692 visu.draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.8f,13,filename).display(disp); 29693 disp.set_key(key,false); key = 0; 29694 } break; 29695 } 29696 29697 if (!area) mx = my = X = Y = Z = -1; 29698 else { 29699 if (disp.button()&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; } 29700 if (!(disp.button()&1) && phase>=2) { 29701 switch (clicked_area) { 29702 case 1 : Z1 = Z; break; 29703 case 2 : Y1 = Y; break; 29704 case 3 : X1 = X; break; 29705 } 29706 } 29707 if (disp.button()&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } } 29708 if (disp.button()&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); } 29709 if (disp.wheel()) { 29710 if (_depth>1 && !disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT() && !disp.is_keySHIFTLEFT() && !disp.is_keySHIFTRIGHT() && 29711 !disp.is_keyALT() && !disp.is_keyALTGR()) { 29712 switch (area) { 29713 case 1 : if (phase) Z = (Z1+=disp.wheel()); else Z = (Z0+=disp.wheel()); break; 29714 case 2 : if (phase) Y = (Y1+=disp.wheel()); else Y = (Y0+=disp.wheel()); break; 29715 case 3 : if (phase) X = (X1+=disp.wheel()); else X = (X0+=disp.wheel()); break; 29716 } 29717 disp.set_wheel(); 29718 } else key = ~0U; 29719 } 29720 if ((disp.button()&1)!=old_button) { 29721 switch (phase++) { 29722 case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break; 29723 case 1 : X1 = X; Y1 = Y; Z1 = Z; break; 29724 } 29725 old_button = disp.button()&1; 29726 } 29727 if (_depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign(); 29728 } 29729 29730 if (phase) { 29731 if (!coords_type) shape_selected = phase?true:false; 29732 else { 29733 if (_depth>1) shape_selected = (phase==3)?true:false; 29734 else shape_selected = (phase==2)?true:false; 29735 } 29736 } 29737 29738 if (X0<0) X0 = 0; if (X0>=width()) X0 = width() - 1; if (Y0<0) Y0 = 0; if (Y0>=height()) Y0 = height() - 1; 29739 if (Z0<0) Z0 = 0; if (Z0>=depth()) Z0 = depth() - 1; 29740 if (X1<1) X1 = 0; if (X1>=width()) X1 = width() - 1; if (Y1<0) Y1 = 0; if (Y1>=height()) Y1 = height() - 1; 29741 if (Z1<0) Z1 = 0; if (Z1>=depth()) Z1 = depth() - 1; 29742 29743 // Draw visualization image on the display 29744 if (oX!=X || oY!=Y || oZ!=Z || !visu0) { 29745 if (!visu0) { 29746 CImg<Tuchar> tmp, tmp0; 29747 if (_depth!=1) { 29748 tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1); 29749 tmp = tmp0.get_channels(0,cimg::min(2U,_spectrum - 1)); 29750 } else tmp = get_channels(0,cimg::min(2U,_spectrum - 1)); 29751 switch (old_normalization) { 29752 case 0 : visu0 = tmp; break; 29753 case 3 : 29754 if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255); 29755 else { 29756 const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max(); 29757 visu0.assign(tmp._width,tmp._height,1,tmp._spectrum); 29758 unsigned char *ptrd = visu0.end(); 29759 cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs - m)*255.0f/(M - m)); 29760 } break; 29761 default : visu0 = tmp.normalize(0,255); 29762 } 29763 visu0.resize(disp); 29764 } 29765 visu = visu0; 29766 if (!color) { 29767 if (visu.mean()<200) { 29768 foreground_color[0] = foreground_color[1] = foreground_color[2] = 255; 29769 background_color[0] = background_color[1] = background_color[2] = 0; 29770 } else { 29771 foreground_color[0] = foreground_color[1] = foreground_color[2] = 0; 29772 background_color[0] = background_color[1] = background_color[2] = 255; 29773 } 29774 } 29775 29776 const int d = (_depth>1)?_depth:0; 29777 if (phase) switch (coords_type) { 29778 case 1 : { 29779 const int 29780 x0 = (int)((X0+0.5f)*disp.width()/(_width+d)), 29781 y0 = (int)((Y0+0.5f)*disp.height()/(_height+d)), 29782 x1 = (int)((X1+0.5f)*disp.width()/(_width+d)), 29783 y1 = (int)((Y1+0.5f)*disp.height()/(_height+d)); 29784 visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch); 29785 if (d) { 29786 const int 29787 zx0 = (int)((_width+Z0+0.5f)*disp.width()/(_width+d)), 29788 zx1 = (int)((_width+Z1+0.5f)*disp.width()/(_width+d)), 29789 zy0 = (int)((_height+Z0+0.5f)*disp.height()/(_height+d)), 29790 zy1 = (int)((_height+Z1+0.5f)*disp.height()/(_height+d)); 29791 visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch). 29792 draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch); 29793 } 29794 } break; 29795 case 2 : { 29796 const int 29797 x0 = (X0<X1?X0:X1)*disp.width()/(_width+d), 29798 y0 = (Y0<Y1?Y0:Y1)*disp.height()/(_height+d), 29799 x1 = ((X0<X1?X1:X0)+1)*disp.width()/(_width+d)-1, 29800 y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height()/(_height+d)-1; 29801 visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch); 29802 if (d) { 29803 const int 29804 zx0 = (int)((_width+(Z0<Z1?Z0:Z1))*disp.width()/(_width+d)), 29805 zy0 = (int)((_height+(Z0<Z1?Z0:Z1))*disp.height()/(_height+d)), 29806 zx1 = (int)((_width+(Z0<Z1?Z1:Z0)+1)*disp.width()/(_width+d))-1, 29807 zy1 = (int)((_height+(Z0<Z1?Z1:Z0)+1)*disp.height()/(_height+d))-1; 29808 visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch); 29809 visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch); 29810 } 29811 } break; 29812 case 3 : { 29813 const int 29814 x0 = X0*disp.width()/(_width+d), 29815 y0 = Y0*disp.height()/(_height+d), 29816 x1 = X1*disp.width()/(_width+d)-1, 29817 y1 = Y1*disp.height()/(_height+d)-1; 29818 visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),0,foreground_color,0.2f). 29819 draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),0,foreground_color,0.6f,hatch); 29820 if (d) { 29821 const int 29822 zx0 = (int)((_width+Z0)*disp.width()/(_width+d)), 29823 zy0 = (int)((_height+Z0)*disp.height()/(_height+d)), 29824 zx1 = (int)((_width+Z1+1)*disp.width()/(_width+d))-1, 29825 zy1 = (int)((_height+Z1+1)*disp.height()/(_height+d))-1; 29826 visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),0,foreground_color,0.2f). 29827 draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),0,foreground_color,0.6f,hatch). 29828 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),0,foreground_color,0.2f). 29829 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),0,foreground_color,0.6f,hatch); 29830 } 29831 } break; 29832 } else { 29833 const int 29834 x0 = X*disp.width()/(_width+d), 29835 y0 = Y*disp.height()/(_height+d), 29836 x1 = (X+1)*disp.width()/(_width+d)-1, 29837 y1 = (Y+1)*disp.height()/(_height+d)-1; 29838 if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U); 29839 } 29840 29841 if (my>=0 && my<13) text_down = true; else if (my>=visu.height()-13) text_down = false; 29842 if (!coords_type || !phase) { 29843 if (X>=0 && Y>=0 && Z>=0 && X<width() && Y<height() && Z<depth()) { 29844 if (_depth>1) std::sprintf(text," Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z); 29845 else std::sprintf(text," Point (%d,%d) = [ ",origX+X,origY+Y); 29846 char *ctext = text + std::strlen(text), *const ltext = text + 512; 29847 for (unsigned int c = 0; c<_spectrum && ctext<ltext; ++c) { 29848 std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,c))); 29849 ctext = text + std::strlen(text); 29850 *(ctext++) = ' '; *ctext = 0; 29851 } 29852 std::sprintf(text + std::strlen(text),"] "); 29853 } 29854 } else switch (coords_type) { 29855 case 1 : { 29856 const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ); 29857 if (_depth>1) std::sprintf(text," Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g ", 29858 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm); 29859 else std::sprintf(text," Vect (%d,%d)-(%d,%d), Norm = %g ", 29860 origX+X0,origY+Y0,origX+X1,origY+Y1,norm); 29861 } break; 29862 case 2 : 29863 if (_depth>1) std::sprintf(text," Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d) ", 29864 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1), 29865 origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0), 29866 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); 29867 else std::sprintf(text," Box (%d,%d)-(%d,%d), Size = (%d,%d) ", 29868 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0), 29869 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); 29870 break; 29871 default : 29872 if (_depth>1) std::sprintf(text," Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d) ", 29873 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1, 29874 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); 29875 else std::sprintf(text," Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d) ", 29876 origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); 29877 29878 } 29879 if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.height()-13:0,text,foreground_color,background_color,0.7f,13); 29880 disp.display(visu).wait(25); 29881 } else if (!shape_selected) disp.wait(); 29882 if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); } 29883 } 29884 29885 // Return result 29886 CImg<intT> res(1,6,1,1,-1); 29887 if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; } 29888 if (shape_selected) { 29889 if (coords_type==2) { 29890 if (X0>X1) cimg::swap(X0,X1); 29891 if (Y0>Y1) cimg::swap(Y0,Y1); 29892 if (Z0>Z1) cimg::swap(Z0,Z1); 29893 } 29894 if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1; 29895 switch (coords_type) { 29896 case 1 : case 2 : res[3] = X1; res[4] = Y1; res[5] = Z1; 29897 default : res[0] = X0; res[1] = Y0; res[2] = Z0; 29898 } 29899 } 29900 disp.set_button(); 29901 disp._normalization = old_normalization; 29902 disp._is_resized = old_is_resized; 29903 if (key!=~0U) disp.set_key(key); 29904 return res; 29905 } 29906 29907 //! Select sub-graph in a graph. 29908 CImg<intT> get_select_graph(CImgDisplay &disp, 29909 const unsigned int plot_type=1, const unsigned int vertex_type=1, 29910 const char *const labelx=0, const double xmin=0, const double xmax=0, 29911 const char *const labely=0, const double ymin=0, const double ymax=0) const { 29912 if (is_empty()) 29913 throw CImgInstanceException(_cimg_instance 29914 "display_graph() : Empty instance.", 29915 cimg_instance); 29916 29917 const unsigned int siz = _width*_height*_depth, onormalization = disp.normalization(); 29918 if (!disp) { char ntitle[64] = { 0 }; std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); } 29919 (disp.show().set_button().set_wheel())._normalization = 0; 29920 double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax; 29921 if (nymin==nymax) nymin = (Tfloat)min_max(nymax); 29922 if (nymin==nymax) { --nymin; ++nymax; } 29923 if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; } 29924 29925 const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 }; 29926 const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; 29927 static unsigned int odimv = 0; 29928 static CImg<ucharT> palette; 29929 if (odimv!=_spectrum) { 29930 odimv = _spectrum; 29931 palette = CImg<ucharT>(3,_spectrum,1,1,120).noise(70,1); 29932 if (_spectrum==1) { palette[0] = palette[1] = 120; palette[2] = 200; } 29933 else { 29934 palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10; 29935 if (_spectrum>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; } 29936 if (_spectrum>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; } 29937 } 29938 } 29939 29940 CImg<ucharT> visu0, visu, graph, text, axes; 29941 const unsigned int whd = _width*_height*_depth; 29942 int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2; 29943 char message[1024] = { 0 }; 29944 unsigned int okey = 0, obutton = 0; 29945 CImg_3x3(I,unsigned char); 29946 29947 for (bool selected = false; !selected && !disp.is_closed() && !okey && !disp.wheel(); ) { 29948 const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); 29949 const unsigned int key = disp.key(), button = disp.button(); 29950 29951 // Generate graph representation. 29952 if (!visu0) { 29953 visu0.assign(disp.width(),disp.height(),1,3,220); 29954 const int gdimx = disp.width() - 32, gdimy = disp.height() - 32; 29955 if (gdimx>0 && gdimy>0) { 29956 graph.assign(gdimx,gdimy,1,3,255); 29957 graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333); 29958 cimg_forC(*this,c) graph.draw_graph(get_shared_channel(c),&palette(0,c),(plot_type!=3 || _spectrum==1)?1:0.6f, 29959 plot_type,vertex_type,nymax,nymin,false); 29960 29961 axes.assign(gdimx,gdimy,1,1,0); 29962 const float 29963 dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin), 29964 px = (float)std::pow(10.0,(int)std::log10(dx)-2.0), 29965 py = (float)std::pow(10.0,(int)std::log10(dy)-2.0); 29966 const CImg<Tdouble> 29967 seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px), 29968 seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py); 29969 axes.draw_axes(seqx,seqy,white); 29970 if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray); 29971 if (nymax<0) axes.draw_axis(seqx,0,gray); 29972 if (nxmin>0) axes.draw_axis(0,seqy,gray); 29973 if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray); 29974 29975 cimg_for3x3(axes,x,y,0,0,I,unsigned char) 29976 if (Icc) { 29977 if (Icc==255) cimg_forC(graph,c) graph(x,y,c) = 0; 29978 else cimg_forC(graph,c) graph(x,y,c) = (unsigned char)(2*graph(x,y,c)/3); 29979 } 29980 else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forC(graph,c) graph(x,y,c) = (graph(x,y,c)+255)/2; 29981 29982 visu0.draw_image(16,16,graph); 29983 visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2). 29984 draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white); 29985 } else graph.assign(); 29986 text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1,13); 29987 visu0.draw_image((visu0.width()-text.width())/2,visu0.height()-14,~text); 29988 text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1,13).rotate(-90); 29989 visu0.draw_image(2,(visu0.height()-text.height())/2,~text); 29990 visu.assign(); 29991 } 29992 29993 // Generate and display current view. 29994 if (!visu) { 29995 visu.assign(visu0); 29996 if (graph && x0>=0 && x1>=0) { 29997 const int 29998 nx0 = x0<=x1?x0:x1, 29999 nx1 = x0<=x1?x1:x0, 30000 ny0 = y0<=y1?y0:y1, 30001 ny1 = y0<=y1?y1:y0, 30002 sx0 = 16 + nx0*(visu.width()-32)/whd, 30003 sx1 = 15 + (nx1+1)*(visu.width()-32)/whd, 30004 sy0 = 16 + ny0, 30005 sy1 = 16 + ny1; 30006 30007 if (y0>=0 && y1>=0) 30008 visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU); 30009 else visu.draw_rectangle(sx0,0,sx1,visu.height()-17,gray,0.5f). 30010 draw_line(sx0,16,sx0,visu.height()-17,black,0.5f,0xCCCCCCCCU). 30011 draw_line(sx1,16,sx1,visu.height()-17,black,0.5f,0xCCCCCCCCU); 30012 } 30013 if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.width()-16 && mouse_y<visu.height()-16) { 30014 if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.height()-17,black,0.5f,0x55555555U); 30015 const unsigned x = (mouse_x-16)*whd/(disp.width()-32); 30016 const double cx = nxmin + x*(nxmax-nxmin)/whd; 30017 if (_spectrum>=7) 30018 std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx, 30019 (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2), 30020 (double)(*this)(x,0,0,_spectrum-4),(double)(*this)(x,0,0,_spectrum-3),(double)(*this)(x,0,0,_spectrum-1)); 30021 else { 30022 std::sprintf(message,"Value[%g] = ( ",cx); 30023 cimg_forC(*this,c) std::sprintf(message+std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); 30024 std::sprintf(message+std::strlen(message),")"); 30025 } 30026 if (x0>=0 && x1>=0) { 30027 const int 30028 nx0 = x0<=x1?x0:x1, 30029 nx1 = x0<=x1?x1:x0, 30030 ny0 = y0<=y1?y0:y1, 30031 ny1 = y0<=y1?y1:y0; 30032 const double 30033 cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.width()-32), 30034 cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.width()-32), 30035 cy0 = nymax - ny0*(nymax-nymin)/(visu.height()-32), 30036 cy1 = nymax - ny1*(nymax-nymin)/(visu.height()-32); 30037 if (y0>=0 && y1>=0) 30038 std::sprintf(message+std::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1); 30039 else 30040 std::sprintf(message+std::strlen(message)," - Range [ %g - %g ]",cx0,cx1); 30041 } 30042 text.assign().draw_text(0,0,message,white,ngray,1,13); 30043 visu.draw_image((visu.width()-text.width())/2,1,~text); 30044 } 30045 visu.display(disp); 30046 } 30047 30048 // Test keys. 30049 switch (okey = key) { 30050 #if cimg_OS!=2 30051 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : 30052 #endif 30053 case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : okey = 0; break; 30054 case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 30055 disp.set_fullscreen(false).resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), 30056 CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). 30057 _is_resized = true; 30058 disp.set_key(key,false); okey = 0; 30059 } break; 30060 case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 30061 disp.set_fullscreen(false).resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; 30062 disp.set_key(key,false); okey = 0; 30063 } break; 30064 case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 30065 disp.set_fullscreen(false).resize(cimg_fitscreen(640,480,1),false)._is_resized = true; 30066 disp.set_key(key,false); okey = 0; 30067 } break; 30068 case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 30069 disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; 30070 disp.set_key(key,false); okey = 0; 30071 } break; 30072 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 30073 static unsigned int snap_number = 0; 30074 if (visu || visu0) { 30075 CImg<ucharT> &screen = visu?visu:visu0; 30076 char filename[32] = { 0 }; 30077 std::FILE *file; 30078 do { 30079 std::sprintf(filename,"CImg_%.4u.bmp",snap_number++); 30080 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 30081 } while (file); 30082 (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp); 30083 screen.save(filename); 30084 screen.draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename).display(disp); 30085 } 30086 disp.set_key(key,false); okey = 0; 30087 } break; 30088 } 30089 30090 // Handle mouse motion and mouse buttons 30091 if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) { 30092 visu.assign(); 30093 if (disp.mouse_x()>=0 && disp.mouse_y()>=0) { 30094 const int 30095 mx = (mouse_x-16)*(int)whd/(disp.width()-32), 30096 cx = mx<0?0:(mx>=(int)whd?whd-1:mx), 30097 my = mouse_y-16, 30098 cy = my<=0?0:(my>=(disp.height()-32)?(disp.height()-32):my); 30099 if (button&1) { 30100 if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; } 30101 } 30102 else if (button&2) { 30103 if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; } 30104 } 30105 else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; } 30106 } else if (!button && obutton) selected = true; 30107 obutton = button; omouse_x = mouse_x; omouse_y = mouse_y; 30108 } 30109 if (disp.is_resized()) { disp.resize(false); visu0.assign(); } 30110 if (visu && visu0) disp.wait(); 30111 } 30112 disp._normalization = onormalization; 30113 if (x1<x0) cimg::swap(x0,x1); 30114 if (y1<y0) cimg::swap(y0,y1); 30115 disp.set_key(okey); 30116 return CImg<intT>(4,1,1,1,x0,y0,x1,y1); 30117 } 30118 30119 //! Load an image from a file. 30120 /** 30121 \param filename is the name of the image file to load. 30122 \note The extension of \c filename defines the file format. If no filename 30123 extension is provided, CImg<T>::get_load() will try to load a .cimg file. 30124 **/ 30125 CImg<T>& load(const char *const filename) { 30126 if (!filename) 30127 throw CImgArgumentException(_cimg_instance 30128 "load() : Specified filename is (null).", 30129 cimg_instance); 30130 30131 const char *const ext = cimg::split_filename(filename); 30132 const unsigned int omode = cimg::exception_mode(); 30133 cimg::exception_mode() = 0; 30134 try { 30135 #ifdef cimg_load_plugin 30136 cimg_load_plugin(filename); 30137 #endif 30138 #ifdef cimg_load_plugin1 30139 cimg_load_plugin1(filename); 30140 #endif 30141 #ifdef cimg_load_plugin2 30142 cimg_load_plugin2(filename); 30143 #endif 30144 #ifdef cimg_load_plugin3 30145 cimg_load_plugin3(filename); 30146 #endif 30147 #ifdef cimg_load_plugin4 30148 cimg_load_plugin4(filename); 30149 #endif 30150 #ifdef cimg_load_plugin5 30151 cimg_load_plugin5(filename); 30152 #endif 30153 #ifdef cimg_load_plugin6 30154 cimg_load_plugin6(filename); 30155 #endif 30156 #ifdef cimg_load_plugin7 30157 cimg_load_plugin7(filename); 30158 #endif 30159 #ifdef cimg_load_plugin8 30160 cimg_load_plugin8(filename); 30161 #endif 30162 // ASCII formats 30163 if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename); 30164 else if (!cimg::strcasecmp(ext,"dlm") || 30165 !cimg::strcasecmp(ext,"txt")) load_dlm(filename); 30166 30167 // 2d binary formats 30168 else if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename); 30169 else if (!cimg::strcasecmp(ext,"jpg") || 30170 !cimg::strcasecmp(ext,"jpeg") || 30171 !cimg::strcasecmp(ext,"jpe") || 30172 !cimg::strcasecmp(ext,"jfif") || 30173 !cimg::strcasecmp(ext,"jif")) load_jpeg(filename); 30174 else if (!cimg::strcasecmp(ext,"png")) load_png(filename); 30175 else if (!cimg::strcasecmp(ext,"ppm") || 30176 !cimg::strcasecmp(ext,"pgm") || 30177 !cimg::strcasecmp(ext,"pnm")) load_pnm(filename); 30178 else if (!cimg::strcasecmp(ext,"pfm")) load_pfm(filename); 30179 else if (!cimg::strcasecmp(ext,"tif") || 30180 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); 30181 else if (!cimg::strcasecmp(ext,"exr")) load_exr(filename); 30182 else if (!cimg::strcasecmp(ext,"cr2") || 30183 !cimg::strcasecmp(ext,"crw") || 30184 !cimg::strcasecmp(ext,"dcr") || 30185 !cimg::strcasecmp(ext,"mrw") || 30186 !cimg::strcasecmp(ext,"nef") || 30187 !cimg::strcasecmp(ext,"orf") || 30188 !cimg::strcasecmp(ext,"pix") || 30189 !cimg::strcasecmp(ext,"ptx") || 30190 !cimg::strcasecmp(ext,"raf") || 30191 !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename); 30192 30193 // 3d binary formats 30194 else if (!cimg::strcasecmp(ext,"dcm") || 30195 !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename); 30196 else if (!cimg::strcasecmp(ext,"hdr") || 30197 !cimg::strcasecmp(ext,"nii")) load_analyze(filename); 30198 else if (!cimg::strcasecmp(ext,"par") || 30199 !cimg::strcasecmp(ext,"rec")) load_parrec(filename); 30200 else if (!cimg::strcasecmp(ext,"inr")) load_inr(filename); 30201 else if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename); 30202 else if (!cimg::strcasecmp(ext,"cimg") || 30203 !cimg::strcasecmp(ext,"cimgz") || 30204 !*ext) return load_cimg(filename); 30205 30206 // Archive files 30207 else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); 30208 30209 // Image sequences 30210 else if (!cimg::strcasecmp(ext,"avi") || 30211 !cimg::strcasecmp(ext,"mov") || 30212 !cimg::strcasecmp(ext,"asf") || 30213 !cimg::strcasecmp(ext,"divx") || 30214 !cimg::strcasecmp(ext,"flv") || 30215 !cimg::strcasecmp(ext,"mpg") || 30216 !cimg::strcasecmp(ext,"m1v") || 30217 !cimg::strcasecmp(ext,"m2v") || 30218 !cimg::strcasecmp(ext,"m4v") || 30219 !cimg::strcasecmp(ext,"mjp") || 30220 !cimg::strcasecmp(ext,"mkv") || 30221 !cimg::strcasecmp(ext,"mpe") || 30222 !cimg::strcasecmp(ext,"movie") || 30223 !cimg::strcasecmp(ext,"ogm") || 30224 !cimg::strcasecmp(ext,"qt") || 30225 !cimg::strcasecmp(ext,"rm") || 30226 !cimg::strcasecmp(ext,"vob") || 30227 !cimg::strcasecmp(ext,"wmv") || 30228 !cimg::strcasecmp(ext,"xvid") || 30229 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename); 30230 else throw CImgIOException("CImg<%s>::load()", 30231 pixel_type()); 30232 } catch (CImgException& e) { 30233 if (!cimg::strncasecmp(e.what(),"cimg::fopen()",13)) { 30234 cimg::exception_mode() = omode; 30235 throw CImgIOException(_cimg_instance 30236 "load() : Failed to open file '%s'.", 30237 cimg_instance, 30238 filename); 30239 } else try { 30240 const char *const f_type = cimg::file_type(0,filename); 30241 if (!cimg::strcasecmp(f_type,"pnm")) load_pnm(filename); 30242 else if (!cimg::strcasecmp(f_type,"pfm")) load_pfm(filename); 30243 else if (!cimg::strcasecmp(f_type,"bmp")) load_bmp(filename); 30244 else if (!cimg::strcasecmp(f_type,"jpg")) load_jpeg(filename); 30245 else if (!cimg::strcasecmp(f_type,"pan")) load_pandore(filename); 30246 else if (!cimg::strcasecmp(f_type,"png")) load_png(filename); 30247 else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); 30248 else if (!cimg::strcasecmp(f_type,"inr")) load_inr(filename); 30249 else if (!cimg::strcasecmp(f_type,"dcm")) load_medcon_external(filename); 30250 else throw CImgIOException("CImg<%s>::load()", 30251 pixel_type()); 30252 } catch (CImgException&) { 30253 try { 30254 load_other(filename); 30255 } catch (CImgException&) { 30256 throw CImgIOException(_cimg_instance 30257 "load() : Failed to recognize format of file '%s'.", 30258 cimg_instance, 30259 filename); 30260 } 30261 } 30262 } 30263 cimg::exception_mode() = omode; 30264 return *this; 30265 } 30266 30267 static CImg<T> get_load(const char *const filename) { 30268 return CImg<T>().load(filename); 30269 } 30270 30271 //! Load an image from an ASCII file. 30272 CImg<T>& load_ascii(const char *const filename) { 30273 return _load_ascii(0,filename); 30274 } 30275 30276 static CImg<T> get_load_ascii(const char *const filename) { 30277 return CImg<T>().load_ascii(filename); 30278 } 30279 30280 //! Load an image from an ASCII file. 30281 CImg<T>& load_ascii(std::FILE *const file) { 30282 return _load_ascii(file,0); 30283 } 30284 30285 static CImg<T> get_load_ascii(std::FILE *const file) { 30286 return CImg<T>().load_ascii(file); 30287 } 30288 30289 CImg<T>& _load_ascii(std::FILE *const file, const char *const filename) { 30290 if (!file && !filename) 30291 throw CImgArgumentException(_cimg_instance 30292 "load_ascii() : Specified filename is (null).", 30293 cimg_instance); 30294 30295 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 30296 char line[256] = { 0 }; 30297 int err = std::fscanf(nfile,"%255[^\n]",line); 30298 unsigned int off, dx = 0, dy = 1, dz = 1, dc = 1; 30299 std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dc); 30300 err = std::fscanf(nfile,"%*[^0-9.eE+-]"); 30301 if (!dx || !dy || !dz || !dc) { 30302 if (!file) cimg::fclose(nfile); 30303 throw CImgIOException(_cimg_instance 30304 "load_ascii() : Invalid ASCII header in file '%s', image dimensions are set to (%u,%u,%u,%u).", 30305 cimg_instance, 30306 filename?filename:"(FILE*)",dx,dy,dz,dc); 30307 } 30308 assign(dx,dy,dz,dc); 30309 const unsigned int siz = size(); 30310 double val; 30311 T *ptr = _data; 30312 for (err = 1, off = 0; off<siz && err==1; ++off) { 30313 err = std::fscanf(nfile,"%lf%*[^0-9.eE+-]",&val); 30314 *(ptr++) = (T)val; 30315 } 30316 if (err!=1) 30317 cimg::warn(_cimg_instance 30318 "load_ascii() : Only %u/%u values read from file '%s'.", 30319 cimg_instance, 30320 off-1,siz,filename?filename:"(FILE*)"); 30321 30322 if (!file) cimg::fclose(nfile); 30323 return *this; 30324 } 30325 30326 //! Load an image from a DLM file. 30327 CImg<T>& load_dlm(const char *const filename) { 30328 return _load_dlm(0,filename); 30329 } 30330 30331 static CImg<T> get_load_dlm(const char *const filename) { 30332 return CImg<T>().load_dlm(filename); 30333 } 30334 30335 //! Load an image from a DLM file. 30336 CImg<T>& load_dlm(std::FILE *const file) { 30337 return _load_dlm(file,0); 30338 } 30339 30340 static CImg<T> get_load_dlm(std::FILE *const file) { 30341 return CImg<T>().load_dlm(file); 30342 } 30343 30344 CImg<T>& _load_dlm(std::FILE *const file, const char *const filename) { 30345 if (!file && !filename) 30346 throw CImgArgumentException(_cimg_instance 30347 "load_dlm() : Specified filename is (null).", 30348 cimg_instance); 30349 30350 std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); 30351 char delimiter[256] = { 0 }, tmp[256] = { 0 }; 30352 unsigned int cdx = 0, dx = 0, dy = 0; 30353 int err = 0; 30354 double val; 30355 assign(256,256); 30356 while ((err = std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))>0) { 30357 if (err>0) (*this)(cdx++,dy) = (T)val; 30358 if (cdx>=_width) resize(3*_width/2,_height,1,1,0); 30359 char c = 0; 30360 if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { 30361 dx = cimg::max(cdx,dx); 30362 if (++dy>=_height) resize(_width,3*_height/2,1,1,0); 30363 cdx = 0; 30364 } 30365 } 30366 if (cdx && err==1) { dx = cdx; ++dy; } 30367 if (!dx || !dy) { 30368 if (!file) cimg::fclose(nfile); 30369 throw CImgIOException(_cimg_instance 30370 "load_dlm() : Invalid DLM file '%s'.", 30371 cimg_instance, 30372 filename?filename:"(FILE*)"); 30373 } 30374 resize(dx,dy,1,1,0); 30375 if (!file) cimg::fclose(nfile); 30376 return *this; 30377 } 30378 30379 //! Load an image from a BMP file. 30380 CImg<T>& load_bmp(const char *const filename) { 30381 return _load_bmp(0,filename); 30382 } 30383 30384 static CImg<T> get_load_bmp(const char *const filename) { 30385 return CImg<T>().load_bmp(filename); 30386 } 30387 30388 //! Load an image from a BMP file. 30389 CImg<T>& load_bmp(std::FILE *const file) { 30390 return _load_bmp(file,0); 30391 } 30392 30393 static CImg<T> get_load_bmp(std::FILE *const file) { 30394 return CImg<T>().load_bmp(file); 30395 } 30396 30397 CImg<T>& _load_bmp(std::FILE *const file, const char *const filename) { 30398 if (!file && !filename) 30399 throw CImgArgumentException(_cimg_instance 30400 "load_bmp() : Specified filename is (null).", 30401 cimg_instance); 30402 30403 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 30404 unsigned char header[64] = { 0 }; 30405 cimg::fread(header,54,nfile); 30406 if (header[0]!='B' || header[1]!='M') { 30407 if (!file) cimg::fclose(nfile); 30408 throw CImgIOException(_cimg_instance 30409 "load_bmp() : Invalid BMP file '%s'.", 30410 cimg_instance, 30411 filename?filename:"(FILE*)"); 30412 } 30413 30414 // Read header and pixel buffer 30415 int 30416 file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24), 30417 offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24), 30418 dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24), 30419 dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24), 30420 compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24), 30421 nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24), 30422 bpp = header[0x1C] + (header[0x1D]<<8); 30423 const int 30424 cimg_iobuffer = 12*1024*1024, 30425 dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)), 30426 align_bytes = (4-dx_bytes%4)%4, 30427 buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align_bytes),file_size-offset); 30428 30429 CImg<intT> palette; 30430 if (bpp<16) { if (!nb_colors) nb_colors = 1<<bpp; } else nb_colors = 0; 30431 if (nb_colors) { palette.assign(nb_colors); cimg::fread(palette._data,nb_colors,nfile); } 30432 const int xoffset = offset - 54 - 4*nb_colors; 30433 if (xoffset>0) std::fseek(nfile,xoffset,SEEK_CUR); 30434 30435 CImg<ucharT> buffer; 30436 if (buf_size<cimg_iobuffer) { buffer.assign(buf_size); cimg::fread(buffer._data,buf_size,nfile); } 30437 else buffer.assign(dx_bytes + align_bytes); 30438 unsigned char *ptrs = buffer; 30439 30440 // Decompress buffer (if necessary) 30441 if (compression) { 30442 if (file) 30443 throw CImgIOException(_cimg_instance 30444 "load_bmp() : Unable to load compressed data from '(*FILE)' inputs.", 30445 cimg_instance); 30446 else return load_other(filename); 30447 } 30448 30449 // Read pixel data 30450 assign(dx,cimg::abs(dy),1,3); 30451 switch (bpp) { 30452 case 1 : { // Monochrome 30453 for (int y = height()-1; y>=0; --y) { 30454 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30455 unsigned char mask = 0x80, val = 0; 30456 cimg_forX(*this,x) { 30457 if (mask==0x80) val = *(ptrs++); 30458 const unsigned char *col = (unsigned char*)(palette._data + (val&mask?1:0)); 30459 (*this)(x,y,2) = (T)*(col++); 30460 (*this)(x,y,1) = (T)*(col++); 30461 (*this)(x,y,0) = (T)*(col++); 30462 mask = cimg::ror(mask); 30463 } 30464 ptrs+=align_bytes; 30465 } 30466 } break; 30467 case 4 : { // 16 colors 30468 for (int y = height()-1; y>=0; --y) { 30469 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30470 unsigned char mask = 0xF0, val = 0; 30471 cimg_forX(*this,x) { 30472 if (mask==0xF0) val = *(ptrs++); 30473 const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4)); 30474 const unsigned char *col = (unsigned char*)(palette._data + color); 30475 (*this)(x,y,2) = (T)*(col++); 30476 (*this)(x,y,1) = (T)*(col++); 30477 (*this)(x,y,0) = (T)*(col++); 30478 mask = cimg::ror(mask,4); 30479 } 30480 ptrs+=align_bytes; 30481 } 30482 } break; 30483 case 8 : { // 256 colors 30484 for (int y = height()-1; y>=0; --y) { 30485 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30486 cimg_forX(*this,x) { 30487 const unsigned char *col = (unsigned char*)(palette._data + *(ptrs++)); 30488 (*this)(x,y,2) = (T)*(col++); 30489 (*this)(x,y,1) = (T)*(col++); 30490 (*this)(x,y,0) = (T)*(col++); 30491 } 30492 ptrs+=align_bytes; 30493 } 30494 } break; 30495 case 16 : { // 16 bits colors 30496 for (int y = height()-1; y>=0; --y) { 30497 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30498 cimg_forX(*this,x) { 30499 const unsigned char c1 = *(ptrs++), c2 = *(ptrs++); 30500 const unsigned short col = (unsigned short)(c1|(c2<<8)); 30501 (*this)(x,y,2) = (T)(col&0x1F); 30502 (*this)(x,y,1) = (T)((col>>5)&0x1F); 30503 (*this)(x,y,0) = (T)((col>>10)&0x1F); 30504 } 30505 ptrs+=align_bytes; 30506 } 30507 } break; 30508 case 24 : { // 24 bits colors 30509 for (int y = height()-1; y>=0; --y) { 30510 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30511 cimg_forX(*this,x) { 30512 (*this)(x,y,2) = (T)*(ptrs++); 30513 (*this)(x,y,1) = (T)*(ptrs++); 30514 (*this)(x,y,0) = (T)*(ptrs++); 30515 } 30516 ptrs+=align_bytes; 30517 } 30518 } break; 30519 case 32 : { // 32 bits colors 30520 for (int y = height()-1; y>=0; --y) { 30521 if (buf_size>=cimg_iobuffer) { cimg::fread(ptrs=buffer._data,dx_bytes,nfile); std::fseek(nfile,align_bytes,SEEK_CUR); } 30522 cimg_forX(*this,x) { 30523 (*this)(x,y,2) = (T)*(ptrs++); 30524 (*this)(x,y,1) = (T)*(ptrs++); 30525 (*this)(x,y,0) = (T)*(ptrs++); 30526 ++ptrs; 30527 } 30528 ptrs+=align_bytes; 30529 } 30530 } break; 30531 } 30532 if (dy<0) mirror('y'); 30533 if (!file) cimg::fclose(nfile); 30534 return *this; 30535 } 30536 30537 //! Load an image from a JPEG file. 30538 CImg<T>& load_jpeg(const char *const filename) { 30539 return _load_jpeg(0,filename); 30540 } 30541 30542 static CImg<T> get_load_jpeg(const char *const filename) { 30543 return CImg<T>().load_jpeg(filename); 30544 } 30545 30546 //! Load an image from a JPEG file. 30547 CImg<T>& load_jpeg(std::FILE *const file) { 30548 return _load_jpeg(file,0); 30549 } 30550 30551 static CImg<T> get_load_jpeg(std::FILE *const file) { 30552 return CImg<T>().load_jpeg(file); 30553 } 30554 30555 // Custom error handler for libjpeg. 30556 #ifdef cimg_use_jpeg 30557 METHODDEF(void) _cimg_jpeg_error_exit(j_common_ptr cinfo) { 30558 char message[JMSG_LENGTH_MAX]; 30559 (*cinfo->err->format_message)(cinfo,message); // Create the message. 30560 jpeg_destroy(cinfo); // Clean memory and temp files. 30561 throw CImgIOException("CImg<T>::load_jpeg() : Error message returned by libjpeg : %s.",message); 30562 } 30563 #endif 30564 30565 CImg<T>& _load_jpeg(std::FILE *const file, const char *const filename) { 30566 if (!file && !filename) 30567 throw CImgArgumentException(_cimg_instance 30568 "load_jpeg() : Specified filename is (null).", 30569 cimg_instance); 30570 30571 #ifndef cimg_use_jpeg 30572 if (file) 30573 throw CImgIOException(_cimg_instance 30574 "load_jpeg() : Unable to load data from '(FILE*)' unless libjpeg is enabled.", 30575 cimg_instance); 30576 else return load_other(filename); 30577 #else 30578 30579 struct jpeg_decompress_struct cinfo; 30580 struct jpeg_error_mgr jerr; 30581 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 30582 30583 cinfo.err = jpeg_std_error(&jerr); 30584 jerr.error_exit = _cimg_jpeg_error_exit; 30585 jpeg_create_decompress(&cinfo); 30586 jpeg_stdio_src(&cinfo,nfile); 30587 jpeg_read_header(&cinfo,TRUE); 30588 jpeg_start_decompress(&cinfo); 30589 30590 if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) { 30591 if (!file) return load_other(filename); 30592 else 30593 throw CImgIOException(_cimg_instance 30594 "load_jpeg() : Failed to load JPEG data from file '%s'.", 30595 cimg_instance,filename?filename:"(FILE*)"); 30596 } 30597 CImg<ucharT> buffer(cinfo.output_width*cinfo.output_components); 30598 JSAMPROW row_pointer[1]; 30599 assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); 30600 T *ptr_r = _data, *ptr_g = _data + _width*_height, *ptr_b = _data + 2*_width*_height, *ptr_a = _data + 3*_width*_height; 30601 while (cinfo.output_scanline<cinfo.output_height) { 30602 row_pointer[0] = buffer._data; 30603 if (jpeg_read_scanlines(&cinfo,row_pointer,1)!=1) { 30604 cimg::warn(_cimg_instance 30605 "load_jpeg() : Incomplete data in file '%s'.", 30606 cimg_instance,filename?filename:"(FILE*)"); 30607 break; 30608 } 30609 const unsigned char *ptrs = buffer._data; 30610 switch (_spectrum) { 30611 case 1 : { 30612 cimg_forX(*this,x) *(ptr_g++) = (T)*(ptrs++); 30613 } break; 30614 case 3 : { 30615 cimg_forX(*this,x) { 30616 *(ptr_r++) = (T)*(ptrs++); 30617 *(ptr_g++) = (T)*(ptrs++); 30618 *(ptr_b++) = (T)*(ptrs++); 30619 } 30620 } break; 30621 case 4 : { 30622 cimg_forX(*this,x) { 30623 *(ptr_r++) = (T)*(ptrs++); 30624 *(ptr_g++) = (T)*(ptrs++); 30625 *(ptr_b++) = (T)*(ptrs++); 30626 *(ptr_a++) = (T)*(ptrs++); 30627 } 30628 } break; 30629 } 30630 } 30631 jpeg_finish_decompress(&cinfo); 30632 jpeg_destroy_decompress(&cinfo); 30633 if (!file) cimg::fclose(nfile); 30634 return *this; 30635 #endif 30636 } 30637 30638 //! Load an image from a file, using Magick++ library. 30639 // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de> 30640 // This is experimental code, not much tested, use with care. 30641 CImg<T>& load_magick(const char *const filename) { 30642 if (!filename) 30643 throw CImgArgumentException(_cimg_instance 30644 "load_magick() : Specified filename is (null).", 30645 cimg_instance); 30646 30647 #ifdef cimg_use_magick 30648 Magick::Image image(filename); 30649 const unsigned int W = image.size().width(), H = image.size().height(); 30650 switch (image.type()) { 30651 case Magick::PaletteMatteType : 30652 case Magick::TrueColorMatteType : 30653 case Magick::ColorSeparationType : { 30654 assign(W,H,1,4); 30655 T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); 30656 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); 30657 for (unsigned int off = W*H; off; --off) { 30658 *(ptr_r++) = (T)(pixels->red); 30659 *(ptr_g++) = (T)(pixels->green); 30660 *(ptr_b++) = (T)(pixels->blue); 30661 *(ptr_a++) = (T)(pixels->opacity); 30662 ++pixels; 30663 } 30664 } break; 30665 case Magick::PaletteType : 30666 case Magick::TrueColorType : { 30667 assign(W,H,1,3); 30668 T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); 30669 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); 30670 for (unsigned int off = W*H; off; --off) { 30671 *(ptr_r++) = (T)(pixels->red); 30672 *(ptr_g++) = (T)(pixels->green); 30673 *(ptr_b++) = (T)(pixels->blue); 30674 ++pixels; 30675 } 30676 } break; 30677 case Magick::GrayscaleMatteType : { 30678 assign(W,H,1,2); 30679 T *ptr_r = data(0,0,0,0), *ptr_a = data(0,0,0,1); 30680 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); 30681 for (unsigned int off = W*H; off; --off) { 30682 *(ptr_r++) = (T)(pixels->red); 30683 *(ptr_a++) = (T)(pixels->opacity); 30684 ++pixels; 30685 } 30686 } break; 30687 default : { 30688 assign(W,H,1,1); 30689 T *ptr_r = data(0,0,0,0); 30690 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); 30691 for (unsigned int off = W*H; off; --off) { 30692 *(ptr_r++) = (T)(pixels->red); 30693 ++pixels; 30694 } 30695 } 30696 } 30697 #else 30698 throw CImgIOException(_cimg_instance 30699 "load_magick() : Unable to load file '%s' unless libMagick++ is enabled.", 30700 cimg_instance, 30701 filename); 30702 #endif 30703 return *this; 30704 } 30705 30706 static CImg<T> get_load_magick(const char *const filename) { 30707 return CImg<T>().load_magick(filename); 30708 } 30709 30710 //! Load an image from a PNG file. 30711 CImg<T>& load_png(const char *const filename) { 30712 return _load_png(0,filename); 30713 } 30714 30715 static CImg<T> get_load_png(const char *const filename) { 30716 return CImg<T>().load_png(filename); 30717 } 30718 30719 //! Load an image from a PNG file. 30720 CImg<T>& load_png(std::FILE *const file) { 30721 return _load_png(file,0); 30722 } 30723 30724 static CImg<T> get_load_png(std::FILE *const file) { 30725 return CImg<T>().load_png(file); 30726 } 30727 30728 // (Note : Most of this function has been written by Eric Fausett) 30729 CImg<T>& _load_png(std::FILE *const file, const char *const filename) { 30730 if (!file && !filename) 30731 throw CImgArgumentException(_cimg_instance 30732 "load_png() : Specified filename is (null).", 30733 cimg_instance); 30734 30735 #ifndef cimg_use_png 30736 if (file) 30737 throw CImgIOException(_cimg_instance 30738 "load_png() : Unable to load data from '(FILE*)' unless libpng is enabled.", 30739 cimg_instance); 30740 30741 else return load_other(filename); 30742 #else 30743 // Open file and check for PNG validity 30744 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'. 30745 std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb"); 30746 30747 unsigned char pngCheck[8] = { 0 }; 30748 cimg::fread(pngCheck,8,(std::FILE*)nfile); 30749 if (png_sig_cmp(pngCheck,0,8)) { 30750 if (!file) cimg::fclose(nfile); 30751 throw CImgIOException(_cimg_instance 30752 "load_png() : Invalid PNG file '%s'.", 30753 cimg_instance, 30754 nfilename?nfilename:"(FILE*)"); 30755 } 30756 30757 // Setup PNG structures for read 30758 png_voidp user_error_ptr = 0; 30759 png_error_ptr user_error_fn = 0, user_warning_fn = 0; 30760 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn); 30761 if (!png_ptr) { 30762 if (!file) cimg::fclose(nfile); 30763 throw CImgIOException(_cimg_instance 30764 "load_png() : Failed to initialize 'png_ptr' structure for file '%s'.", 30765 cimg_instance, 30766 nfilename?nfilename:"(FILE*)"); 30767 } 30768 png_infop info_ptr = png_create_info_struct(png_ptr); 30769 if (!info_ptr) { 30770 if (!file) cimg::fclose(nfile); 30771 png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0); 30772 throw CImgIOException(_cimg_instance 30773 "load_png() : Failed to initialize 'info_ptr' structure for file '%s'.", 30774 cimg_instance, 30775 nfilename?nfilename:"(FILE*)"); 30776 } 30777 png_infop end_info = png_create_info_struct(png_ptr); 30778 if (!end_info) { 30779 if (!file) cimg::fclose(nfile); 30780 png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0); 30781 throw CImgIOException(_cimg_instance 30782 "load_png() : Failed to initialize 'end_info' structure for file '%s'.", 30783 cimg_instance, 30784 nfilename?nfilename:"(FILE*)"); 30785 } 30786 30787 // Error handling callback for png file reading 30788 if (setjmp(png_jmpbuf(png_ptr))) { 30789 if (!file) cimg::fclose((std::FILE*)nfile); 30790 png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); 30791 throw CImgIOException(_cimg_instance 30792 "load_png() : Encountered unknown fatal error in libpng for file '%s'.", 30793 cimg_instance, 30794 nfilename?nfilename:"(FILE*)"); 30795 } 30796 png_init_io(png_ptr, nfile); 30797 png_set_sig_bytes(png_ptr, 8); 30798 30799 // Get PNG Header Info up to data block 30800 png_read_info(png_ptr,info_ptr); 30801 png_uint_32 W, H; 30802 int bit_depth, color_type, interlace_type; 30803 png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,(int*)0,(int*)0); 30804 int new_bit_depth = bit_depth; 30805 int new_color_type = color_type; 30806 30807 // Transforms to unify image data 30808 if (new_color_type == PNG_COLOR_TYPE_PALETTE){ 30809 png_set_palette_to_rgb(png_ptr); 30810 new_color_type-=PNG_COLOR_MASK_PALETTE; 30811 new_bit_depth = 8; 30812 } 30813 if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){ 30814 png_set_expand_gray_1_2_4_to_8(png_ptr); 30815 new_bit_depth = 8; 30816 } 30817 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 30818 png_set_tRNS_to_alpha(png_ptr); 30819 if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){ 30820 png_set_gray_to_rgb(png_ptr); 30821 new_color_type |= PNG_COLOR_MASK_COLOR; 30822 } 30823 if (new_color_type == PNG_COLOR_TYPE_RGB) 30824 png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER); 30825 png_read_update_info(png_ptr,info_ptr); 30826 if (!(new_bit_depth==8 || new_bit_depth==16)) { 30827 if (!file) cimg::fclose(nfile); 30828 png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0); 30829 throw CImgIOException(_cimg_instance 30830 "load_png() : Invalid bit depth %u in file '%s'.", 30831 cimg_instance, 30832 new_bit_depth,nfilename?nfilename:"(FILE*)"); 30833 } 30834 const int byte_depth = new_bit_depth>>3; 30835 30836 // Allocate Memory for Image Read 30837 png_bytep *const imgData = new png_bytep[H]; 30838 for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W]; 30839 png_read_image(png_ptr,imgData); 30840 png_read_end(png_ptr,end_info); 30841 30842 // Read pixel data 30843 if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) { 30844 if (!file) cimg::fclose(nfile); 30845 png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0); 30846 throw CImgIOException(_cimg_instance 30847 "load_png() : Invalid color coding type %u in file '%s'.", 30848 cimg_instance, 30849 new_color_type,nfilename?nfilename:"(FILE*)"); 30850 } 30851 const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB); 30852 assign(W,H,1,no_alpha_channel?3:4); 30853 T *ptr1 = data(0,0,0,0), *ptr2 = data(0,0,0,1), *ptr3 = data(0,0,0,2), *ptr4 = data(0,0,0,3); 30854 switch (new_bit_depth) { 30855 case 8 : { 30856 cimg_forY(*this,y){ 30857 const unsigned char *ptrs = (unsigned char*)imgData[y]; 30858 cimg_forX(*this,x){ 30859 *(ptr1++) = (T)*(ptrs++); 30860 *(ptr2++) = (T)*(ptrs++); 30861 *(ptr3++) = (T)*(ptrs++); 30862 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++); 30863 } 30864 } 30865 } break; 30866 case 16 : { 30867 cimg_forY(*this,y){ 30868 const unsigned short *ptrs = (unsigned short*)(imgData[y]); 30869 if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*_width); 30870 cimg_forX(*this,x){ 30871 *(ptr1++) = (T)*(ptrs++); 30872 *(ptr2++) = (T)*(ptrs++); 30873 *(ptr3++) = (T)*(ptrs++); 30874 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++); 30875 } 30876 } 30877 } break; 30878 } 30879 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 30880 30881 // Deallocate Image Read Memory 30882 cimg_forY(*this,n) delete[] imgData[n]; 30883 delete[] imgData; 30884 if (!file) cimg::fclose(nfile); 30885 return *this; 30886 #endif 30887 } 30888 30889 //! Load an image from a PNM file. 30890 CImg<T>& load_pnm(const char *const filename) { 30891 return _load_pnm(0,filename); 30892 } 30893 30894 static CImg<T> get_load_pnm(const char *const filename) { 30895 return CImg<T>().load_pnm(filename); 30896 } 30897 30898 //! Load an image from a PNM file. 30899 CImg<T>& load_pnm(std::FILE *const file) { 30900 return _load_pnm(file,0); 30901 } 30902 30903 static CImg<T> get_load_pnm(std::FILE *const file) { 30904 return CImg<T>().load_pnm(file); 30905 } 30906 30907 CImg<T>& _load_pnm(std::FILE *const file, const char *const filename) { 30908 if (!file && !filename) 30909 throw CImgArgumentException(_cimg_instance 30910 "load_pnm() : Specified filename is (null).", 30911 cimg_instance); 30912 30913 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 30914 unsigned int ppm_type, W, H, colormax = 255; 30915 char item[1024] = { 0 }; 30916 int err, rval, gval, bval; 30917 const int cimg_iobuffer = 12*1024*1024; 30918 while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 30919 if (std::sscanf(item," P%u",&ppm_type)!=1) { 30920 if (!file) cimg::fclose(nfile); 30921 throw CImgIOException(_cimg_instance 30922 "load_pnm() : PNM header not found in file '%s'.", 30923 cimg_instance, 30924 filename?filename:"(FILE*)"); 30925 } 30926 while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 30927 if ((err=std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) { 30928 if (!file) cimg::fclose(nfile); 30929 throw CImgIOException(_cimg_instance 30930 "load_pnm() : WIDTH and HEIGHT fields undefined in file '%s'.", 30931 cimg_instance, 30932 filename?filename:"(FILE*)"); 30933 } 30934 if (err==2) { 30935 while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 30936 if (std::sscanf(item,"%u",&colormax)!=1) 30937 cimg::warn(_cimg_instance 30938 "load_pnm() : COLORMAX field is undefined in file '%s'.", 30939 cimg_instance, 30940 filename?filename:"(FILE*)"); 30941 } 30942 std::fgetc(nfile); 30943 30944 switch (ppm_type) { 30945 case 2 : { // Grey Ascii 30946 assign(W,H,1,1); 30947 T* ptr_r = _data; 30948 cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptr_r++) = (T)rval; else break; } 30949 } break; 30950 case 3 : { // Color Ascii 30951 assign(W,H,1,3); 30952 T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); 30953 cimg_forXY(*this,x,y) { 30954 if (std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(ptr_r++) = (T)rval; *(ptr_g++) = (T)gval; *(ptr_b++) = (T)bval; } 30955 else break; 30956 } 30957 } break; 30958 case 5 : { // Grey Binary 30959 if (colormax<256) { // 8 bits 30960 CImg<ucharT> raw; 30961 assign(W,H,1,1); 30962 T *ptrd = data(0,0,0,0); 30963 for (int toread = (int)size(); toread>0; ) { 30964 raw.assign(cimg::min(toread,cimg_iobuffer)); 30965 cimg::fread(raw._data,raw._width,nfile); 30966 toread-=raw._width; 30967 const unsigned char *ptrs = raw._data; 30968 for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); 30969 } 30970 } else { // 16 bits 30971 CImg<ushortT> raw; 30972 assign(W,H,1,1); 30973 T *ptrd = data(0,0,0,0); 30974 for (int toread = (int)size(); toread>0; ) { 30975 raw.assign(cimg::min(toread,cimg_iobuffer/2)); 30976 cimg::fread(raw._data,raw._width,nfile); 30977 if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); 30978 toread-=raw._width; 30979 const unsigned short *ptrs = raw._data; 30980 for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); 30981 } 30982 } 30983 } break; 30984 case 6 : { // Color Binary 30985 if (colormax<256) { // 8 bits 30986 CImg<ucharT> raw; 30987 assign(W,H,1,3); 30988 T 30989 *ptr_r = data(0,0,0,0), 30990 *ptr_g = data(0,0,0,1), 30991 *ptr_b = data(0,0,0,2); 30992 for (int toread = (int)size(); toread>0; ) { 30993 raw.assign(cimg::min(toread,cimg_iobuffer)); 30994 cimg::fread(raw._data,raw._width,nfile); 30995 toread-=raw._width; 30996 const unsigned char *ptrs = raw._data; 30997 for (unsigned int off = raw._width/3; off; --off) { 30998 *(ptr_r++) = (T)*(ptrs++); 30999 *(ptr_g++) = (T)*(ptrs++); 31000 *(ptr_b++) = (T)*(ptrs++); 31001 } 31002 } 31003 } else { // 16 bits 31004 CImg<ushortT> raw; 31005 assign(W,H,1,3); 31006 T 31007 *ptr_r = data(0,0,0,0), 31008 *ptr_g = data(0,0,0,1), 31009 *ptr_b = data(0,0,0,2); 31010 for (int toread = (int)size(); toread>0; ) { 31011 raw.assign(cimg::min(toread,cimg_iobuffer/2)); 31012 cimg::fread(raw._data,raw._width,nfile); 31013 if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); 31014 toread-=raw._width; 31015 const unsigned short *ptrs = raw._data; 31016 for (unsigned int off = raw._width/3; off; --off) { 31017 *(ptr_r++) = (T)*(ptrs++); 31018 *(ptr_g++) = (T)*(ptrs++); 31019 *(ptr_b++) = (T)*(ptrs++); 31020 } 31021 } 31022 } 31023 } break; 31024 default : 31025 assign(); 31026 if (!file) cimg::fclose(nfile); 31027 throw CImgIOException(_cimg_instance 31028 "load_pnm() : PNM type 'P%d' found, but type is not supported.", 31029 cimg_instance, 31030 filename?filename:"(FILE*)",ppm_type); 31031 } 31032 if (!file) cimg::fclose(nfile); 31033 return *this; 31034 } 31035 31036 //! Load an image from a PFM file. 31037 CImg<T>& load_pfm(const char *const filename) { 31038 return _load_pfm(0,filename); 31039 } 31040 31041 static CImg<T> get_load_pfm(const char *const filename) { 31042 return CImg<T>().load_pfm(filename); 31043 } 31044 31045 //! Load an image from a PFM file. 31046 CImg<T>& load_pfm(std::FILE *const file) { 31047 return _load_pfm(file,0); 31048 } 31049 31050 static CImg<T> get_load_pfm(std::FILE *const file) { 31051 return CImg<T>().load_pfm(file); 31052 } 31053 31054 CImg<T>& _load_pfm(std::FILE *const file, const char *const filename) { 31055 if (!file && !filename) 31056 throw CImgArgumentException(_cimg_instance 31057 "load_pfm() : Specified filename is (null).", 31058 cimg_instance); 31059 31060 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 31061 char pfm_type, item[1024] = { 0 }; 31062 int W = 0, H = 0, err = 0; 31063 double scale = 0; 31064 while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 31065 if (std::sscanf(item," P%c",&pfm_type)!=1) { 31066 if (!file) cimg::fclose(nfile); 31067 throw CImgIOException(_cimg_instance 31068 "load_pfm() : PFM header not found in file '%s'.", 31069 cimg_instance, 31070 filename?filename:"(FILE*)"); 31071 } 31072 while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 31073 if ((err=std::sscanf(item," %d %d",&W,&H))<2) { 31074 if (!file) cimg::fclose(nfile); 31075 throw CImgIOException(_cimg_instance 31076 "load_pfm() : WIDTH and HEIGHT fields are undefined in file '%s'.", 31077 cimg_instance, 31078 filename?filename:"(FILE*)"); 31079 } 31080 if (err==2) { 31081 while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); 31082 if (std::sscanf(item,"%lf",&scale)!=1) 31083 cimg::warn(_cimg_instance 31084 "load_pfm() : SCALE field is undefined in file '%s'.", 31085 cimg_instance, 31086 filename?filename:"(FILE*)"); 31087 } 31088 std::fgetc(nfile); 31089 const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness(); 31090 if (is_color) { 31091 assign(W,H,1,3,0); 31092 CImg<floatT> buf(3*W); 31093 T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); 31094 cimg_forY(*this,y) { 31095 cimg::fread(buf._data,3*W,nfile); 31096 if (is_inverted) cimg::invert_endianness(buf._data,3*W); 31097 const float *ptrs = buf._data; 31098 cimg_forX(*this,x) { 31099 *(ptr_r++) = (T)*(ptrs++); 31100 *(ptr_g++) = (T)*(ptrs++); 31101 *(ptr_b++) = (T)*(ptrs++); 31102 } 31103 } 31104 } else { 31105 assign(W,H,1,1,0); 31106 CImg<floatT> buf(W); 31107 T *ptrd = data(0,0,0,0); 31108 cimg_forY(*this,y) { 31109 cimg::fread(buf._data,W,nfile); 31110 if (is_inverted) cimg::invert_endianness(buf._data,W); 31111 const float *ptrs = buf._data; 31112 cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++); 31113 } 31114 } 31115 if (!file) cimg::fclose(nfile); 31116 return *this; 31117 } 31118 31119 //! Load an image from a RGB file. 31120 CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { 31121 return _load_rgb(0,filename,dimw,dimh); 31122 } 31123 31124 static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { 31125 return CImg<T>().load_rgb(filename,dimw,dimh); 31126 } 31127 31128 //! Load an image from a RGB file. 31129 CImg<T>& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { 31130 return _load_rgb(file,0,dimw,dimh); 31131 } 31132 31133 static CImg<T> get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { 31134 return CImg<T>().load_rgb(file,dimw,dimh); 31135 } 31136 31137 CImg<T>& _load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { 31138 if (!file && !filename) 31139 throw CImgArgumentException(_cimg_instance 31140 "load_rgb() : Specified filename is (null).", 31141 cimg_instance); 31142 31143 if (!dimw || !dimh) return assign(); 31144 const int cimg_iobuffer = 12*1024*1024; 31145 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 31146 CImg<ucharT> raw; 31147 assign(dimw,dimh,1,3); 31148 T 31149 *ptr_r = data(0,0,0,0), 31150 *ptr_g = data(0,0,0,1), 31151 *ptr_b = data(0,0,0,2); 31152 for (int toread = (int)size(); toread>0; ) { 31153 raw.assign(cimg::min(toread,cimg_iobuffer)); 31154 cimg::fread(raw._data,raw._width,nfile); 31155 toread-=raw._width; 31156 const unsigned char *ptrs = raw._data; 31157 for (unsigned int off = raw._width/3; off; --off) { 31158 *(ptr_r++) = (T)*(ptrs++); 31159 *(ptr_g++) = (T)*(ptrs++); 31160 *(ptr_b++) = (T)*(ptrs++); 31161 } 31162 } 31163 if (!file) cimg::fclose(nfile); 31164 return *this; 31165 } 31166 31167 //! Load an image from a RGBA file. 31168 CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { 31169 return _load_rgba(0,filename,dimw,dimh); 31170 } 31171 31172 static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { 31173 return CImg<T>().load_rgba(filename,dimw,dimh); 31174 } 31175 31176 //! Load an image from a RGBA file. 31177 CImg<T>& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { 31178 return _load_rgba(file,0,dimw,dimh); 31179 } 31180 31181 static CImg<T> get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { 31182 return CImg<T>().load_rgba(file,dimw,dimh); 31183 } 31184 31185 CImg<T>& _load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { 31186 if (!file && !filename) 31187 throw CImgArgumentException(_cimg_instance 31188 "load_rgba() : Specified filename is (null).", 31189 cimg_instance); 31190 31191 if (!dimw || !dimh) return assign(); 31192 const int cimg_iobuffer = 12*1024*1024; 31193 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 31194 CImg<ucharT> raw; 31195 assign(dimw,dimh,1,4); 31196 T 31197 *ptr_r = data(0,0,0,0), 31198 *ptr_g = data(0,0,0,1), 31199 *ptr_b = data(0,0,0,2), 31200 *ptr_a = data(0,0,0,3); 31201 for (int toread = (int)size(); toread>0; ) { 31202 raw.assign(cimg::min(toread,cimg_iobuffer)); 31203 cimg::fread(raw._data,raw._width,nfile); 31204 toread-=raw._width; 31205 const unsigned char *ptrs = raw._data; 31206 for (unsigned int off = raw._width/4; off; --off) { 31207 *(ptr_r++) = (T)*(ptrs++); 31208 *(ptr_g++) = (T)*(ptrs++); 31209 *(ptr_b++) = (T)*(ptrs++); 31210 *(ptr_a++) = (T)*(ptrs++); 31211 } 31212 } 31213 if (!file) cimg::fclose(nfile); 31214 return *this; 31215 } 31216 31217 //! Load an image from a TIFF file. 31218 CImg<T>& load_tiff(const char *const filename, 31219 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 31220 const unsigned int step_frame=1) { 31221 if (!filename) 31222 throw CImgArgumentException(_cimg_instance 31223 "load_tiff() : Specified filename is (null).", 31224 cimg_instance); 31225 31226 const unsigned int 31227 nfirst_frame = first_frame<last_frame?first_frame:last_frame, 31228 nstep_frame = step_frame?step_frame:1; 31229 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame; 31230 31231 #ifndef cimg_use_tiff 31232 if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1) 31233 throw CImgArgumentException(_cimg_instance 31234 "load_tiff() : Unable to read sub-images from file '%s' unless libtiff is enabled.", 31235 cimg_instance, 31236 filename); 31237 return load_other(filename); 31238 #else 31239 TIFF *tif = TIFFOpen(filename,"r"); 31240 if (tif) { 31241 unsigned int nb_images = 0; 31242 do ++nb_images; while (TIFFReadDirectory(tif)); 31243 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) 31244 cimg::warn(_cimg_instance 31245 "load_tiff() : File '%s' contains %u image(s) while specified frame range is [%u,%u] (step %u).", 31246 cimg_instance, 31247 filename,nb_images,nfirst_frame,nlast_frame,nstep_frame); 31248 31249 if (nfirst_frame>=nb_images) return assign(); 31250 if (nlast_frame>=nb_images) nlast_frame = nb_images-1; 31251 TIFFSetDirectory(tif,0); 31252 CImg<T> frame; 31253 for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) { 31254 frame._load_tiff(tif,l); 31255 if (l==nfirst_frame) assign(frame._width,frame._height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame._spectrum); 31256 if (frame._width>_width || frame._height>_height || frame._spectrum>_spectrum) 31257 resize(cimg::max(frame._width,_width),cimg::max(frame._height,_height),-100,cimg::max(frame._spectrum,_spectrum),0); 31258 draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame); 31259 } 31260 TIFFClose(tif); 31261 } else throw CImgException(_cimg_instance 31262 "load_tiff() : Failed to open file '%s'.", 31263 cimg_instance, 31264 filename); 31265 return *this; 31266 #endif 31267 } 31268 31269 static CImg<T> get_load_tiff(const char *const filename, 31270 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 31271 const unsigned int step_frame=1) { 31272 return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame); 31273 } 31274 31275 // (Original contribution by Jerome Boulanger). 31276 #ifdef cimg_use_tiff 31277 template<typename t> 31278 void _load_tiff_tiled_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) { 31279 t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); 31280 if (buf) { 31281 for (unsigned int row = 0; row<ny; row+=th) 31282 for (unsigned int col = 0; col<nx; col+=tw) { 31283 if (TIFFReadTile(tif,buf,col,row,0,0)<0) { 31284 _TIFFfree(buf); TIFFClose(tif); 31285 throw CImgException(_cimg_instance 31286 "load_tiff() : Invalid tile in file '%s'.", 31287 cimg_instance, 31288 TIFFFileName(tif)); 31289 } 31290 const t *ptr = buf; 31291 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr) 31292 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc) 31293 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) 31294 (*this)(cc,rr,vv) = (T)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]); 31295 } 31296 _TIFFfree(buf); 31297 } 31298 } 31299 31300 template<typename t> 31301 void _load_tiff_tiled_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) { 31302 t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); 31303 if (buf) { 31304 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) 31305 for (unsigned int row = 0; row<ny; row+=th) 31306 for (unsigned int col = 0; col<nx; col+=tw) { 31307 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) { 31308 _TIFFfree(buf); TIFFClose(tif); 31309 throw CImgException(_cimg_instance 31310 "load_tiff() : Invalid tile in file '%s'.", 31311 cimg_instance, 31312 TIFFFileName(tif)); 31313 } 31314 const t *ptr = buf; 31315 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr) 31316 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc) 31317 (*this)(cc,rr,vv) = (T)*(ptr++); 31318 } 31319 _TIFFfree(buf); 31320 } 31321 } 31322 31323 template<typename t> 31324 void _load_tiff_contig(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) { 31325 t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); 31326 if (buf) { 31327 uint32 row, rowsperstrip = (uint32)-1; 31328 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); 31329 for (row = 0; row<ny; row+= rowsperstrip) { 31330 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip); 31331 tstrip_t strip = TIFFComputeStrip(tif, row, 0); 31332 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { 31333 _TIFFfree(buf); TIFFClose(tif); 31334 throw CImgException(_cimg_instance 31335 "load_tiff() : Invalid strip in file '%s'.", 31336 cimg_instance, 31337 TIFFFileName(tif)); 31338 } 31339 const t *ptr = buf; 31340 for (unsigned int rr = 0; rr<nrow; ++rr) 31341 for (unsigned int cc = 0; cc<nx; ++cc) 31342 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)*(ptr++); 31343 } 31344 _TIFFfree(buf); 31345 } 31346 } 31347 31348 template<typename t> 31349 void _load_tiff_separate(TIFF *const tif, const uint16 samplesperpixel, const uint32 nx, const uint32 ny) { 31350 t *buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); 31351 if (buf) { 31352 uint32 row, rowsperstrip = (uint32)-1; 31353 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); 31354 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) 31355 for (row = 0; row<ny; row+= rowsperstrip) { 31356 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip); 31357 tstrip_t strip = TIFFComputeStrip(tif, row, vv); 31358 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { 31359 _TIFFfree(buf); TIFFClose(tif); 31360 throw CImgException(_cimg_instance 31361 "load_tiff() : Invalid strip in file '%s'.", 31362 cimg_instance, 31363 TIFFFileName(tif)); 31364 } 31365 const t *ptr = buf; 31366 for (unsigned int rr = 0;rr<nrow; ++rr) 31367 for (unsigned int cc = 0; cc<nx; ++cc) 31368 (*this)(cc,row+rr,vv) = (T)*(ptr++); 31369 } 31370 _TIFFfree(buf); 31371 } 31372 } 31373 31374 CImg<T>& _load_tiff(TIFF *const tif, const unsigned int directory) { 31375 if (!TIFFSetDirectory(tif,directory)) return assign(); 31376 uint16 samplesperpixel, bitspersample; 31377 uint16 sampleformat = SAMPLEFORMAT_UINT; 31378 uint32 nx,ny; 31379 const char *const filename = TIFFFileName(tif); 31380 TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx); 31381 TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny); 31382 TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel); 31383 TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat); 31384 if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) { 31385 cimg::warn(_cimg_instance 31386 "load_tiff() : Unknow value for tag TIFFTAG_SAMPLESPERPIXEL (so assumed to be 1), in file '%s'.", 31387 cimg_instance, 31388 filename); 31389 31390 samplesperpixel = 1; 31391 } 31392 TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample); 31393 assign(nx,ny,1,samplesperpixel); 31394 if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) { 31395 uint16 photo, config; 31396 TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config); 31397 TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo); 31398 if (TIFFIsTiled(tif)) { 31399 uint32 tw, th; 31400 TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw); 31401 TIFFGetField(tif,TIFFTAG_TILELENGTH,&th); 31402 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { 31403 case 8 : { 31404 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig<unsigned char>(tif,samplesperpixel,nx,ny,tw,th); 31405 else _load_tiff_tiled_contig<signed char>(tif,samplesperpixel,nx,ny,tw,th); 31406 } break; 31407 case 16 : 31408 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig<unsigned short>(tif,samplesperpixel,nx,ny,tw,th); 31409 else _load_tiff_tiled_contig<short>(tif,samplesperpixel,nx,ny,tw,th); 31410 break; 31411 case 32 : 31412 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_contig<unsigned int>(tif,samplesperpixel,nx,ny,tw,th); 31413 else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_tiled_contig<int>(tif,samplesperpixel,nx,ny,tw,th); 31414 else _load_tiff_tiled_contig<float>(tif,samplesperpixel,nx,ny,tw,th); 31415 break; 31416 } else switch (bitspersample) { 31417 case 8 : 31418 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate<unsigned char>(tif,samplesperpixel,nx,ny,tw,th); 31419 else _load_tiff_tiled_separate<signed char>(tif,samplesperpixel,nx,ny,tw,th); 31420 break; 31421 case 16 : 31422 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate<unsigned short>(tif,samplesperpixel,nx,ny,tw,th); 31423 else _load_tiff_tiled_separate<short>(tif,samplesperpixel,nx,ny,tw,th); 31424 break; 31425 case 32 : 31426 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_tiled_separate<unsigned int>(tif,samplesperpixel,nx,ny,tw,th); 31427 else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_tiled_separate<int>(tif,samplesperpixel,nx,ny,tw,th); 31428 else _load_tiff_tiled_separate<float>(tif,samplesperpixel,nx,ny,tw,th); 31429 break; 31430 } 31431 } else { 31432 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { 31433 case 8 : 31434 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned char>(tif,samplesperpixel,nx,ny); 31435 else _load_tiff_contig<signed char>(tif,samplesperpixel,nx,ny); 31436 break; 31437 case 16 : 31438 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned short>(tif,samplesperpixel,nx,ny); 31439 else _load_tiff_contig<short>(tif,samplesperpixel,nx,ny); 31440 break; 31441 case 32 : 31442 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig<unsigned int>(tif,samplesperpixel,nx,ny); 31443 else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig<int>(tif,samplesperpixel,nx,ny); 31444 else _load_tiff_contig<float>(tif,samplesperpixel,nx,ny); 31445 break; 31446 } else switch (bitspersample){ 31447 case 8 : 31448 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned char>(tif,samplesperpixel,nx,ny); 31449 else _load_tiff_separate<signed char>(tif,samplesperpixel,nx,ny); 31450 break; 31451 case 16 : 31452 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned short>(tif,samplesperpixel,nx,ny); 31453 else _load_tiff_separate<short>(tif,samplesperpixel,nx,ny); 31454 break; 31455 case 32 : 31456 if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate<unsigned int>(tif,samplesperpixel,nx,ny); 31457 else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate<int>(tif,samplesperpixel,nx,ny); 31458 else _load_tiff_separate<float>(tif,samplesperpixel,nx,ny); 31459 break; 31460 } 31461 } 31462 } else { 31463 uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32)); 31464 if (!raster) { 31465 _TIFFfree(raster); TIFFClose(tif); 31466 throw CImgException(_cimg_instance 31467 "load_tiff() : Failed to allocated memory for file '%s'.", 31468 cimg_instance, 31469 filename); 31470 } 31471 TIFFReadRGBAImage(tif,nx,ny,raster,0); 31472 switch (samplesperpixel) { 31473 case 1 : { 31474 cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x] + 128)/257); 31475 } break; 31476 case 3 : { 31477 cimg_forXY(*this,x,y) { 31478 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); 31479 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); 31480 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); 31481 } 31482 } break; 31483 case 4 : { 31484 cimg_forXY(*this,x,y) { 31485 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); 31486 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); 31487 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); 31488 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]); 31489 } 31490 } break; 31491 } 31492 _TIFFfree(raster); 31493 } 31494 return *this; 31495 } 31496 #endif 31497 31498 //! Load an image from an ANALYZE7.5/NIFTI file. 31499 CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) { 31500 return _load_analyze(0,filename,voxsize); 31501 } 31502 31503 static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) { 31504 return CImg<T>().load_analyze(filename,voxsize); 31505 } 31506 31507 //! Load an image from an ANALYZE7.5/NIFTI file. 31508 CImg<T>& load_analyze(std::FILE *const file, float *const voxsize=0) { 31509 return _load_analyze(file,0,voxsize); 31510 } 31511 31512 static CImg<T> get_load_analyze(std::FILE *const file, float *const voxsize=0) { 31513 return CImg<T>().load_analyze(file,voxsize); 31514 } 31515 31516 CImg<T>& _load_analyze(std::FILE *const file, const char *const filename, float *const voxsize=0) { 31517 if (!file && !filename) 31518 throw CImgArgumentException(_cimg_instance 31519 "load_analyze() : Specified filename is (null).", 31520 cimg_instance); 31521 31522 std::FILE *nfile_header = 0, *nfile = 0; 31523 if (!file) { 31524 char body[1024] = { 0 }; 31525 const char *const ext = cimg::split_filename(filename,body); 31526 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file. 31527 nfile_header = cimg::fopen(filename,"rb"); 31528 std::sprintf(body+std::strlen(body),".img"); 31529 nfile = cimg::fopen(body,"rb"); 31530 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file. 31531 nfile = cimg::fopen(filename,"rb"); 31532 std::sprintf(body+std::strlen(body),".hdr"); 31533 nfile_header = cimg::fopen(body,"rb"); 31534 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file. 31535 } else nfile_header = nfile = file; // File is a Niftii file. 31536 if (!nfile || !nfile_header) 31537 throw CImgIOException(_cimg_instance 31538 "load_analyze() : Invalid Analyze7.5 or NIFTI header in file '%s'.", 31539 cimg_instance, 31540 filename?filename:"(FILE*)"); 31541 31542 // Read header. 31543 bool endian = false; 31544 unsigned int header_size; 31545 cimg::fread(&header_size,1,nfile_header); 31546 if (!header_size) 31547 throw CImgIOException(_cimg_instance 31548 "load_analyze() : Invalid zero-sized header in file '%s'.", 31549 cimg_instance, 31550 filename?filename:"(FILE*)"); 31551 31552 if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); } 31553 unsigned char *const header = new unsigned char[header_size]; 31554 cimg::fread(header+4,header_size-4,nfile_header); 31555 if (!file && nfile_header!=nfile) cimg::fclose(nfile_header); 31556 if (endian) { 31557 cimg::invert_endianness((short*)(header+40),5); 31558 cimg::invert_endianness((short*)(header+70),1); 31559 cimg::invert_endianness((short*)(header+72),1); 31560 cimg::invert_endianness((float*)(header+76),4); 31561 cimg::invert_endianness((float*)(header+112),1); 31562 } 31563 unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1; 31564 if (!dim[0]) 31565 cimg::warn(_cimg_instance 31566 "load_analyze() : File '%s' defines an image with zero dimensions.", 31567 cimg_instance, 31568 filename?filename:"(FILE*)"); 31569 31570 if (dim[0]>4) 31571 cimg::warn(_cimg_instance 31572 "load_analyze() : File '%s' defines an image with %u dimensions, reading only the 4 first.", 31573 cimg_instance, 31574 filename?filename:"(FILE*)",dim[0]); 31575 31576 if (dim[0]>=1) dimx = dim[1]; 31577 if (dim[0]>=2) dimy = dim[2]; 31578 if (dim[0]>=3) dimz = dim[3]; 31579 if (dim[0]>=4) dimv = dim[4]; 31580 float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1; 31581 const unsigned short datatype = *(short*)(header+70); 31582 if (voxsize) { 31583 const float *vsize = (float*)(header+76); 31584 voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; 31585 } 31586 delete[] header; 31587 31588 // Read pixel data. 31589 assign(dimx,dimy,dimz,dimv); 31590 switch (datatype) { 31591 case 2 : { 31592 unsigned char *const buffer = new unsigned char[dimx*dimy*dimz*dimv]; 31593 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); 31594 cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); 31595 delete[] buffer; 31596 } break; 31597 case 4 : { 31598 short *const buffer = new short[dimx*dimy*dimz*dimv]; 31599 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); 31600 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); 31601 cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); 31602 delete[] buffer; 31603 } break; 31604 case 8 : { 31605 int *const buffer = new int[dimx*dimy*dimz*dimv]; 31606 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); 31607 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); 31608 cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); 31609 delete[] buffer; 31610 } break; 31611 case 16 : { 31612 float *const buffer = new float[dimx*dimy*dimz*dimv]; 31613 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); 31614 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); 31615 cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); 31616 delete[] buffer; 31617 } break; 31618 case 64 : { 31619 double *const buffer = new double[dimx*dimy*dimz*dimv]; 31620 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); 31621 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv); 31622 cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); 31623 delete[] buffer; 31624 } break; 31625 default : 31626 if (!file) cimg::fclose(nfile); 31627 throw CImgIOException(_cimg_instance 31628 "load_analyze() : Unable to load datatype %d in file '%s'", 31629 cimg_instance, 31630 datatype,filename?filename:"(FILE*)"); 31631 } 31632 if (!file) cimg::fclose(nfile); 31633 return *this; 31634 } 31635 31636 //! Load an image (list) from a .cimg file. 31637 CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') { 31638 CImgList<T> list; 31639 list.load_cimg(filename); 31640 if (list._width==1) return list[0].move_to(*this); 31641 return assign(list.get_append(axis,align)); 31642 } 31643 31644 static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') { 31645 return CImg<T>().load_cimg(filename,axis,align); 31646 } 31647 31648 //! Load an image (list) from a .cimg file. 31649 CImg<T>& load_cimg(std::FILE *const file, const char axis='z', const char align='p') { 31650 CImgList<T> list; 31651 list.load_cimg(file); 31652 if (list._width==1) return list[0].move_to(*this); 31653 return assign(list.get_append(axis,align)); 31654 } 31655 31656 static CImg<T> get_load_cimg(std::FILE *const file, const char axis='z', const char align='p') { 31657 return CImg<T>().load_cimg(file,axis,align); 31658 } 31659 31660 //! Load a sub-image (list) from a .cimg file. 31661 CImg<T>& load_cimg(const char *const filename, 31662 const unsigned int n0, const unsigned int n1, 31663 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 31664 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, 31665 const char axis='z', const char align='p') { 31666 CImgList<T> list; 31667 list.load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 31668 if (list._width==1) return list[0].move_to(*this); 31669 return assign(list.get_append(axis,align)); 31670 } 31671 31672 static CImg<T> get_load_cimg(const char *const filename, 31673 const unsigned int n0, const unsigned int n1, 31674 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 31675 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, 31676 const char axis='z', const char align='p') { 31677 return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); 31678 } 31679 31680 //! Load a sub-image (list) from a non-compressed .cimg file. 31681 CImg<T>& load_cimg(std::FILE *const file, 31682 const unsigned int n0, const unsigned int n1, 31683 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 31684 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, 31685 const char axis='z', const char align='p') { 31686 CImgList<T> list; 31687 list.load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 31688 if (list._width==1) return list[0].move_to(*this); 31689 return assign(list.get_append(axis,align)); 31690 } 31691 31692 static CImg<T> get_load_cimg(std::FILE *const file, 31693 const unsigned int n0, const unsigned int n1, 31694 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 31695 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1, 31696 const char axis='z', const char align='p') { 31697 return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); 31698 } 31699 31700 //! Load an image from an INRIMAGE-4 file. 31701 CImg<T>& load_inr(const char *const filename, float *const voxsize=0) { 31702 return _load_inr(0,filename,voxsize); 31703 } 31704 31705 static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) { 31706 return CImg<T>().load_inr(filename,voxsize); 31707 } 31708 31709 //! Load an image from an INRIMAGE-4 file. 31710 CImg<T>& load_inr(std::FILE *const file, float *const voxsize=0) { 31711 return _load_inr(file,0,voxsize); 31712 } 31713 31714 static CImg<T> get_load_inr(std::FILE *const file, float *voxsize=0) { 31715 return CImg<T>().load_inr(file,voxsize); 31716 } 31717 31718 // Load an image from an INRIMAGE-4 file (internal). 31719 static void _load_inr_header(std::FILE *file, int out[8], float *const voxsize) { 31720 char item[1024] = { 0 }, tmp1[64] = { 0 }, tmp2[64] = { 0 }; 31721 out[0] = std::fscanf(file,"%63s",item); 31722 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; 31723 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) 31724 throw CImgIOException("CImg<%s>::load_inr() : INRIMAGE-4 header not found.", 31725 pixel_type()); 31726 31727 while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && std::strncmp(item,"##}",3)) { 31728 std::sscanf(item," XDIM%*[^0-9]%d",out); 31729 std::sscanf(item," YDIM%*[^0-9]%d",out+1); 31730 std::sscanf(item," ZDIM%*[^0-9]%d",out+2); 31731 std::sscanf(item," VDIM%*[^0-9]%d",out+3); 31732 std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6); 31733 if (voxsize) { 31734 std::sscanf(item," VX%*[^0-9.+-]%f",voxsize); 31735 std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1); 31736 std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2); 31737 } 31738 if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; 31739 switch (std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { 31740 case 0 : break; 31741 case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2); 31742 case 1 : 31743 if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; 31744 if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; 31745 if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; 31746 if (out[4]>=0) break; 31747 default : 31748 throw CImgIOException("CImg<%s>::load_inr() : Invalid pixel type '%s' defined in header.", 31749 pixel_type(), 31750 tmp2); 31751 } 31752 } 31753 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) 31754 throw CImgIOException("CImg<%s>::load_inr() : Invalid dimensions (%d,%d,%d,%d) defined in header.", 31755 pixel_type(), 31756 out[0],out[1],out[2],out[3]); 31757 if(out[4]<0 || out[5]<0) 31758 throw CImgIOException("CImg<%s>::load_inr() : Incomplete pixel type defined in header.", 31759 pixel_type()); 31760 if(out[6]<0) 31761 throw CImgIOException("CImg<%s>::load_inr() : Incomplete PIXSIZE field defined in header.", 31762 pixel_type()); 31763 if(out[7]<0) 31764 throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type undefined in header.", 31765 pixel_type()); 31766 } 31767 31768 CImg<T>& _load_inr(std::FILE *const file, const char *const filename, float *const voxsize) { 31769 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \ 31770 if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ 31771 Ts *xval, *const val = new Ts[fopt[0]*fopt[3]]; \ 31772 cimg_forYZ(*this,y,z) { \ 31773 cimg::fread(val,fopt[0]*fopt[3],nfile); \ 31774 if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \ 31775 xval = val; cimg_forX(*this,x) cimg_forC(*this,c) (*this)(x,y,z,c) = (T)*(xval++); \ 31776 } \ 31777 delete[] val; \ 31778 loaded = true; \ 31779 } 31780 31781 if (!file && !filename) 31782 throw CImgArgumentException(_cimg_instance 31783 "load_inr() : Specified filename is (null).", 31784 cimg_instance); 31785 31786 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 31787 int fopt[8], endian=cimg::endianness()?1:0; 31788 bool loaded = false; 31789 if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1; 31790 _load_inr_header(nfile,fopt,voxsize); 31791 assign(fopt[0],fopt[1],fopt[2],fopt[3]); 31792 _cimg_load_inr_case(0,0,8,unsigned char); 31793 _cimg_load_inr_case(0,1,8,char); 31794 _cimg_load_inr_case(0,0,16,unsigned short); 31795 _cimg_load_inr_case(0,1,16,short); 31796 _cimg_load_inr_case(0,0,32,unsigned int); 31797 _cimg_load_inr_case(0,1,32,int); 31798 _cimg_load_inr_case(1,0,32,float); 31799 _cimg_load_inr_case(1,1,32,float); 31800 _cimg_load_inr_case(1,0,64,double); 31801 _cimg_load_inr_case(1,1,64,double); 31802 if (!loaded) { 31803 if (!file) cimg::fclose(nfile); 31804 throw CImgIOException(_cimg_instance 31805 "load_inr() : Unknown pixel type defined in file '%s'.", 31806 cimg_instance, 31807 filename?filename:"(FILE*)"); 31808 } 31809 if (!file) cimg::fclose(nfile); 31810 return *this; 31811 } 31812 31813 //! Load an image from a EXR file. 31814 CImg<T>& load_exr(const char *const filename) { 31815 if (!filename) 31816 throw CImgArgumentException(_cimg_instance 31817 "load_exr() : Specified filename is (null).", 31818 cimg_instance); 31819 31820 #ifndef cimg_use_openexr 31821 return load_other(filename); 31822 #else 31823 Imf::RgbaInputFile file(filename); 31824 Imath::Box2i dw = file.dataWindow(); 31825 const int 31826 inwidth = dw.max.x - dw.min.x + 1, 31827 inheight = dw.max.y - dw.min.y + 1; 31828 Imf::Array2D<Imf::Rgba> pixels; 31829 pixels.resizeErase(inheight,inwidth); 31830 file.setFrameBuffer(&pixels[0][0] - dw.min.x - dw.min.y*inwidth, 1, inwidth); 31831 file.readPixels(dw.min.y, dw.max.y); 31832 assign(inwidth,inheight,1,4); 31833 T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); 31834 cimg_forXY(*this,x,y) { 31835 *(ptr_r++) = (T)pixels[y][x].r; 31836 *(ptr_g++) = (T)pixels[y][x].g; 31837 *(ptr_b++) = (T)pixels[y][x].b; 31838 *(ptr_a++) = (T)pixels[y][x].a; 31839 } 31840 return *this; 31841 #endif 31842 } 31843 31844 static CImg<T> get_load_exr(const char *const filename) { 31845 return CImg<T>().load_exr(filename); 31846 } 31847 31848 //! Load an image from a PANDORE file. 31849 CImg<T>& load_pandore(const char *const filename) { 31850 return _load_pandore(0,filename); 31851 } 31852 31853 static CImg<T> get_load_pandore(const char *const filename) { 31854 return CImg<T>().load_pandore(filename); 31855 } 31856 31857 //! Load an image from a PANDORE file. 31858 CImg<T>& load_pandore(std::FILE *const file) { 31859 return _load_pandore(file,0); 31860 } 31861 31862 static CImg<T> get_load_pandore(std::FILE *const file) { 31863 return CImg<T>().load_pandore(file); 31864 } 31865 31866 CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) { 31867 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \ 31868 cimg::fread(dims,nbdim,nfile); \ 31869 if (endian) cimg::invert_endianness(dims,nbdim); \ 31870 assign(nwidth,nheight,ndepth,ndim); \ 31871 const unsigned int siz = size(); \ 31872 stype *buffer = new stype[siz]; \ 31873 cimg::fread(buffer,siz,nfile); \ 31874 if (endian) cimg::invert_endianness(buffer,siz); \ 31875 T *ptrd = _data; \ 31876 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \ 31877 buffer-=siz; \ 31878 delete[] buffer 31879 31880 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \ 31881 if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \ 31882 else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \ 31883 else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \ 31884 else throw CImgIOException(_cimg_instance \ 31885 "load_pandore() : Unknown pixel datatype in file '%s'.", \ 31886 cimg_instance, \ 31887 filename?filename:"(FILE*)"); } 31888 31889 if (!file && !filename) 31890 throw CImgArgumentException(_cimg_instance 31891 "load_pandore() : Specified filename is (null).", 31892 cimg_instance); 31893 31894 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 31895 char header[32] = { 0 }; 31896 cimg::fread(header,12,nfile); 31897 if (cimg::strncasecmp("PANDORE",header,7)) { 31898 if (!file) cimg::fclose(nfile); 31899 throw CImgIOException(_cimg_instance 31900 "load_pandore() : PANDORE header not found in file '%s'.", 31901 cimg_instance, 31902 filename?filename:"(FILE*)"); 31903 } 31904 unsigned int imageid, dims[8] = { 0 }; 31905 cimg::fread(&imageid,1,nfile); 31906 const bool endian = (imageid>255); 31907 if (endian) cimg::invert_endianness(imageid); 31908 cimg::fread(header,20,nfile); 31909 31910 switch (imageid) { 31911 case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; 31912 case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break; 31913 case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break; 31914 case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break; 31915 case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break; 31916 case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break; 31917 case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break; 31918 case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break; 31919 case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break; 31920 case 11 : { // Region 1d 31921 cimg::fread(dims,3,nfile); 31922 if (endian) cimg::invert_endianness(dims,3); 31923 assign(dims[1],1,1,1); 31924 const unsigned siz = size(); 31925 if (dims[2]<256) { 31926 unsigned char *buffer = new unsigned char[siz]; 31927 cimg::fread(buffer,siz,nfile); 31928 T *ptrd = _data; 31929 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31930 buffer-=siz; 31931 delete[] buffer; 31932 } else { 31933 if (dims[2]<65536) { 31934 unsigned short *buffer = new unsigned short[siz]; 31935 cimg::fread(buffer,siz,nfile); 31936 if (endian) cimg::invert_endianness(buffer,siz); 31937 T *ptrd = _data; 31938 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31939 buffer-=siz; 31940 delete[] buffer; 31941 } else { 31942 unsigned int *buffer = new unsigned int[siz]; 31943 cimg::fread(buffer,siz,nfile); 31944 if (endian) cimg::invert_endianness(buffer,siz); 31945 T *ptrd = _data; 31946 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31947 buffer-=siz; 31948 delete[] buffer; 31949 } 31950 } 31951 } 31952 break; 31953 case 12 : { // Region 2d 31954 cimg::fread(dims,4,nfile); 31955 if (endian) cimg::invert_endianness(dims,4); 31956 assign(dims[2],dims[1],1,1); 31957 const unsigned int siz = size(); 31958 if (dims[3]<256) { 31959 unsigned char *buffer = new unsigned char[siz]; 31960 cimg::fread(buffer,siz,nfile); 31961 T *ptrd = _data; 31962 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31963 buffer-=siz; 31964 delete[] buffer; 31965 } else { 31966 if (dims[3]<65536) { 31967 unsigned short *buffer = new unsigned short[siz]; 31968 cimg::fread(buffer,siz,nfile); 31969 if (endian) cimg::invert_endianness(buffer,siz); 31970 T *ptrd = _data; 31971 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31972 buffer-=siz; 31973 delete[] buffer; 31974 } else { 31975 unsigned long *buffer = new unsigned long[siz]; 31976 cimg::fread(buffer,siz,nfile); 31977 if (endian) cimg::invert_endianness(buffer,siz); 31978 T *ptrd = _data; 31979 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31980 buffer-=siz; 31981 delete[] buffer; 31982 } 31983 } 31984 } 31985 break; 31986 case 13 : { // Region 3d 31987 cimg::fread(dims,5,nfile); 31988 if (endian) cimg::invert_endianness(dims,5); 31989 assign(dims[3],dims[2],dims[1],1); 31990 const unsigned int siz = size(); 31991 if (dims[4]<256) { 31992 unsigned char *buffer = new unsigned char[siz]; 31993 cimg::fread(buffer,siz,nfile); 31994 T *ptrd = _data; 31995 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 31996 buffer-=siz; 31997 delete[] buffer; 31998 } else { 31999 if (dims[4]<65536) { 32000 unsigned short *buffer = new unsigned short[siz]; 32001 cimg::fread(buffer,siz,nfile); 32002 if (endian) cimg::invert_endianness(buffer,siz); 32003 T *ptrd = _data; 32004 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 32005 buffer-=siz; 32006 delete[] buffer; 32007 } else { 32008 unsigned int *buffer = new unsigned int[siz]; 32009 cimg::fread(buffer,siz,nfile); 32010 if (endian) cimg::invert_endianness(buffer,siz); 32011 T *ptrd = _data; 32012 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); 32013 buffer-=siz; 32014 delete[] buffer; 32015 } 32016 } 32017 } 32018 break; 32019 case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break; 32020 case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break; 32021 case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break; 32022 case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break; 32023 case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break; 32024 case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break; 32025 case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break; 32026 case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); 32027 case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break; 32028 case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break; 32029 case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break; 32030 case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break; 32031 case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break; 32032 case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break; 32033 case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1); break; 32034 case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break; 32035 case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4); break; 32036 case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; 32037 case 34 : { // Points 1d 32038 int ptbuf[4] = { 0 }; 32039 cimg::fread(ptbuf,1,nfile); 32040 if (endian) cimg::invert_endianness(ptbuf,1); 32041 assign(1); (*this)(0) = (T)ptbuf[0]; 32042 } break; 32043 case 35 : { // Points 2d 32044 int ptbuf[4] = { 0 }; 32045 cimg::fread(ptbuf,2,nfile); 32046 if (endian) cimg::invert_endianness(ptbuf,2); 32047 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0]; 32048 } break; 32049 case 36 : { // Points 3d 32050 int ptbuf[4] = { 0 }; 32051 cimg::fread(ptbuf,3,nfile); 32052 if (endian) cimg::invert_endianness(ptbuf,3); 32053 assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0]; 32054 } break; 32055 default : 32056 if (!file) cimg::fclose(nfile); 32057 throw CImgIOException(_cimg_instance 32058 "load_pandore() : Unable to load data with ID_type %u in file '%s'.", 32059 cimg_instance, 32060 imageid,filename?filename:"(FILE*)"); 32061 } 32062 if (!file) cimg::fclose(nfile); 32063 return *this; 32064 } 32065 32066 //! Load an image from a PAR-REC (Philips) file. 32067 CImg<T>& load_parrec(const char *const filename, const char axis='c', const char align='p') { 32068 CImgList<T> list; 32069 list.load_parrec(filename); 32070 if (list._width==1) return list[0].move_to(*this); 32071 return assign(list.get_append(axis,align)); 32072 } 32073 32074 static CImg<T> get_load_parrec(const char *const filename, const char axis='c', const char align='p') { 32075 return CImg<T>().load_parrec(filename,axis,align); 32076 } 32077 32078 //! Load an image from a .RAW file. 32079 CImg<T>& load_raw(const char *const filename, 32080 const unsigned int sizex, const unsigned int sizey=1, 32081 const unsigned int sizez=1, const unsigned int sizev=1, 32082 const bool multiplexed=false, const bool invert_endianness=false) { 32083 return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness); 32084 } 32085 32086 static CImg<T> get_load_raw(const char *const filename, 32087 const unsigned int sizex, const unsigned int sizey=1, 32088 const unsigned int sizez=1, const unsigned int sizev=1, 32089 const bool multiplexed=false, const bool invert_endianness=false) { 32090 return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness); 32091 } 32092 32093 //! Load an image from a .RAW file. 32094 CImg<T>& load_raw(std::FILE *const file, 32095 const unsigned int sizex, const unsigned int sizey=1, 32096 const unsigned int sizez=1, const unsigned int sizev=1, 32097 const bool multiplexed=false, const bool invert_endianness=false) { 32098 return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness); 32099 } 32100 32101 static CImg<T> get_load_raw(std::FILE *const file, 32102 const unsigned int sizex, const unsigned int sizey=1, 32103 const unsigned int sizez=1, const unsigned int sizev=1, 32104 const bool multiplexed=false, const bool invert_endianness=false) { 32105 return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness); 32106 } 32107 32108 CImg<T>& _load_raw(std::FILE *const file, const char *const filename, 32109 const unsigned int sizex, const unsigned int sizey, 32110 const unsigned int sizez, const unsigned int sizev, 32111 const bool multiplexed, const bool invert_endianness) { 32112 if (!file && !filename) 32113 throw CImgArgumentException(_cimg_instance 32114 "load_raw() : Specified filename is (null).", 32115 cimg_instance); 32116 32117 assign(sizex,sizey,sizez,sizev,0); 32118 const unsigned int siz = size(); 32119 if (siz) { 32120 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 32121 if (!multiplexed) { 32122 cimg::fread(_data,siz,nfile); 32123 if (invert_endianness) cimg::invert_endianness(_data,siz); 32124 } 32125 else { 32126 CImg<T> buf(1,1,1,sizev); 32127 cimg_forXYZ(*this,x,y,z) { 32128 cimg::fread(buf._data,sizev,nfile); 32129 if (invert_endianness) cimg::invert_endianness(buf._data,sizev); 32130 set_vector_at(buf,x,y,z); } 32131 } 32132 if (!file) cimg::fclose(nfile); 32133 } 32134 return *this; 32135 } 32136 32137 //! Load a video sequence using FFMPEG av's libraries. 32138 CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32139 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false, 32140 const char axis='z', const char align='p') { 32141 return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).move_to(*this); 32142 } 32143 32144 static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32145 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false, 32146 const char axis='z', const char align='p') { 32147 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align); 32148 } 32149 32150 //! Load an image sequence from a YUV file. 32151 CImg<T>& load_yuv(const char *const filename, 32152 const unsigned int sizex, const unsigned int sizey=1, 32153 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32154 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') { 32155 return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).move_to(*this); 32156 } 32157 32158 static CImg<T> get_load_yuv(const char *const filename, 32159 const unsigned int sizex, const unsigned int sizey=1, 32160 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32161 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') { 32162 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align); 32163 } 32164 32165 //! Load an image sequence from a YUV file. 32166 CImg<T>& load_yuv(std::FILE *const file, 32167 const unsigned int sizex, const unsigned int sizey=1, 32168 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32169 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') { 32170 return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).move_to(*this); 32171 } 32172 32173 static CImg<T> get_load_yuv(std::FILE *const file, 32174 const unsigned int sizex, const unsigned int sizey=1, 32175 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 32176 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') { 32177 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align); 32178 } 32179 32180 //! Load a 3d object from a .OFF file. 32181 template<typename tf, typename tc> 32182 CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) { 32183 return _load_off(0,filename,primitives,colors); 32184 } 32185 32186 template<typename tf, typename tc> 32187 static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) { 32188 return CImg<T>().load_off(filename,primitives,colors); 32189 } 32190 32191 //! Load a 3d object from a .OFF file. 32192 template<typename tf, typename tc> 32193 CImg<T>& load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) { 32194 return _load_off(file,0,primitives,colors); 32195 } 32196 32197 template<typename tf, typename tc> 32198 static CImg<T> get_load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) { 32199 return CImg<T>().load_off(file,primitives,colors); 32200 } 32201 32202 template<typename tf, typename tc> 32203 CImg<T>& _load_off(std::FILE *const file, const char *const filename, 32204 CImgList<tf>& primitives, CImgList<tc>& colors) { 32205 if (!file && !filename) 32206 throw CImgArgumentException(_cimg_instance 32207 "load_off() : Specified filename is (null).", 32208 cimg_instance); 32209 32210 std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); 32211 unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0; 32212 char line[256] = { 0 }; 32213 int err; 32214 32215 // Skip comments, and read magic string OFF 32216 do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); 32217 if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) { 32218 if (!file) cimg::fclose(nfile); 32219 throw CImgIOException(_cimg_instance 32220 "load_off() : OFF header not found in file '%s'.", 32221 cimg_instance, 32222 filename?filename:"(FILE*)"); 32223 } 32224 do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); 32225 if ((err = std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { 32226 if (!file) cimg::fclose(nfile); 32227 throw CImgIOException(_cimg_instance 32228 "load_off() : Invalid number of vertices or primitives specified in file '%s'.", 32229 cimg_instance, 32230 filename?filename:"(FILE*)"); 32231 } 32232 32233 // Read points data 32234 assign(nb_points,3); 32235 float X = 0, Y = 0, Z = 0; 32236 cimg_forX(*this,l) { 32237 do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); 32238 if ((err = std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { 32239 if (!file) cimg::fclose(nfile); 32240 throw CImgIOException(_cimg_instance 32241 "load_off() : Failed to read vertex %u/%u in file '%s'.", 32242 cimg_instance, 32243 l+1,nb_points,filename?filename:"(FILE*)"); 32244 } 32245 (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z; 32246 } 32247 32248 // Read primitive data 32249 primitives.assign(); 32250 colors.assign(); 32251 bool stopflag = false; 32252 while (!stopflag) { 32253 float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f; 32254 unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0; 32255 line[0] = 0; 32256 if ((err = std::fscanf(nfile,"%u",&prim))!=1) stopflag=true; 32257 else { 32258 ++nb_read; 32259 switch (prim) { 32260 case 1 : { 32261 if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) { 32262 cimg::warn(_cimg_instance 32263 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32264 cimg_instance, 32265 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32266 32267 err = std::fscanf(nfile,"%*[^\n] "); 32268 } else { 32269 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32270 CImg<tf>::vector(i0).move_to(primitives); 32271 CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); 32272 } 32273 } break; 32274 case 2 : { 32275 if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) { 32276 cimg::warn(_cimg_instance 32277 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32278 cimg_instance, 32279 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32280 32281 err = std::fscanf(nfile,"%*[^\n] "); 32282 } else { 32283 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32284 CImg<tf>::vector(i0,i1).move_to(primitives); 32285 CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); 32286 } 32287 } break; 32288 case 3 : { 32289 if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) { 32290 cimg::warn(_cimg_instance 32291 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32292 cimg_instance, 32293 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32294 32295 err = std::fscanf(nfile,"%*[^\n] "); 32296 } else { 32297 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32298 CImg<tf>::vector(i0,i2,i1).move_to(primitives); 32299 CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); 32300 } 32301 } break; 32302 case 4 : { 32303 if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) { 32304 cimg::warn(_cimg_instance 32305 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32306 cimg_instance, 32307 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32308 32309 err = std::fscanf(nfile,"%*[^\n] "); 32310 } else { 32311 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32312 CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives); 32313 CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)).move_to(colors); 32314 } 32315 } break; 32316 case 5 : { 32317 if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) { 32318 cimg::warn(_cimg_instance 32319 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32320 cimg_instance, 32321 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32322 32323 err = std::fscanf(nfile,"%*[^\n] "); 32324 } else { 32325 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32326 CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives); 32327 CImg<tf>::vector(i0,i4,i3).move_to(primitives); 32328 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); 32329 ++nb_primitives; 32330 } 32331 } break; 32332 case 6 : { 32333 if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) { 32334 cimg::warn(_cimg_instance 32335 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32336 cimg_instance, 32337 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32338 32339 err = std::fscanf(nfile,"%*[^\n] "); 32340 } else { 32341 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32342 CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives); 32343 CImg<tf>::vector(i0,i5,i4,i3).move_to(primitives); 32344 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); 32345 ++nb_primitives; 32346 } 32347 } break; 32348 case 7 : { 32349 if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) { 32350 cimg::warn(_cimg_instance 32351 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32352 cimg_instance, 32353 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32354 32355 err = std::fscanf(nfile,"%*[^\n] "); 32356 } else { 32357 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32358 CImg<tf>::vector(i0,i4,i3,i1).move_to(primitives); 32359 CImg<tf>::vector(i0,i6,i5,i4).move_to(primitives); 32360 CImg<tf>::vector(i3,i2,i1).move_to(primitives); 32361 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); 32362 ++(++nb_primitives); 32363 } 32364 } break; 32365 case 8 : { 32366 if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) { 32367 cimg::warn(_cimg_instance 32368 "load_off() : Failed to read primitive %u/%u from file '%s'.", 32369 cimg_instance, 32370 nb_read,nb_primitives,filename?filename:"(FILE*)"); 32371 32372 err = std::fscanf(nfile,"%*[^\n] "); 32373 } else { 32374 err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2); 32375 CImg<tf>::vector(i0,i3,i2,i1).move_to(primitives); 32376 CImg<tf>::vector(i0,i5,i4,i3).move_to(primitives); 32377 CImg<tf>::vector(i0,i7,i6,i5).move_to(primitives); 32378 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); 32379 ++(++nb_primitives); 32380 } 32381 } break; 32382 default : 32383 cimg::warn(_cimg_instance 32384 "load_off() : Failed to read primitive %u/%u (%u vertices) from file '%s'.", 32385 cimg_instance, 32386 nb_read,nb_primitives,prim,filename?filename:"(FILE*)"); 32387 32388 err = std::fscanf(nfile,"%*[^\n] "); 32389 } 32390 } 32391 } 32392 if (!file) cimg::fclose(nfile); 32393 if (primitives._width!=nb_primitives) 32394 cimg::warn(_cimg_instance 32395 "load_off() : Only %u/%u primitives read from file '%s'.", 32396 cimg_instance, 32397 primitives._width,nb_primitives,filename?filename:"(FILE*)"); 32398 32399 return *this; 32400 } 32401 32402 //! Load a video sequence using FFMPEG's external tool 'ffmpeg'. 32403 CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') { 32404 return get_load_ffmpeg_external(filename,axis,align).move_to(*this); 32405 } 32406 32407 static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') { 32408 return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align); 32409 } 32410 32411 //! Load an image using GraphicsMagick's external tool 'gm'. 32412 CImg<T>& load_graphicsmagick_external(const char *const filename) { 32413 if (!filename) 32414 throw CImgArgumentException(_cimg_instance 32415 "load_graphicsmagick_external() : Specified filename is (null).", 32416 cimg_instance); 32417 32418 char command[1024] = { 0 }, filetmp[512] = { 0 }; 32419 std::FILE *file = 0; 32420 #if cimg_OS==1 32421 std::sprintf(command,"%s convert \"%s\" pnm:-",cimg::graphicsmagick_path(),filename); 32422 file = popen(command,"r"); 32423 if (file) { load_pnm(file); pclose(file); return *this; } 32424 #endif 32425 do { 32426 std::sprintf(filetmp,"%s%c%s.pnm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 32427 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 32428 } while (file); 32429 std::sprintf(command,"%s convert \"%s\" \"%s\"",cimg::graphicsmagick_path(),filename,filetmp); 32430 cimg::system(command,cimg::graphicsmagick_path()); 32431 if (!(file = std::fopen(filetmp,"rb"))) { 32432 cimg::fclose(cimg::fopen(filename,"r")); 32433 throw CImgIOException(_cimg_instance 32434 "load_graphicsmagick_external() : Failed to load file '%s' with external command 'gm'.", 32435 cimg_instance, 32436 filename); 32437 32438 } else cimg::fclose(file); 32439 load_pnm(filetmp); 32440 std::remove(filetmp); 32441 return *this; 32442 } 32443 32444 static CImg<T> get_load_graphicsmagick_external(const char *const filename) { 32445 return CImg<T>().load_graphicsmagick_external(filename); 32446 } 32447 32448 //! Load a gzipped image file, using external tool 'gunzip'. 32449 CImg<T>& load_gzip_external(const char *const filename) { 32450 if (!filename) 32451 throw CImgIOException(_cimg_instance 32452 "load_gzip_external() : Specified filename is (null).", 32453 cimg_instance); 32454 32455 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 32456 const char 32457 *const ext = cimg::split_filename(filename,body), 32458 *const ext2 = cimg::split_filename(body,0); 32459 32460 std::FILE *file = 0; 32461 do { 32462 if (!cimg::strcasecmp(ext,"gz")) { 32463 if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); 32464 else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 32465 } else { 32466 if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); 32467 else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 32468 } 32469 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 32470 } while (file); 32471 32472 std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp); 32473 cimg::system(command); 32474 if (!(file = std::fopen(filetmp,"rb"))) { 32475 cimg::fclose(cimg::fopen(filename,"r")); 32476 throw CImgIOException(_cimg_instance 32477 "load_gzip_external() : Failed to load file '%s' with external command 'gunzip'.", 32478 cimg_instance, 32479 filename); 32480 32481 } else cimg::fclose(file); 32482 load(filetmp); 32483 std::remove(filetmp); 32484 return *this; 32485 } 32486 32487 static CImg<T> get_load_gzip_external(const char *const filename) { 32488 return CImg<T>().load_gzip_external(filename); 32489 } 32490 32491 //! Load an image using ImageMagick's external tool 'convert'. 32492 CImg<T>& load_imagemagick_external(const char *const filename) { 32493 if (!filename) 32494 throw CImgArgumentException(_cimg_instance 32495 "load_imagemagick_external() : Specified filename is (null).", 32496 cimg_instance); 32497 32498 char command[1024] = { 0 }, filetmp[512] = { 0 }; 32499 std::FILE *file = 0; 32500 #if cimg_OS==1 32501 std::sprintf(command,"%s \"%s\" pnm:-",cimg::imagemagick_path(),filename); 32502 file = popen(command,"r"); 32503 if (file) { load_pnm(file); pclose(file); return *this; } 32504 #endif 32505 do { 32506 std::sprintf(filetmp,"%s%c%s.pnm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 32507 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 32508 } while (file); 32509 std::sprintf(command,"%s \"%s\" \"%s\"",cimg::imagemagick_path(),filename,filetmp); 32510 cimg::system(command,cimg::imagemagick_path()); 32511 if (!(file = std::fopen(filetmp,"rb"))) { 32512 cimg::fclose(cimg::fopen(filename,"r")); 32513 throw CImgIOException(_cimg_instance 32514 "load_imagemagick_external() : Failed to load file '%s' with external command 'convert'.", 32515 cimg_instance, 32516 filename); 32517 32518 } else cimg::fclose(file); 32519 load_pnm(filetmp); 32520 std::remove(filetmp); 32521 return *this; 32522 } 32523 32524 static CImg<T> get_load_imagemagick_external(const char *const filename) { 32525 return CImg<T>().load_imagemagick_external(filename); 32526 } 32527 32528 //! Load a DICOM image file, using XMedcon's external tool 'medcon'. 32529 CImg<T>& load_medcon_external(const char *const filename) { 32530 if (!filename) 32531 throw CImgArgumentException(_cimg_instance 32532 "load_medcon_external() : Specified filename is (null).", 32533 cimg_instance); 32534 32535 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 32536 cimg::fclose(cimg::fopen(filename,"r")); 32537 std::FILE *file = 0; 32538 do { 32539 std::sprintf(filetmp,"%s.hdr",cimg::filenamerand()); 32540 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 32541 } while (file); 32542 std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename); 32543 cimg::system(command); 32544 cimg::split_filename(filetmp,body); 32545 std::sprintf(command,"m000-%s.hdr",body); 32546 file = std::fopen(command,"rb"); 32547 if (!file) { 32548 throw CImgIOException(_cimg_instance 32549 "load_medcon_external() : Failed to load file '%s' with external command 'medcon'.", 32550 cimg_instance, 32551 filename); 32552 32553 } else cimg::fclose(file); 32554 load_analyze(command); 32555 std::remove(command); 32556 std::sprintf(command,"m000-%s.img",body); 32557 std::remove(command); 32558 return *this; 32559 } 32560 32561 static CImg<T> get_load_medcon_external(const char *const filename) { 32562 return CImg<T>().load_medcon_external(filename); 32563 } 32564 32565 //! Load a RAW Color Camera image file, using external tool 'dcraw'. 32566 CImg<T>& load_dcraw_external(const char *const filename) { 32567 if (!filename) 32568 throw CImgArgumentException(_cimg_instance 32569 "load_dcraw_external() : Specified filename is (null).", 32570 cimg_instance); 32571 32572 char command[1024] = { 0 }, filetmp[512] = { 0 }; 32573 std::FILE *file = 0; 32574 #if cimg_OS==1 32575 std::sprintf(command,"%s -w -4 -c \"%s\"",cimg::dcraw_path(),filename); 32576 file = popen(command,"r"); 32577 if (file) { load_pnm(file); pclose(file); return *this; } 32578 #endif 32579 do { 32580 std::sprintf(filetmp,"%s%c%s.ppm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 32581 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 32582 } while (file); 32583 std::sprintf(command,"%s -w -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp); 32584 cimg::system(command,cimg::dcraw_path()); 32585 if (!(file = std::fopen(filetmp,"rb"))) { 32586 cimg::fclose(cimg::fopen(filename,"r")); 32587 throw CImgIOException(_cimg_instance 32588 "load_dcraw_external() : Failed to load file '%s' with external command 'dcraw'.", 32589 cimg_instance, 32590 filename); 32591 32592 } else cimg::fclose(file); 32593 load_pnm(filetmp); 32594 std::remove(filetmp); 32595 return *this; 32596 } 32597 32598 static CImg<T> get_load_dcraw_external(const char *const filename) { 32599 return CImg<T>().load_dcraw_external(filename); 32600 } 32601 32602 //! Load an image using ImageMagick's or GraphicsMagick's executables. 32603 CImg<T>& load_other(const char *const filename) { 32604 if (!filename) 32605 throw CImgArgumentException(_cimg_instance 32606 "load_other() : Specified filename is (null).", 32607 cimg_instance); 32608 32609 const unsigned int omode = cimg::exception_mode(); 32610 cimg::exception_mode() = 0; 32611 try { load_magick(filename); } 32612 catch (CImgException&) { 32613 try { load_imagemagick_external(filename); } 32614 catch (CImgException&) { 32615 try { load_graphicsmagick_external(filename); } 32616 catch (CImgException&) { 32617 assign(); 32618 } 32619 } 32620 } 32621 cimg::exception_mode() = omode; 32622 if (is_empty()) 32623 throw CImgIOException(_cimg_instance 32624 "load_other() : Failed to load file '%s'. Format is not natively supported, and no external commands succeeded.", 32625 cimg_instance, 32626 filename); 32627 return *this; 32628 } 32629 32630 static CImg<T> get_load_other(const char *const filename) { 32631 return CImg<T>().load_other(filename); 32632 } 32633 32634 //@} 32635 //--------------------------- 32636 // 32637 //! \name Data Output 32638 //@{ 32639 //--------------------------- 32640 32641 //! Display informations about the image on the standard error output. 32642 /** 32643 \param title Name for the considered image (optional). 32644 \param display_stats Compute and display image statistics (optional). 32645 **/ 32646 const CImg<T>& print(const char *const title=0, const bool display_stats=true) const { 32647 int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0; 32648 static CImg<doubleT> st; 32649 if (!is_empty() && display_stats) { 32650 st = get_stats(); 32651 xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7]; 32652 xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11]; 32653 } 32654 const unsigned int siz = size(), msiz = siz*sizeof(T), siz1 = siz-1; 32655 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = _width-1; 32656 char ntitle[64] = { 0 }; 32657 if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type()); 32658 32659 std::fprintf(cimg::output(),"%s: this = %p, size = (%u,%u,%u,%u) [%u %s], data = (%s*)%p", 32660 title?title:ntitle,(void*)this,_width,_height,_depth,_spectrum, 32661 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), 32662 mdisp==0?"b":(mdisp==1?"Kb":"Mb"), 32663 pixel_type(),(void*)begin()); 32664 if (_data) std::fprintf(cimg::output(),"..%p (%s) = [ ",(void*)((char*)end()-1),_is_shared?"shared":"non-shared"); 32665 else std::fprintf(cimg::output()," (%s) = [ ",_is_shared?"shared":"non-shared"); 32666 32667 if (!is_empty()) cimg_foroff(*this,off) { 32668 std::fprintf(cimg::output(),cimg::type<T>::format(),cimg::type<T>::format(_data[off])); 32669 if (off!=siz1) std::fprintf(cimg::output(),"%s",off%_width==width1?" ; ":" "); 32670 if (off==7 && siz>16) { off = siz1-8; if (off!=7) std::fprintf(cimg::output(),"... "); } 32671 } 32672 if (!is_empty() && display_stats) 32673 std::fprintf(cimg::output()," ], min = %g, max = %g, mean = %g, std = %g, coords(min) = (%u,%u,%u,%u), coords(max) = (%u,%u,%u,%u).\n", 32674 st[0],st[1],st[2],std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM); 32675 else std::fprintf(cimg::output(),"%s].\n",is_empty()?"":" "); 32676 std::fflush(cimg::output()); 32677 return *this; 32678 } 32679 32680 //! Display an image into a CImgDisplay window. 32681 const CImg<T>& display(CImgDisplay& disp) const { 32682 disp.display(*this); 32683 return *this; 32684 } 32685 32686 //! Display an image in a window with a title \p title, and wait a '_is_closed' or 'keyboard' event.\n 32687 const CImg<T>& display(CImgDisplay &disp, const bool display_info) const { 32688 return _display(disp,0,display_info); 32689 } 32690 32691 //! Display an image in a window with a title \p title, and wait a '_is_closed' or 'keyboard' event.\n 32692 const CImg<T>& display(const char *const title=0, const bool display_info=true) const { 32693 CImgDisplay disp; 32694 return _display(disp,title,display_info); 32695 } 32696 32697 const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const { 32698 if (is_empty()) 32699 throw CImgInstanceException(_cimg_instance 32700 "display() : Empty instance.", 32701 cimg_instance); 32702 32703 unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0; 32704 int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1; 32705 char ntitle[256] = { 0 }; 32706 if (!disp) { 32707 if (!title) std::sprintf(ntitle,"CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); 32708 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:ntitle,1); 32709 } 32710 std::strncpy(ntitle,disp.title(),255); 32711 if (display_info) print(ntitle); 32712 disp.show().flush(); 32713 32714 CImg<T> zoom; 32715 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed(); ) { 32716 if (reset_view) { 32717 XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2; 32718 x0 = 0; y0 = 0; z0 = 0; x1 = _width - 1; y1 = _height-1; z1 = _depth-1; 32719 oldw = disp.width(); oldh = disp.height(); 32720 reset_view = false; 32721 } 32722 if (!x0 && !y0 && !z0 && x1==width()-1 && y1==height()-1 && z1==depth()-1) zoom.assign(); 32723 else zoom = get_crop(x0,y0,z0,x1,y1,z1); 32724 32725 const unsigned int 32726 dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0, 32727 tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0); 32728 if (resize_disp) { 32729 const unsigned int 32730 ttw = tw*disp.width()/oldw, tth = th*disp.height()/oldh, 32731 dM = cimg::max(ttw,tth), diM = (unsigned int)cimg::max(disp.width(),disp.height()), 32732 imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM); 32733 disp.set_fullscreen(false).resize(cimg_fitscreen(imgw,imgh,1),false); 32734 resize_disp = false; 32735 } 32736 oldw = tw; oldh = th; 32737 32738 bool 32739 go_up = false, go_down = false, go_left = false, go_right = false, 32740 go_inc = false, go_dec = false, go_in = false, go_out = false, 32741 go_in_center = false; 32742 const CImg<T>& visu = zoom?zoom:*this; 32743 const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0); 32744 32745 if (disp.wheel()) { 32746 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { go_out = !(go_in = disp.wheel()>0); go_in_center = false; } 32747 else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { go_right = !(go_left = disp.wheel()>0); } 32748 else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) { go_down = !(go_up = disp.wheel()>0); } 32749 disp.set_wheel(); 32750 } 32751 32752 const int 32753 sx0 = selection(0), sy0 = selection(1), sz0 = selection(2), 32754 sx1 = selection(3), sy1 = selection(4), sz1 = selection(5); 32755 if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) { 32756 x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0; 32757 if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true; 32758 resize_disp = true; 32759 } else switch (key = disp.key()) { 32760 #if cimg_OS!=2 32761 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : 32762 #endif 32763 case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : 32764 #if cimg_OS!=2 32765 case cimg::keyALTGR : 32766 #endif 32767 case cimg::keyALT : key = 0; break; 32768 case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) { // Special mode : play stack of frames 32769 const unsigned int 32770 w1 = visu._width*disp.width()/(visu._width+(visu._depth>1?visu._depth:0)), 32771 h1 = visu._height*disp.height()/(visu._height+(visu._depth>1?visu._depth:0)); 32772 float frametiming = 5; 32773 bool is_stopped = false; 32774 disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0; 32775 for (unsigned int timer = 0; !key && !disp.is_closed() && !disp.button(); ) { 32776 if (disp.is_resized()) disp.resize(false); 32777 if (!timer) { 32778 visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2])); 32779 (++XYZ[2])%=visu._depth; 32780 } 32781 if (!is_stopped) { if (++timer>(unsigned int)frametiming) timer = 0; } else timer = ~0U; 32782 if (disp.wheel()) { frametiming-=disp.wheel()/3.0f; disp.set_wheel(); } 32783 switch (key = disp.key()) { 32784 #if cimg_OS!=2 32785 case cimg::keyCTRLRIGHT : 32786 #endif 32787 case cimg::keyCTRLLEFT :key = 0; break; 32788 case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break; 32789 case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break; 32790 case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break; 32791 case cimg::keyARROWLEFT : case cimg::keyARROWUP : 32792 is_stopped = true; timer = 0; key = 0; break; 32793 case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : 32794 is_stopped = true; (XYZ[2]+=visu._depth-2)%=visu._depth; timer = 0; key = 0; break; 32795 case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 32796 disp.set_fullscreen(false).resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), 32797 CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false); 32798 disp.set_key(key,false); key = 0; 32799 } break; 32800 case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 32801 disp.set_fullscreen(false).resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false).set_key(key,false); key = 0; 32802 } break; 32803 case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 32804 disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false).set_key(key,false); key = 0; 32805 } break; 32806 case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 32807 disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen().set_key(key,false); key = 0; 32808 } break; 32809 } 32810 frametiming = frametiming<1?1:(frametiming>39?39:frametiming); 32811 disp.wait(20); 32812 } 32813 const unsigned int 32814 w2 = (visu._width + (visu._depth>1?visu._depth:0))*disp.width()/visu._width, 32815 h2 = (visu._height + (visu._depth>1?visu._depth:0))*disp.height()/visu._height; 32816 disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle).set_key().set_button().set_wheel(); 32817 key = 0; 32818 } break; 32819 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break; 32820 case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break; 32821 case cimg::keyPADSUB : go_out = true; key = 0; break; 32822 case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break; 32823 case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break; 32824 case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break; 32825 case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break; 32826 case cimg::keyPAD7 : go_up = go_left = true; key = 0; break; 32827 case cimg::keyPAD9 : go_up = go_right = true; key = 0; break; 32828 case cimg::keyPAD1 : go_down = go_left = true; key = 0; break; 32829 case cimg::keyPAD3 : go_down = go_right = true; key = 0; break; 32830 case cimg::keyPAGEUP : go_inc = true; key = 0; break; 32831 case cimg::keyPAGEDOWN : go_dec = true; key = 0; break; 32832 } 32833 if (go_in) { 32834 const int 32835 mx = go_in_center?disp.width()/2:disp.mouse_x(), 32836 my = go_in_center?disp.height()/2:disp.mouse_y(), 32837 mX = mx*(_width+(_depth>1?_depth:0))/disp.width(), 32838 mY = my*(_height+(_depth>1?_depth:0))/disp.height(); 32839 int X = XYZ[0], Y = XYZ[1], Z = XYZ[2]; 32840 if (mX<width() && mY<height()) { X = x0 + mX*(1+x1-x0)/_width; Y = y0 + mY*(1+y1-y0)/_height; Z = XYZ[2]; } 32841 if (mX<width() && mY>=height()) { X = x0 + mX*(1+x1-x0)/_width; Z = z0 + (mY-_height)*(1+z1-z0)/_depth; Y = XYZ[1]; } 32842 if (mX>=width() && mY<height()) { Y = y0 + mY*(1+y1-y0)/_height; Z = z0 + (mX-_width)*(1+z1-z0)/_depth; X = XYZ[0]; } 32843 if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; } 32844 if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; } 32845 if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; } 32846 } 32847 if (go_out) { 32848 const int 32849 deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8, 32850 ndeltax = deltax?deltax:(_width>1?1:0), 32851 ndeltay = deltay?deltay:(_height>1?1:0), 32852 ndeltaz = deltaz?deltaz:(_depth>1?1:0); 32853 x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz; 32854 x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz; 32855 if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; } 32856 if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; } 32857 if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; } 32858 if (x1>=width()) { x0-=(x1-width()+1); x1 = width()-1; if (x0<0) x0 = 0; } 32859 if (y1>=height()) { y0-=(y1-height()+1); y1 = height()-1; if (y0<0) y0 = 0; } 32860 if (z1>=depth()) { z0-=(z1-depth()+1); z1 = depth()-1; if (z0<0) z0 = 0; } 32861 } 32862 if (go_left) { 32863 const int delta = (x1-x0)/5, ndelta = delta?delta:(_width>1?1:0); 32864 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; } 32865 else { x1-=x0; x0 = 0; } 32866 } 32867 if (go_right) { 32868 const int delta = (x1-x0)/5, ndelta = delta?delta:(_width>1?1:0); 32869 if (x1+ndelta<width()) { x0+=ndelta; x1+=ndelta; } 32870 else { x0+=(width()-1-x1); x1 = width()-1; } 32871 } 32872 if (go_up) { 32873 const int delta = (y1-y0)/5, ndelta = delta?delta:(_height>1?1:0); 32874 if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; } 32875 else { y1-=y0; y0 = 0; } 32876 } 32877 if (go_down) { 32878 const int delta = (y1-y0)/5, ndelta = delta?delta:(_height>1?1:0); 32879 if (y1+ndelta<height()) { y0+=ndelta; y1+=ndelta; } 32880 else { y0+=(height()-1-y1); y1 = height()-1; } 32881 } 32882 if (go_inc) { 32883 const int delta = (z1-z0)/5, ndelta = delta?delta:(_depth>1?1:0); 32884 if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; } 32885 else { z1-=z0; z0 = 0; } 32886 } 32887 if (go_dec) { 32888 const int delta = (z1-z0)/5, ndelta = delta?delta:(_depth>1?1:0); 32889 if (z1+ndelta<depth()) { z0+=ndelta; z1+=ndelta; } 32890 else { z0+=(depth()-1-z1); z1 = depth()-1; } 32891 } 32892 } 32893 disp.set_key(key); 32894 return *this; 32895 } 32896 32897 //! High-level interface for displaying a 3d object. 32898 template<typename tp, typename tf, typename tc, typename to> 32899 const CImg<T>& display_object3d(CImgDisplay& disp, 32900 const CImg<tp>& vertices, 32901 const CImgList<tf>& primitives, 32902 const CImgList<tc>& colors, 32903 const to& opacities, 32904 const bool centering=true, 32905 const int render_static=4, const int render_motion=1, 32906 const bool double_sided=true, const float focale=500, 32907 const float light_x=0, const float light_y=0, const float light_z=-5000, 32908 const float specular_light=0.2f, const float specular_shine=0.1f, 32909 const bool display_axes=true, float *const pose_matrix=0) const { 32910 return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static, 32911 render_motion,double_sided,focale, 32912 light_x,light_y,light_z,specular_light,specular_shine, 32913 display_axes,pose_matrix); 32914 } 32915 32916 //! High-level interface for displaying a 3d object. 32917 template<typename tp, typename tf, typename tc, typename to> 32918 const CImg<T>& display_object3d(const char *const title, 32919 const CImg<tp>& vertices, 32920 const CImgList<tf>& primitives, 32921 const CImgList<tc>& colors, 32922 const to& opacities, 32923 const bool centering=true, 32924 const int render_static=4, const int render_motion=1, 32925 const bool double_sided=true, const float focale=500, 32926 const float light_x=0, const float light_y=0, const float light_z=-5000, 32927 const float specular_light=0.2f, const float specular_shine=0.1f, 32928 const bool display_axes=true, float *const pose_matrix=0) const { 32929 CImgDisplay disp; 32930 return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static, 32931 render_motion,double_sided,focale, 32932 light_x,light_y,light_z,specular_light,specular_shine, 32933 display_axes,pose_matrix); 32934 } 32935 32936 //! High-level interface for displaying a 3d object. 32937 template<typename tp, typename tf, typename tc> 32938 const CImg<T>& display_object3d(CImgDisplay &disp, 32939 const CImg<tp>& vertices, 32940 const CImgList<tf>& primitives, 32941 const CImgList<tc>& colors, 32942 const bool centering=true, 32943 const int render_static=4, const int render_motion=1, 32944 const bool double_sided=true, const float focale=500, 32945 const float light_x=0, const float light_y=0, const float light_z=-5000, 32946 const float specular_light=0.2f, const float specular_shine=0.1f, 32947 const bool display_axes=true, float *const pose_matrix=0) const { 32948 return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering, 32949 render_static,render_motion,double_sided,focale, 32950 light_x,light_y,light_z,specular_light,specular_shine, 32951 display_axes,pose_matrix); 32952 } 32953 32954 //! High-level interface for displaying a 3d object. 32955 template<typename tp, typename tf, typename tc> 32956 const CImg<T>& display_object3d(const char *const title, 32957 const CImg<tp>& vertices, 32958 const CImgList<tf>& primitives, 32959 const CImgList<tc>& colors, 32960 const bool centering=true, 32961 const int render_static=4, const int render_motion=1, 32962 const bool double_sided=true, const float focale=500, 32963 const float light_x=0, const float light_y=0, const float light_z=-5000, 32964 const float specular_light=0.2f, const float specular_shine=0.1f, 32965 const bool display_axes=true, float *const pose_matrix=0) const { 32966 return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering, 32967 render_static,render_motion,double_sided,focale, 32968 light_x,light_y,light_z,specular_light,specular_shine, 32969 display_axes,pose_matrix); 32970 } 32971 32972 //! High-level interface for displaying a 3d object. 32973 template<typename tp, typename tf> 32974 const CImg<T>& display_object3d(CImgDisplay &disp, 32975 const CImg<tp>& vertices, 32976 const CImgList<tf>& primitives, 32977 const bool centering=true, 32978 const int render_static=4, const int render_motion=1, 32979 const bool double_sided=true, const float focale=500, 32980 const float light_x=0, const float light_y=0, const float light_z=-5000, 32981 const float specular_light=0.2f, const float specular_shine=0.1f, 32982 const bool display_axes=true, float *const pose_matrix=0) const { 32983 return display_object3d(disp,vertices,primitives,CImgList<T>(),centering, 32984 render_static,render_motion,double_sided,focale, 32985 light_x,light_y,light_z,specular_light,specular_shine, 32986 display_axes,pose_matrix); 32987 } 32988 32989 //! High-level interface for displaying a 3d object. 32990 template<typename tp, typename tf> 32991 const CImg<T>& display_object3d(const char *const title, 32992 const CImg<tp>& vertices, 32993 const CImgList<tf>& primitives, 32994 const bool centering=true, 32995 const int render_static=4, const int render_motion=1, 32996 const bool double_sided=true, const float focale=500, 32997 const float light_x=0, const float light_y=0, const float light_z=-5000, 32998 const float specular_light=0.2f, const float specular_shine=0.1f, 32999 const bool display_axes=true, float *const pose_matrix=0) const { 33000 return display_object3d(title,vertices,primitives,CImgList<T>(),centering, 33001 render_static,render_motion,double_sided,focale, 33002 light_x,light_y,light_z,specular_light,specular_shine, 33003 display_axes,pose_matrix); 33004 } 33005 33006 //! High-level interface for displaying a 3d object. 33007 template<typename tp> 33008 const CImg<T>& display_object3d(CImgDisplay &disp, 33009 const CImg<tp>& vertices, 33010 const bool centering=true, 33011 const int render_static=4, const int render_motion=1, 33012 const bool double_sided=true, const float focale=500, 33013 const float light_x=0, const float light_y=0, const float light_z=-5000, 33014 const float specular_light=0.2f, const float specular_shine=0.1f, 33015 const bool display_axes=true, float *const pose_matrix=0) const { 33016 return display_object3d(disp,vertices,CImgList<uintT>(),centering, 33017 render_static,render_motion,double_sided,focale, 33018 light_x,light_y,light_z,specular_light,specular_shine, 33019 display_axes,pose_matrix); 33020 } 33021 33022 //! High-level interface for displaying a 3d object. 33023 template<typename tp> 33024 const CImg<T>& display_object3d(const char *const title, 33025 const CImg<tp>& vertices, 33026 const bool centering=true, 33027 const int render_static=4, const int render_motion=1, 33028 const bool double_sided=true, const float focale=500, 33029 const float light_x=0, const float light_y=0, const float light_z=-5000, 33030 const float specular_light=0.2f, const float specular_shine=0.1f, 33031 const bool display_axes=true, float *const pose_matrix=0) const { 33032 return display_object3d(title,vertices,CImgList<uintT>(),centering, 33033 render_static,render_motion,double_sided,focale, 33034 light_x,light_y,light_z,specular_light,specular_shine, 33035 display_axes,pose_matrix); 33036 } 33037 33038 template<typename tp, typename tf, typename tc, typename to> 33039 const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title, 33040 const CImg<tp>& vertices, 33041 const CImgList<tf>& primitives, 33042 const CImgList<tc>& colors, 33043 const to& opacities, 33044 const bool centering, 33045 const int render_static, const int render_motion, 33046 const bool double_sided, const float focale, 33047 const float light_x, const float light_y, const float light_z, 33048 const float specular_light, const float specular_shine, 33049 const bool display_axes, float *const pose_matrix) const { 33050 33051 // Check input arguments 33052 if (is_empty()) { 33053 if (disp) return CImg<T>(disp.width(),disp.height(),1,(colors && colors[0].size()==1)?1:3,0). 33054 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, 33055 render_static,render_motion,double_sided,focale, 33056 light_x,light_y,light_z,specular_light,specular_shine, 33057 display_axes,pose_matrix); 33058 else return CImg<T>(cimg_fitscreen(640,480,1),1,(colors && colors[0].size()==1)?1:3,0). 33059 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, 33060 render_static,render_motion,double_sided,focale, 33061 light_x,light_y,light_z,specular_light,specular_shine, 33062 display_axes,pose_matrix); 33063 } else { if (disp) disp.resize(*this,false); } 33064 char error_message[1024] = { 0 }; 33065 if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) 33066 throw CImgArgumentException(_cimg_instance 33067 "display_object3d() : Invalid specified 3d object (%u,%u) (%s).", 33068 cimg_instance,vertices._width,primitives._width,error_message); 33069 if (vertices._width && !primitives) { 33070 CImgList<tf> nprimitives(vertices._width,1,1,1,1); 33071 cimglist_for(nprimitives,l) nprimitives(l,0) = l; 33072 return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, 33073 render_static,render_motion,double_sided,focale, 33074 light_x,light_y,light_z,specular_light,specular_shine, 33075 display_axes,pose_matrix); 33076 } 33077 if (!disp) { 33078 char ntitle[256] = { 0 }; 33079 if (!title) { std::sprintf(ntitle,"CImg<%s> (%u vertices, %u primitives)",pixel_type(),vertices._width,primitives._width); } 33080 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:ntitle,3); 33081 } 33082 33083 // Init 3d objects and compute object statistics 33084 CImgList<tf> reverse_primitives; 33085 CImg<floatT> 33086 pose, rot_mat, 33087 centered_vertices = centering?CImg<floatT>(vertices._width,3):CImg<floatT>(), 33088 rotated_vertices(vertices._width,3), 33089 bbox_vertices, rotated_bbox_vertices, 33090 axes_vertices, rotated_axes_vertices, 33091 bbox_opacities, axes_opacities; 33092 CImgList<uintT> bbox_primitives, axes_primitives; 33093 CImgList<T> bbox_colors, bbox_colors2, axes_colors; 33094 float dx = 0, dy = 0, dz = 0, ratio = 1; 33095 33096 T minval = (T)0, maxval = (T)255; 33097 if (disp.normalization() && colors) { 33098 minval = colors.min_max(maxval); 33099 if (minval==maxval) { minval = (T)0; maxval = (T)255; } 33100 } 33101 unsigned int ns_width = 0, ns_height = 0; 33102 const float meanval = (float)mean(); 33103 bool color_model = true, ndisplay_axes = display_axes; 33104 int _double_sided = (int)double_sided; 33105 if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false; 33106 const CImg<T> 33107 background_color(1,1,1,_spectrum,color_model?minval:maxval), 33108 foreground_color(1,1,1,_spectrum,color_model?maxval:minval); 33109 33110 float xm = cimg::type<float>::max(), xM = cimg::type<float>::min(), ym = xm, yM = xM, zm = xm, zM = xM; 33111 cimg_forX(vertices,i) { 33112 const float x = (float)vertices(i,0), y = (float)vertices(i,1), z = (float)vertices(i,2); 33113 if (x<xm) xm = x; 33114 if (x>xM) xM = x; 33115 if (y<ym) ym = y; 33116 if (y>yM) yM = y; 33117 if (z<zm) zm = z; 33118 if (z>zM) zM = z; 33119 } 33120 const float delta = cimg::max(xM-xm,yM-ym,zM-zm); 33121 rotated_axes_vertices = axes_vertices.assign(7,3,1,1, 33122 0,20,0,0,22,-6,-6, 33123 0,0,20,0,-6,22,-6, 33124 0,0,0,20,0,0,22); 33125 axes_opacities.assign(3,1,1,1,1); 33126 axes_colors.assign(3,_spectrum,1,1,1,foreground_color[0]); 33127 axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3); 33128 33129 // Begin user interaction loop 33130 CImg<T> visu0(*this), visu; 33131 CImg<floatT> zbuffer(visu0.width(),visu0.height(),1,1,0); 33132 bool init = true, clicked = false, redraw = true; 33133 unsigned int key = 0; 33134 int 33135 x0 = 0, y0 = 0, x1 = 0, y1 = 0, 33136 nrender_static = render_static, 33137 nrender_motion = render_motion; 33138 disp.show().flush(); 33139 33140 while (!disp.is_closed() && !key) { 33141 33142 // Init object position and scale if necessary 33143 if (init) { 33144 ratio = delta>0?(2.0f*cimg::min(disp.width(),disp.height())/(3.0f*delta)):0; 33145 dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm); 33146 if (centering) { 33147 cimg_forX(centered_vertices,l) { 33148 centered_vertices(l,0) = (float)((vertices(l,0) - dx)*ratio); 33149 centered_vertices(l,1) = (float)((vertices(l,1) - dy)*ratio); 33150 centered_vertices(l,2) = (float)((vertices(l,2) - dz)*ratio); 33151 } 33152 } 33153 rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1, 33154 xm,xM,xM,xm,xm,xM,xM,xm, 33155 ym,ym,yM,yM,ym,ym,yM,yM, 33156 zm,zm,zm,zm,zM,zM,zM,zM); 33157 bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6); 33158 bbox_colors.assign(6,_spectrum,1,1,1,background_color[0]); 33159 bbox_colors2.assign(6,_spectrum,1,1,1,foreground_color[0]); 33160 bbox_opacities.assign(bbox_colors._width,1,1,1,0.3f); 33161 33162 if (!pose) { 33163 if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,3,1,1,false); 33164 else pose = CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0); 33165 } 33166 init = false; 33167 redraw = true; 33168 } 33169 33170 // Rotate and draw 3d object 33171 if (redraw) { 33172 const float 33173 r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0), 33174 r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1), 33175 r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2); 33176 if ((clicked && nrender_motion>=0) || (!clicked && nrender_static>=0)) { 33177 if (centering) cimg_forX(centered_vertices,l) { 33178 const float x = centered_vertices(l,0), y = centered_vertices(l,1), z = centered_vertices(l,2); 33179 rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30; 33180 rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31; 33181 rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32; 33182 } else cimg_forX(vertices,l) { 33183 const float 33184 x = (float)vertices(l,0), 33185 y = (float)vertices(l,1), 33186 z = (float)vertices(l,2); 33187 rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30; 33188 rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31; 33189 rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32; 33190 } 33191 } else { 33192 if (!centering) cimg_forX(bbox_vertices,l) { 33193 const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2); 33194 rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30; 33195 rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31; 33196 rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32; 33197 } else cimg_forX(bbox_vertices,l) { 33198 const float x = (bbox_vertices(l,0) - dx)*ratio, y = (bbox_vertices(l,1) - dy)*ratio, z = (bbox_vertices(l,2) - dz)*ratio; 33199 rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30; 33200 rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31; 33201 rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32; 33202 } 33203 } 33204 33205 // Draw object 33206 visu = visu0; 33207 if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0)) 33208 visu.draw_object3d(visu._width/2.0f,visu._height/2.0f,0,rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale). 33209 draw_object3d(visu._width/2.0f,visu._height/2.0f,0,rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale); 33210 else visu.draw_object3d(visu._width/2.0f,visu._height/2.0f,0, 33211 rotated_vertices,reverse_primitives?reverse_primitives:primitives, 33212 colors,opacities,clicked?nrender_motion:nrender_static,_double_sided==1,focale, 33213 width()/2.0f+light_x,height()/2.0f+light_y,light_z,specular_light,specular_shine, 33214 (!clicked && nrender_static>0)?zbuffer.fill(0):CImg<floatT>::empty()); 33215 33216 // Draw axes 33217 if (ndisplay_axes) { 33218 const float Xaxes = 25, Yaxes = visu._height - 38.0f; 33219 cimg_forX(axes_vertices,l) { 33220 const float x = axes_vertices(l,0), y = axes_vertices(l,1), z = axes_vertices(l,2); 33221 rotated_axes_vertices(l,0) = r00*x + r10*y + r20*z; 33222 rotated_axes_vertices(l,1) = r01*x + r11*y + r21*z; 33223 rotated_axes_vertices(l,2) = r02*x + r12*y + r22*z; 33224 } 33225 axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.0f; 33226 axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.0f; 33227 axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f; 33228 visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives,axes_colors,axes_opacities,1,false,focale). 33229 draw_text((int)(Xaxes+rotated_axes_vertices(4,0)), 33230 (int)(Yaxes+rotated_axes_vertices(4,1)), 33231 "X",axes_colors[0]._data,0,axes_opacities(0,0),13). 33232 draw_text((int)(Xaxes+rotated_axes_vertices(5,0)), 33233 (int)(Yaxes+rotated_axes_vertices(5,1)), 33234 "Y",axes_colors[1]._data,0,axes_opacities(1,0),13). 33235 draw_text((int)(Xaxes+rotated_axes_vertices(6,0)), 33236 (int)(Yaxes+rotated_axes_vertices(6,1)), 33237 "Z",axes_colors[2]._data,0,axes_opacities(2,0),13); 33238 } 33239 visu.display(disp); 33240 if (!clicked || nrender_motion==nrender_static) redraw = false; 33241 } 33242 33243 // Handle user interaction 33244 disp.wait(); 33245 if ((disp.button() || disp.wheel()) && disp.mouse_x()>=0 && disp.mouse_y()>=0) { 33246 redraw = true; 33247 if (!clicked) { x0 = x1 = disp.mouse_x(); y0 = y1 = disp.mouse_y(); if (!disp.wheel()) clicked = true; } 33248 else { x1 = disp.mouse_x(); y1 = disp.mouse_y(); } 33249 if (disp.button()&1) { 33250 const float 33251 R = 0.45f*cimg::min(disp.width(),disp.height()), 33252 R2 = R*R, 33253 u0 = (float)(x0-disp.width()/2), 33254 v0 = (float)(y0-disp.height()/2), 33255 u1 = (float)(x1-disp.width()/2), 33256 v1 = (float)(y1-disp.height()/2), 33257 n0 = (float)std::sqrt(u0*u0+v0*v0), 33258 n1 = (float)std::sqrt(u1*u1+v1*v1), 33259 nu0 = n0>R?(u0*R/n0):u0, 33260 nv0 = n0>R?(v0*R/n0):v0, 33261 nw0 = (float)std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)), 33262 nu1 = n1>R?(u1*R/n1):u1, 33263 nv1 = n1>R?(v1*R/n1):v1, 33264 nw1 = (float)std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)), 33265 u = nv0*nw1-nw0*nv1, 33266 v = nw0*nu1-nu0*nw1, 33267 w = nv0*nu1-nu0*nv1, 33268 n = (float)std::sqrt(u*u+v*v+w*w), 33269 alpha = (float)std::asin(n/R2); 33270 rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha); 33271 rot_mat*=pose.get_crop(0,0,2,2); 33272 pose.draw_image(rot_mat); 33273 x0=x1; y0=y1; 33274 } 33275 if (disp.button()&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; } 33276 if (disp.wheel()) { pose(3,2)-=focale*disp.wheel()/10; disp.set_wheel(); } 33277 if (disp.button()&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; } 33278 if ((disp.button()&1) && (disp.button()&2)) { 33279 init = true; disp.set_button(); x0 = x1; y0 = y1; 33280 pose = CImg<floatT>(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0); 33281 } 33282 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; } 33283 33284 switch (key = disp.key()) { 33285 #if cimg_OS!=2 33286 case cimg::keyCTRLRIGHT : 33287 #endif 33288 case 0 : case cimg::keyCTRLLEFT : key = 0; break; 33289 case cimg::keyD: if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 33290 disp.set_fullscreen(false).resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), 33291 CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). 33292 _is_resized = true; 33293 disp.set_key(key,false); key = 0; 33294 } break; 33295 case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 33296 disp.set_fullscreen(false).resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; 33297 disp.set_key(key,false); key = 0; 33298 } break; 33299 case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 33300 disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; 33301 disp.set_key(key,false); key = 0; 33302 } break; 33303 case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 33304 if (!ns_width || !ns_height || 33305 ns_width>(unsigned int)disp.screen_width() || ns_height>(unsigned int)disp.screen_height()) { 33306 ns_width = disp.screen_width()*3U/4; 33307 ns_height = disp.screen_height()*3U/4; 33308 } 33309 if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false); 33310 else { 33311 ns_width = (unsigned int)disp.width(); ns_height = disp.height(); 33312 disp.resize(disp.screen_width(),disp.screen_height(),false); 33313 } 33314 disp.toggle_fullscreen()._is_resized = true; 33315 disp.set_key(key,false); key = 0; 33316 } break; 33317 case cimg::keyT : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Switch single/double-sided primitives. 33318 if (--_double_sided==-2) _double_sided = 1; 33319 if (_double_sided>=0) reverse_primitives.assign(); 33320 else primitives.get_reverse_object3d().move_to(reverse_primitives); 33321 disp.set_key(key,false); key = 0; redraw = true; 33322 } break; 33323 case cimg::keyZ : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Enable/disable Z-buffer 33324 if (zbuffer) zbuffer.assign(); 33325 else zbuffer.assign(visu0.width(),visu0.height(),1,1,0); 33326 disp.set_key(key,false); key = 0; redraw = true; 33327 } break; 33328 case cimg::keyA : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Show/hide 3d axes. 33329 ndisplay_axes = !ndisplay_axes; 33330 disp.set_key(key,false); key = 0; redraw = true; 33331 } break; 33332 case cimg::keyF1 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to points. 33333 nrender_motion = (nrender_static==0 && nrender_motion!=0)?0:-1; nrender_static = 0; 33334 disp.set_key(key,false); key = 0; redraw = true; 33335 } break; 33336 case cimg::keyF2 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to lines. 33337 nrender_motion = (nrender_static==1 && nrender_motion!=1)?1:-1; nrender_static = 1; 33338 disp.set_key(key,false); key = 0; redraw = true; 33339 } break; 33340 case cimg::keyF3 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat. 33341 nrender_motion = (nrender_static==2 && nrender_motion!=2)?2:-1; nrender_static = 2; 33342 disp.set_key(key,false); key = 0; redraw = true; 33343 } break; 33344 case cimg::keyF4 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat-shaded. 33345 nrender_motion = (nrender_static==3 && nrender_motion!=3)?3:-1; nrender_static = 3; 33346 disp.set_key(key,false); key = 0; redraw = true; 33347 } break; 33348 case cimg::keyF5 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to gouraud-shaded. 33349 nrender_motion = (nrender_static==4 && nrender_motion!=4)?4:-1; nrender_static = 4; 33350 disp.set_key(key,false); key = 0; redraw = true; 33351 } break; 33352 case cimg::keyF6 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to phong-shaded. 33353 nrender_motion = (nrender_static==5 && nrender_motion!=5)?5:-1; nrender_static = 5; 33354 disp.set_key(key,false); key = 0; redraw = true; 33355 } break; 33356 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot 33357 static unsigned int snap_number = 0; 33358 char filename[32] = { 0 }; 33359 std::FILE *file; 33360 do { 33361 std::sprintf(filename,"CImg_%.4u.bmp",snap_number++); 33362 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 33363 } while (file); 33364 (+visu).draw_text(0,0," Saving snapshot... ",foreground_color._data,background_color._data,1,13).display(disp); 33365 visu.save(filename); 33366 visu.draw_text(0,0," Snapshot '%s' saved. ",foreground_color._data,background_color._data,1,13,filename).display(disp); 33367 disp.set_key(key,false); key = 0; 33368 } break; 33369 case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file 33370 static unsigned int snap_number = 0; 33371 char filename[32] = { 0 }; 33372 std::FILE *file; 33373 do { 33374 std::sprintf(filename,"CImg_%.4u.off",snap_number++); 33375 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 33376 } while (file); 33377 visu.draw_text(0,0," Saving object... ",foreground_color._data,background_color._data,1,13).display(disp); 33378 vertices.save_off(filename,reverse_primitives?reverse_primitives:primitives,colors); 33379 visu.draw_text(0,0," Object '%s' saved. ",foreground_color._data,background_color._data,1,13,filename).display(disp); 33380 disp.set_key(key,false); key = 0; 33381 } break; 33382 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file 33383 static unsigned int snap_number = 0; 33384 char filename[32] = { 0 }; 33385 std::FILE *file; 33386 do { 33387 std::sprintf(filename,"CImg_%.4u.cimg",snap_number++); 33388 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 33389 } while (file); 33390 visu.draw_text(0,0," Saving object... ",foreground_color._data,background_color._data,1,13).display(disp); 33391 vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities).save_cimg(filename); 33392 visu.draw_text(0,0," Object '%s' saved. ",foreground_color._data,background_color._data,1,13,filename).display(disp); 33393 disp.set_key(key,false); key = 0; 33394 } break; 33395 #ifdef cimg_use_board 33396 case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file 33397 static unsigned int snap_number = 0; 33398 char filename[32] = { 0 }; 33399 std::FILE *file; 33400 do { 33401 std::sprintf(filename,"CImg_%.4u.eps",snap_number++); 33402 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 33403 } while (file); 33404 visu.draw_text(0,0," Saving EPS snapshot... ",foreground_color._data,background_color._data,1,13).display(disp); 33405 LibBoard::Board board; 33406 (+visu).draw_object3d(board,visu._width/2.0f,visu._height/2.0f,0, 33407 rotated_vertices,reverse_primitives?reverse_primitives:primitives, 33408 colors,opacities,clicked?nrender_motion:nrender_static, 33409 _double_sided==1,focale, 33410 visu.width()/2.0f+light_x,visu.height()/2.0f+light_y,light_z,specular_light,specular_shine, 33411 zbuffer.fill(0)); 33412 board.saveEPS(filename); 33413 visu.draw_text(0,0," Object '%s' saved. ",foreground_color._data,background_color._data,1,13,filename).display(disp); 33414 disp.set_key(key,false); key = 0; 33415 } break; 33416 case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file 33417 static unsigned int snap_number = 0; 33418 char filename[32] = { 0 }; 33419 std::FILE *file; 33420 do { 33421 std::sprintf(filename,"CImg_%.4u.svg",snap_number++); 33422 if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); 33423 } while (file); 33424 visu.draw_text(0,0," Saving SVG snapshot... ",foreground_color._data,background_color._data,1,13).display(disp); 33425 LibBoard::Board board; 33426 (+visu).draw_object3d(board,visu._width/2.0f,visu._height/2.0f,0, 33427 rotated_vertices,reverse_primitives?reverse_primitives:primitives, 33428 colors,opacities,clicked?nrender_motion:nrender_static, 33429 _double_sided==1,focale, 33430 visu.width()/2.0f+light_x,visu.height()/2.0f+light_y,light_z,specular_light,specular_shine, 33431 zbuffer.fill(0)); 33432 board.saveSVG(filename); 33433 visu.draw_text(0,0," Object '%s' saved. ",foreground_color._data,background_color._data,1,13,filename).display(disp); 33434 disp.set_key(key,false); key = 0; 33435 } break; 33436 #endif 33437 } 33438 if (disp.is_resized()) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width(),disp.height()); redraw = true; } 33439 } 33440 if (pose_matrix) std::memcpy(pose_matrix,pose._data,12*sizeof(float)); 33441 disp.set_button().set_key(key); 33442 return *this; 33443 } 33444 33445 //! High-level interface for displaying a graph. 33446 const CImg<T>& display_graph(CImgDisplay &disp, 33447 const unsigned int plot_type=1, const unsigned int vertex_type=1, 33448 const char *const labelx=0, const double xmin=0, const double xmax=0, 33449 const char *const labely=0, const double ymin=0, const double ymax=0) const { 33450 if (is_empty()) 33451 throw CImgInstanceException(_cimg_instance 33452 "display_graph() : Empty instance.", 33453 cimg_instance); 33454 33455 const unsigned int siz = _width*_height*_depth, onormalization = disp.normalization(); 33456 if (!disp) { char ntitle[64] = { 0 }; std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); } 33457 disp.show().flush()._normalization = 0; 33458 double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax; 33459 if (nxmin==nxmax) { nxmin = 0; nxmax = siz; } 33460 int x0 = 0, x1 = width()*height()*depth() - 1, key = 0; 33461 33462 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed(); ) { 33463 if (reset_view) { x0 = 0; x1 = width()*height()*depth()-1; y0 = ymin; y1 = ymax; reset_view = false; } 33464 CImg<T> zoom(x1-x0+1,1,1,spectrum()); 33465 cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg<T>(data(x0,0,0,c),x1-x0+1,1,1,1,true); 33466 33467 if (y0==y1) y0 = zoom.min_max(y1); 33468 if (y0==y1) { --y0; ++y1; } 33469 const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type, 33470 labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + (x1+1)*(nxmax-nxmin)/siz, 33471 labely,y0,y1); 33472 33473 const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); 33474 if (selection[0]>=0 && selection[2]>=0) { 33475 x1 = x0 + selection[2]; 33476 x0+=selection[0]; 33477 if (x0==x1) reset_view = true; 33478 if (selection[1]>=0 && selection[3]>=0) { 33479 y0 = y1 - selection[3]*(y1-y0)/(disp.height()-32); 33480 y1-=selection[1]*(y1-y0)/(disp.height()-32); 33481 } 33482 } else { 33483 bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false; 33484 switch (key = disp.key()) { 33485 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; disp.set_key(); break; 33486 case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break; 33487 case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break; 33488 case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key(); break; 33489 case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key(); break; 33490 case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break; 33491 case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break; 33492 case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break; 33493 case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break; 33494 case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break; 33495 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break; 33496 } 33497 if (disp.wheel()) { 33498 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_out = !(go_in = disp.wheel()>0); 33499 else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0); 33500 else go_up = !(go_down = disp.wheel()<0); 33501 key = 0; 33502 } 33503 33504 if (go_in) { 33505 const int 33506 xsiz = x1 - x0, 33507 mx = (mouse_x-16)*xsiz/(disp.width()-32), 33508 cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx)); 33509 if (x1-x0>4) { 33510 x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8; 33511 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 33512 const double 33513 ysiz = y1 - y0, 33514 my = (mouse_y-16)*ysiz/(disp.height()-32), 33515 cy = y1 - (my<0?0:(my>=ysiz?ysiz:my)); 33516 y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8; 33517 } else y0 = y1 = 0; 33518 } 33519 } 33520 if (go_out) { 33521 if (x0>0 || x1<(int)siz-1) { 33522 const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0); 33523 const double ndeltay = (y1-y0)/8; 33524 x0-=ndeltax; x1+=ndeltax; 33525 y0-=ndeltay; y1+=ndeltay; 33526 if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; } 33527 if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; } 33528 } 33529 } 33530 if (go_left) { 33531 const int delta = (x1-x0)/5, ndelta = delta?delta:1; 33532 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; } 33533 else { x1-=x0; x0 = 0; } 33534 go_left = false; 33535 } 33536 if (go_right) { 33537 const int delta = (x1-x0)/5, ndelta = delta?delta:1; 33538 if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; } 33539 else { x0+=(siz-1-x1); x1 = siz-1; } 33540 go_right = false; 33541 } 33542 if (go_up) { 33543 const double delta = (y1-y0)/10, ndelta = delta?delta:1; 33544 y0+=ndelta; y1+=ndelta; 33545 go_up = false; 33546 } 33547 if (go_down) { 33548 const double delta = (y1-y0)/10, ndelta = delta?delta:1; 33549 y0-=ndelta; y1-=ndelta; 33550 go_down = false; 33551 } 33552 } 33553 } 33554 disp._normalization = onormalization; 33555 return *this; 33556 } 33557 33558 //! High-level interface for displaying a graph. 33559 const CImg<T>& display_graph(const char *const title=0, 33560 const unsigned int plot_type=1, const unsigned int vertex_type=1, 33561 const char *const labelx=0, const double xmin=0, const double xmax=0, 33562 const char *const labely=0, const double ymin=0, const double ymax=0) const { 33563 if (is_empty()) 33564 throw CImgInstanceException(_cimg_instance 33565 "display_graph() : Empty instance.", 33566 cimg_instance); 33567 33568 char ntitle[64] = { 0 }; if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type()); 33569 CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0); 33570 return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax); 33571 } 33572 33573 //! Save the image as a file. 33574 /** 33575 The used file format is defined by the file extension in the filename \p filename. 33576 Parameter \p number can be used to add a 6-digit number to the filename before saving. 33577 **/ 33578 const CImg<T>& save(const char *const filename, const int number=-1) const { 33579 if (!filename) 33580 throw CImgArgumentException(_cimg_instance 33581 "save() : Specified filename is (null).", 33582 cimg_instance); 33583 // Do not test for empty instances, since .cimg format is able to manage empty instances. 33584 const char *const ext = cimg::split_filename(filename); 33585 char nfilename[1024] = { 0 }; 33586 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename; 33587 #ifdef cimg_save_plugin 33588 cimg_save_plugin(fn); 33589 #endif 33590 #ifdef cimg_save_plugin1 33591 cimg_save_plugin1(fn); 33592 #endif 33593 #ifdef cimg_save_plugin2 33594 cimg_save_plugin2(fn); 33595 #endif 33596 #ifdef cimg_save_plugin3 33597 cimg_save_plugin3(fn); 33598 #endif 33599 #ifdef cimg_save_plugin4 33600 cimg_save_plugin4(fn); 33601 #endif 33602 #ifdef cimg_save_plugin5 33603 cimg_save_plugin5(fn); 33604 #endif 33605 #ifdef cimg_save_plugin6 33606 cimg_save_plugin6(fn); 33607 #endif 33608 #ifdef cimg_save_plugin7 33609 cimg_save_plugin7(fn); 33610 #endif 33611 #ifdef cimg_save_plugin8 33612 cimg_save_plugin8(fn); 33613 #endif 33614 // ASCII formats 33615 if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn); 33616 else if (!cimg::strcasecmp(ext,"dlm") || 33617 !cimg::strcasecmp(ext,"txt")) return save_dlm(fn); 33618 else if (!cimg::strcasecmp(ext,"cpp") || 33619 !cimg::strcasecmp(ext,"hpp") || 33620 !cimg::strcasecmp(ext,"h") || 33621 !cimg::strcasecmp(ext,"c")) return save_cpp(fn); 33622 33623 // 2d binary formats 33624 else if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn); 33625 else if (!cimg::strcasecmp(ext,"jpg") || 33626 !cimg::strcasecmp(ext,"jpeg") || 33627 !cimg::strcasecmp(ext,"jpe") || 33628 !cimg::strcasecmp(ext,"jfif") || 33629 !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn); 33630 else if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn); 33631 else if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn); 33632 else if (!cimg::strcasecmp(ext,"png")) return save_png(fn); 33633 else if (!cimg::strcasecmp(ext,"pgm") || 33634 !cimg::strcasecmp(ext,"ppm") || 33635 !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn); 33636 else if (!cimg::strcasecmp(ext,"pfm")) return save_pfm(fn); 33637 else if (!cimg::strcasecmp(ext,"exr")) return save_exr(fn); 33638 else if (!cimg::strcasecmp(ext,"tif") || 33639 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); 33640 33641 // 3d binary formats 33642 else if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); 33643 else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false); 33644 else if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn); 33645 else if (!cimg::strcasecmp(ext,"hdr") || 33646 !cimg::strcasecmp(ext,"nii")) return save_analyze(fn); 33647 else if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn); 33648 else if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn); 33649 else if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn); 33650 33651 // Archive files 33652 else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); 33653 33654 // Image sequences 33655 else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true); 33656 else if (!cimg::strcasecmp(ext,"avi") || 33657 !cimg::strcasecmp(ext,"mov") || 33658 !cimg::strcasecmp(ext,"asf") || 33659 !cimg::strcasecmp(ext,"divx") || 33660 !cimg::strcasecmp(ext,"flv") || 33661 !cimg::strcasecmp(ext,"mpg") || 33662 !cimg::strcasecmp(ext,"m1v") || 33663 !cimg::strcasecmp(ext,"m2v") || 33664 !cimg::strcasecmp(ext,"m4v") || 33665 !cimg::strcasecmp(ext,"mjp") || 33666 !cimg::strcasecmp(ext,"mkv") || 33667 !cimg::strcasecmp(ext,"mpe") || 33668 !cimg::strcasecmp(ext,"movie") || 33669 !cimg::strcasecmp(ext,"ogm") || 33670 !cimg::strcasecmp(ext,"qt") || 33671 !cimg::strcasecmp(ext,"rm") || 33672 !cimg::strcasecmp(ext,"vob") || 33673 !cimg::strcasecmp(ext,"wmv") || 33674 !cimg::strcasecmp(ext,"xvid") || 33675 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn); 33676 return save_other(fn); 33677 } 33678 33679 // Save the image as an ASCII file (ASCII Raw + simple header) (internal). 33680 const CImg<T>& _save_ascii(std::FILE *const file, const char *const filename) const { 33681 if (!file && !filename) 33682 throw CImgArgumentException(_cimg_instance 33683 "save_ascii() : Specified filename is (null).", 33684 cimg_instance); 33685 if (is_empty()) 33686 throw CImgInstanceException(_cimg_instance 33687 "save_ascii() : Empty instance, for file '%s'.", 33688 cimg_instance, 33689 filename?filename:"(FILE*)"); 33690 33691 std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); 33692 std::fprintf(nfile,"%u %u %u %u\n",_width,_height,_depth,_spectrum); 33693 const T* ptrs = _data; 33694 cimg_forYZC(*this,y,z,c) { 33695 cimg_forX(*this,x) std::fprintf(nfile,"%g ",(double)*(ptrs++)); 33696 std::fputc('\n',nfile); 33697 } 33698 if (!file) cimg::fclose(nfile); 33699 return *this; 33700 } 33701 33702 //! Save the image as an ASCII file (ASCII Raw + simple header). 33703 const CImg<T>& save_ascii(const char *const filename) const { 33704 return _save_ascii(0,filename); 33705 } 33706 33707 //! Save the image as an ASCII file (ASCII Raw + simple header). 33708 const CImg<T>& save_ascii(std::FILE *const file) const { 33709 return _save_ascii(file,0); 33710 } 33711 33712 // Save the image as a C or CPP source file (internal). 33713 const CImg<T>& _save_cpp(std::FILE *const file, const char *const filename) const { 33714 if (!file && !filename) 33715 throw CImgArgumentException(_cimg_instance 33716 "save_cpp() : Specified filename is (null).", 33717 cimg_instance); 33718 if (is_empty()) 33719 throw CImgInstanceException(_cimg_instance 33720 "save_cpp() : Empty instance, for file '%s'.", 33721 cimg_instance, 33722 filename?filename:"(FILE*)"); 33723 33724 std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); 33725 char varname[1024] = { 0 }; 33726 if (filename) std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname); 33727 if (!*varname) std::sprintf(varname,"unnamed"); 33728 std::fprintf(nfile, 33729 "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n" 33730 "%s data_%s[] = { \n ", 33731 varname,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname); 33732 for (unsigned int off = 0, siz = size()-1; off<=siz; ++off) { 33733 std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off])); 33734 if (off==siz) std::fprintf(nfile," };\n"); 33735 else if (!((off+1)%16)) std::fprintf(nfile,",\n "); 33736 else std::fprintf(nfile,", "); 33737 } 33738 if (!file) cimg::fclose(nfile); 33739 return *this; 33740 } 33741 33742 //! Save the image as a CPP source file. 33743 const CImg<T>& save_cpp(const char *const filename) const { 33744 return _save_cpp(0,filename); 33745 } 33746 33747 //! Save the image as a CPP source file. 33748 const CImg<T>& save_cpp(std::FILE *const file) const { 33749 return _save_cpp(file,0); 33750 } 33751 33752 // Save the image as a DLM file (internal). 33753 const CImg<T>& _save_dlm(std::FILE *const file, const char *const filename) const { 33754 if (!file && !filename) 33755 throw CImgArgumentException(_cimg_instance 33756 "save_dlm() : Specified filename is (null).", 33757 cimg_instance); 33758 if (is_empty()) 33759 throw CImgInstanceException(_cimg_instance 33760 "save_dlm() : Empty instance, for file '%s'.", 33761 cimg_instance, 33762 filename?filename:"(FILE*)"); 33763 if (_depth>1) 33764 cimg::warn(_cimg_instance 33765 "save_dlm() : Instance is volumetric, values along Z will be unrolled in file '%s'.", 33766 cimg_instance, 33767 filename?filename:"(FILE*)"); 33768 33769 if (_spectrum>1) 33770 cimg::warn(_cimg_instance 33771 "save_dlm() : Instance is multispectral, values along C will be unrolled in file '%s'.", 33772 cimg_instance, 33773 filename?filename:"(FILE*)"); 33774 33775 std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); 33776 const T* ptrs = _data; 33777 cimg_forYZC(*this,y,z,c) { 33778 cimg_forX(*this,x) std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==width()-1)?"":","); 33779 std::fputc('\n',nfile); 33780 } 33781 if (!file) cimg::fclose(nfile); 33782 return *this; 33783 } 33784 33785 //! Save the image as a DLM file. 33786 const CImg<T>& save_dlm(const char *const filename) const { 33787 return _save_dlm(0,filename); 33788 } 33789 33790 //! Save the image as a DLM file. 33791 const CImg<T>& save_dlm(std::FILE *const file) const { 33792 return _save_dlm(file,0); 33793 } 33794 33795 // Save the image as a BMP file (internal). 33796 const CImg<T>& _save_bmp(std::FILE *const file, const char *const filename) const { 33797 if (!file && !filename) 33798 throw CImgArgumentException(_cimg_instance 33799 "save_bmp() : Specified filename is (null).", 33800 cimg_instance); 33801 if (is_empty()) 33802 throw CImgInstanceException(_cimg_instance 33803 "save_bmp() : Empty instance, for file '%s'.", 33804 cimg_instance, 33805 filename?filename:"(FILE*)"); 33806 if (_depth>1) 33807 cimg::warn(_cimg_instance 33808 "save_bmp() : Instance is volumetric, only the first slice will be saved in file '%s'.", 33809 cimg_instance, 33810 filename?filename:"(FILE*)"); 33811 33812 if (_spectrum>3) 33813 cimg::warn(_cimg_instance 33814 "save_bmp() : Instance is multispectral, only the three first channels will be saved in file '%s'.", 33815 cimg_instance, 33816 filename?filename:"(FILE*)"); 33817 33818 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 33819 unsigned char header[54] = { 0 }, align_buf[4] = { 0 }; 33820 const unsigned int 33821 align = (4 - (3*_width)%4)%4, 33822 buf_size = (3*_width+align)*height(), 33823 file_size = 54 + buf_size; 33824 header[0] = 'B'; header[1] = 'M'; 33825 header[0x02] = file_size&0xFF; 33826 header[0x03] = (file_size>>8)&0xFF; 33827 header[0x04] = (file_size>>16)&0xFF; 33828 header[0x05] = (file_size>>24)&0xFF; 33829 header[0x0A] = 0x36; 33830 header[0x0E] = 0x28; 33831 header[0x12] = _width&0xFF; 33832 header[0x13] = (_width>>8)&0xFF; 33833 header[0x14] = (_width>>16)&0xFF; 33834 header[0x15] = (_width>>24)&0xFF; 33835 header[0x16] = _height&0xFF; 33836 header[0x17] = (_height>>8)&0xFF; 33837 header[0x18] = (_height>>16)&0xFF; 33838 header[0x19] = (_height>>24)&0xFF; 33839 header[0x1A] = 1; 33840 header[0x1B] = 0; 33841 header[0x1C] = 24; 33842 header[0x1D] = 0; 33843 header[0x22] = buf_size&0xFF; 33844 header[0x23] = (buf_size>>8)&0xFF; 33845 header[0x24] = (buf_size>>16)&0xFF; 33846 header[0x25] = (buf_size>>24)&0xFF; 33847 header[0x27] = 0x1; 33848 header[0x2B] = 0x1; 33849 cimg::fwrite(header,54,nfile); 33850 33851 const T 33852 *ptr_r = data(0,_height-1,0,0), 33853 *ptr_g = (_spectrum>=2)?data(0,_height-1,0,1):0, 33854 *ptr_b = (_spectrum>=3)?data(0,_height-1,0,2):0; 33855 33856 switch (_spectrum) { 33857 case 1 : { 33858 cimg_forY(*this,y) { 33859 cimg_forX(*this,x) { 33860 const unsigned char val = (unsigned char)*(ptr_r++); 33861 std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile); 33862 } 33863 cimg::fwrite(align_buf,align,nfile); 33864 ptr_r-=2*_width; 33865 } 33866 } break; 33867 case 2 : { 33868 cimg_forY(*this,y) { 33869 cimg_forX(*this,x) { 33870 std::fputc(0,nfile); 33871 std::fputc((unsigned char)(*(ptr_g++)),nfile); 33872 std::fputc((unsigned char)(*(ptr_r++)),nfile); 33873 } 33874 cimg::fwrite(align_buf,align,nfile); 33875 ptr_r-=2*_width; ptr_g-=2*_width; 33876 } 33877 } break; 33878 default : { 33879 cimg_forY(*this,y) { 33880 cimg_forX(*this,x) { 33881 std::fputc((unsigned char)(*(ptr_b++)),nfile); 33882 std::fputc((unsigned char)(*(ptr_g++)),nfile); 33883 std::fputc((unsigned char)(*(ptr_r++)),nfile); 33884 } 33885 cimg::fwrite(align_buf,align,nfile); 33886 ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width; 33887 } 33888 } 33889 } 33890 if (!file) cimg::fclose(nfile); 33891 return *this; 33892 } 33893 33894 //! Save the image as a BMP file. 33895 const CImg<T>& save_bmp(const char *const filename) const { 33896 return _save_bmp(0,filename); 33897 } 33898 33899 //! Save the image as a BMP file. 33900 const CImg<T>& save_bmp(std::FILE *const file) const { 33901 return _save_bmp(file,0); 33902 } 33903 33904 // Save a file in JPEG format (internal). 33905 const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const { 33906 if (!file && !filename) 33907 throw CImgArgumentException(_cimg_instance 33908 "save_jpeg() : Specified filename is (null).", 33909 cimg_instance); 33910 if (is_empty()) 33911 throw CImgInstanceException(_cimg_instance 33912 "save_jpeg() : Empty instance, for file '%s'.", 33913 cimg_instance, 33914 filename?filename:"(FILE*)"); 33915 if (_depth>1) 33916 cimg::warn(_cimg_instance 33917 "save_jpeg() : Instance is volumetric, only the first slice will be saved in file '%s'.", 33918 cimg_instance, 33919 filename?filename:"(FILE*)"); 33920 33921 #ifndef cimg_use_jpeg 33922 if (!file) return save_other(filename,quality); 33923 else throw CImgIOException(_cimg_instance 33924 "save_jpeg() : Unable to save data in '(*FILE)' unless libjpeg is enabled.", 33925 cimg_instance); 33926 #else 33927 unsigned int dimbuf = 0; 33928 J_COLOR_SPACE colortype = JCS_RGB; 33929 33930 switch(_spectrum) { 33931 case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break; 33932 case 2 : dimbuf = 3; colortype = JCS_RGB; break; 33933 case 3 : dimbuf = 3; colortype = JCS_RGB; break; 33934 default: dimbuf = 4; colortype = JCS_CMYK; break; 33935 } 33936 33937 // Call libjpeg functions 33938 struct jpeg_compress_struct cinfo; 33939 struct jpeg_error_mgr jerr; 33940 cinfo.err = jpeg_std_error(&jerr); 33941 jpeg_create_compress(&cinfo); 33942 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 33943 jpeg_stdio_dest(&cinfo,nfile); 33944 cinfo.image_width = _width; 33945 cinfo.image_height = _height; 33946 cinfo.input_components = dimbuf; 33947 cinfo.in_color_space = colortype; 33948 jpeg_set_defaults(&cinfo); 33949 jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE); 33950 jpeg_start_compress(&cinfo,TRUE); 33951 33952 JSAMPROW row_pointer[1]; 33953 CImg<ucharT> buffer(_width*dimbuf); 33954 33955 while (cinfo.next_scanline < cinfo.image_height) { 33956 unsigned char *ptrd = buffer._data; 33957 33958 // Fill pixel buffer 33959 switch (_spectrum) { 33960 case 1 : { // Greyscale images 33961 const T *ptr_g = data(0, cinfo.next_scanline); 33962 for(unsigned int b = 0; b < cinfo.image_width; b++) 33963 *(ptrd++) = (unsigned char)*(ptr_g++); 33964 } break; 33965 case 2 : { // RG images 33966 const T *ptr_r = data(0,cinfo.next_scanline,0,0), 33967 *ptr_g = data(0,cinfo.next_scanline,0,1); 33968 for(unsigned int b = 0; b < cinfo.image_width; b++) { 33969 *(ptrd++) = (unsigned char)*(ptr_r++); 33970 *(ptrd++) = (unsigned char)*(ptr_g++); 33971 *(ptrd++) = 0; 33972 } 33973 } break; 33974 case 3 : { // RGB images 33975 const T *ptr_r = data(0,cinfo.next_scanline,0,0), 33976 *ptr_g = data(0,cinfo.next_scanline,0,1), 33977 *ptr_b = data(0,cinfo.next_scanline,0,2); 33978 for(unsigned int b = 0; b < cinfo.image_width; b++) { 33979 *(ptrd++) = (unsigned char)*(ptr_r++); 33980 *(ptrd++) = (unsigned char)*(ptr_g++); 33981 *(ptrd++) = (unsigned char)*(ptr_b++); 33982 } 33983 } break; 33984 default : { // CMYK images 33985 const T *ptr_r = data(0,cinfo.next_scanline,0,0), 33986 *ptr_g = data(0,cinfo.next_scanline,0,1), 33987 *ptr_b = data(0,cinfo.next_scanline,0,2), 33988 *ptr_a = data(0,cinfo.next_scanline,0,3); 33989 for(unsigned int b = 0; b < cinfo.image_width; b++) { 33990 *(ptrd++) = (unsigned char)*(ptr_r++); 33991 *(ptrd++) = (unsigned char)*(ptr_g++); 33992 *(ptrd++) = (unsigned char)*(ptr_b++); 33993 *(ptrd++) = (unsigned char)*(ptr_a++); 33994 } 33995 } 33996 } 33997 row_pointer[0] = buffer._data; 33998 jpeg_write_scanlines(&cinfo,row_pointer,1); 33999 } 34000 jpeg_finish_compress(&cinfo); 34001 if (!file) cimg::fclose(nfile); 34002 jpeg_destroy_compress(&cinfo); 34003 return *this; 34004 #endif 34005 } 34006 34007 //! Save a file in JPEG format. 34008 const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const { 34009 return _save_jpeg(0,filename,quality); 34010 } 34011 34012 //! Save a file in JPEG format. 34013 const CImg<T>& save_jpeg(std::FILE *const file, const unsigned int quality=100) const { 34014 return _save_jpeg(file,0,quality); 34015 } 34016 34017 //! Save the image using built-in ImageMagick++ library. 34018 const CImg<T>& save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const { 34019 if (!filename) 34020 throw CImgArgumentException(_cimg_instance 34021 "save_magick() : Specified filename is (null).", 34022 cimg_instance); 34023 if (is_empty()) 34024 throw CImgInstanceException(_cimg_instance 34025 "save_magick() : Empty instance, for file '%s'.", 34026 cimg_instance, 34027 filename); 34028 34029 unsigned int foo = bytes_per_pixel; foo = 0; 34030 #ifdef cimg_use_magick 34031 double stmin, stmax = (double)max_min(stmin); 34032 if (_depth>1) 34033 cimg::warn(_cimg_instance 34034 "save_magick() : Instance is volumetric, only the first slice will be saved in file '%s'.", 34035 cimg_instance, 34036 filename); 34037 34038 if (_spectrum>3) 34039 cimg::warn(_cimg_instance 34040 "save_magick() : Instance is multispectral, only the three first channels will be saved in file '%s'.", 34041 cimg_instance, 34042 filename); 34043 34044 if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) 34045 cimg::warn(_cimg_instance 34046 "save_magick() : Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", 34047 cimg_instance, 34048 filename,stmin,stmax); 34049 34050 Magick::Image image(Magick::Geometry(_width,_height),"black"); 34051 image.type(Magick::TrueColorType); 34052 image.depth(bytes_per_pixel?(8*bytes_per_pixel):(stmax>=256?16:8)); 34053 const T 34054 *ptr_r = data(0,0,0,0), 34055 *ptr_g = _spectrum>1?data(0,0,0,1):0, 34056 *ptr_b = _spectrum>2?data(0,0,0,2):0; 34057 Magick::PixelPacket *pixels = image.getPixels(0,0,_width,_height); 34058 switch (_spectrum) { 34059 case 1 : // Scalar images 34060 for (unsigned int off = _width*_height; off; --off) { 34061 pixels->red = pixels->green = pixels->blue = (Magick::Quantum)*(ptr_r++); 34062 ++pixels; 34063 } 34064 break; 34065 case 2 : // RG images 34066 for (unsigned int off = _width*_height; off; --off) { 34067 pixels->red = (Magick::Quantum)*(ptr_r++); 34068 pixels->green = (Magick::Quantum)*(ptr_g++); 34069 pixels->blue = 0; ++pixels; 34070 } 34071 break; 34072 default : // RGB images 34073 for (unsigned int off = _width*_height; off; --off) { 34074 pixels->red = (Magick::Quantum)*(ptr_r++); 34075 pixels->green = (Magick::Quantum)*(ptr_g++); 34076 pixels->blue = (Magick::Quantum)*(ptr_b++); 34077 ++pixels; 34078 } 34079 } 34080 image.syncPixels(); 34081 image.write(filename); 34082 #else 34083 throw CImgIOException(_cimg_instance 34084 "save_magick() : Unable to save file '%s' unless libMagick++ is enabled.", 34085 cimg_instance, 34086 filename); 34087 #endif 34088 return *this; 34089 } 34090 34091 // Save an image to a PNG file (internal). 34092 // Most of this function has been written by Eric Fausett 34093 const CImg<T>& _save_png(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const { 34094 if (!filename) 34095 throw CImgArgumentException(_cimg_instance 34096 "save_png() : Specified filename is (null).", 34097 cimg_instance); 34098 if (is_empty()) 34099 throw CImgInstanceException(_cimg_instance 34100 "save_png() : Empty image, for file '%s'.", 34101 cimg_instance, 34102 filename?filename:"(FILE*)"); 34103 34104 unsigned int foo = bytes_per_pixel; foo = 0; 34105 #ifndef cimg_use_png 34106 if (!file) return save_other(filename); 34107 else throw CImgIOException(_cimg_instance 34108 "save_png() : Unable to save data in '(*FILE)' unless libpng is enabled.", 34109 cimg_instance); 34110 #else 34111 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'. 34112 std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb"); 34113 34114 double stmin, stmax = (double)max_min(stmin); 34115 if (_depth>1) 34116 cimg::warn(_cimg_instance 34117 "save_magick() : Instance is volumetric, only the first slice will be saved in file '%s'.", 34118 cimg_instance, 34119 filename); 34120 34121 if (_spectrum>3) 34122 cimg::warn(_cimg_instance 34123 "save_magick() : Instance is multispectral, only the three first channels will be saved in file '%s'.", 34124 cimg_instance, 34125 filename); 34126 34127 if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) 34128 cimg::warn(_cimg_instance 34129 "save_magick() : Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", 34130 cimg_instance, 34131 filename,stmin,stmax); 34132 34133 // Setup PNG structures for write 34134 png_voidp user_error_ptr = 0; 34135 png_error_ptr user_error_fn = 0, user_warning_fn = 0; 34136 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn); 34137 if(!png_ptr){ 34138 if (!file) cimg::fclose(nfile); 34139 throw CImgIOException(_cimg_instance 34140 "save_png() : Failed to initialize 'png_ptr' structure when saving file '%s'.", 34141 cimg_instance, 34142 nfilename?nfilename:"(FILE*)"); 34143 } 34144 png_infop info_ptr = png_create_info_struct(png_ptr); 34145 if (!info_ptr) { 34146 png_destroy_write_struct(&png_ptr,(png_infopp)0); 34147 if (!file) cimg::fclose(nfile); 34148 throw CImgIOException(_cimg_instance 34149 "save_png() : Failed to initialize 'info_ptr' structure when saving file '%s'.", 34150 cimg_instance, 34151 nfilename?nfilename:"(FILE*)"); 34152 } 34153 if (setjmp(png_jmpbuf(png_ptr))) { 34154 png_destroy_write_struct(&png_ptr, &info_ptr); 34155 if (!file) cimg::fclose(nfile); 34156 throw CImgIOException(_cimg_instance 34157 "save_png() : Encountered unknown fatal error in libpng when saving file '%s'.", 34158 cimg_instance, 34159 nfilename?nfilename:"(FILE*)"); 34160 } 34161 png_init_io(png_ptr, nfile); 34162 const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8); 34163 int color_type; 34164 switch (spectrum()) { 34165 case 1 : color_type = PNG_COLOR_TYPE_GRAY; break; 34166 case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; 34167 case 3 : color_type = PNG_COLOR_TYPE_RGB; break; 34168 default : color_type = PNG_COLOR_TYPE_RGB_ALPHA; 34169 } 34170 const int interlace_type = PNG_INTERLACE_NONE; 34171 const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; 34172 const int filter_method = PNG_FILTER_TYPE_DEFAULT; 34173 png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method); 34174 png_write_info(png_ptr,info_ptr); 34175 const int byte_depth = bit_depth>>3; 34176 const int numChan = spectrum()>4?4:spectrum(); 34177 const int pixel_bit_depth_flag = numChan * (bit_depth-1); 34178 34179 // Allocate Memory for Image Save and Fill pixel data 34180 png_bytep *const imgData = new png_byte*[_height]; 34181 for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width]; 34182 const T *pC0 = data(0,0,0,0); 34183 switch (pixel_bit_depth_flag) { 34184 case 7 : { // Gray 8-bit 34185 cimg_forY(*this,y) { 34186 unsigned char *ptrd = imgData[y]; 34187 cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++); 34188 } 34189 } break; 34190 case 14 : { // Gray w/ Alpha 8-bit 34191 const T *pC1 = data(0,0,0,1); 34192 cimg_forY(*this,y) { 34193 unsigned char *ptrd = imgData[y]; 34194 cimg_forX(*this,x) { 34195 *(ptrd++) = (unsigned char)*(pC0++); 34196 *(ptrd++) = (unsigned char)*(pC1++); 34197 } 34198 } 34199 } break; 34200 case 21 : { // RGB 8-bit 34201 const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); 34202 cimg_forY(*this,y) { 34203 unsigned char *ptrd = imgData[y]; 34204 cimg_forX(*this,x) { 34205 *(ptrd++) = (unsigned char)*(pC0++); 34206 *(ptrd++) = (unsigned char)*(pC1++); 34207 *(ptrd++) = (unsigned char)*(pC2++); 34208 } 34209 } 34210 } break; 34211 case 28 : { // RGB x/ Alpha 8-bit 34212 const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); 34213 cimg_forY(*this,y){ 34214 unsigned char *ptrd = imgData[y]; 34215 cimg_forX(*this,x){ 34216 *(ptrd++) = (unsigned char)*(pC0++); 34217 *(ptrd++) = (unsigned char)*(pC1++); 34218 *(ptrd++) = (unsigned char)*(pC2++); 34219 *(ptrd++) = (unsigned char)*(pC3++); 34220 } 34221 } 34222 } break; 34223 case 15 : { // Gray 16-bit 34224 cimg_forY(*this,y){ 34225 unsigned short *ptrd = (unsigned short*)(imgData[y]); 34226 cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++); 34227 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width); 34228 } 34229 } break; 34230 case 30 : { // Gray w/ Alpha 16-bit 34231 const T *pC1 = data(0,0,0,1); 34232 cimg_forY(*this,y){ 34233 unsigned short *ptrd = (unsigned short*)(imgData[y]); 34234 cimg_forX(*this,x) { 34235 *(ptrd++) = (unsigned short)*(pC0++); 34236 *(ptrd++) = (unsigned short)*(pC1++); 34237 } 34238 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width); 34239 } 34240 } break; 34241 case 45 : { // RGB 16-bit 34242 const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); 34243 cimg_forY(*this,y) { 34244 unsigned short *ptrd = (unsigned short*)(imgData[y]); 34245 cimg_forX(*this,x) { 34246 *(ptrd++) = (unsigned short)*(pC0++); 34247 *(ptrd++) = (unsigned short)*(pC1++); 34248 *(ptrd++) = (unsigned short)*(pC2++); 34249 } 34250 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width); 34251 } 34252 } break; 34253 case 60 : { // RGB w/ Alpha 16-bit 34254 const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); 34255 cimg_forY(*this,y) { 34256 unsigned short *ptrd = (unsigned short*)(imgData[y]); 34257 cimg_forX(*this,x) { 34258 *(ptrd++) = (unsigned short)*(pC0++); 34259 *(ptrd++) = (unsigned short)*(pC1++); 34260 *(ptrd++) = (unsigned short)*(pC2++); 34261 *(ptrd++) = (unsigned short)*(pC3++); 34262 } 34263 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width); 34264 } 34265 } break; 34266 default : 34267 if (!file) cimg::fclose(nfile); 34268 throw CImgIOException(_cimg_instance 34269 "save_png() : Encountered unknown fatal error in libpng when saving file '%s'.", 34270 cimg_instance, 34271 nfilename?nfilename:"(FILE*)"); 34272 } 34273 png_write_image(png_ptr,imgData); 34274 png_write_end(png_ptr,info_ptr); 34275 png_destroy_write_struct(&png_ptr, &info_ptr); 34276 34277 // Deallocate Image Write Memory 34278 cimg_forY(*this,n) delete[] imgData[n]; 34279 delete[] imgData; 34280 if (!file) cimg::fclose(nfile); 34281 return *this; 34282 #endif 34283 } 34284 34285 //! Save a file in PNG format 34286 const CImg<T>& save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const { 34287 return _save_png(0,filename,bytes_per_pixel); 34288 } 34289 34290 //! Save a file in PNG format 34291 const CImg<T>& save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { 34292 return _save_png(file,0,bytes_per_pixel); 34293 } 34294 34295 //! Save the image as a PNM file. 34296 const CImg<T>& save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const { 34297 return _save_pnm(0,filename,bytes_per_pixel); 34298 } 34299 34300 //! Save the image as a PNM file. 34301 const CImg<T>& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { 34302 return _save_pnm(file,0,bytes_per_pixel); 34303 } 34304 34305 // Save the image as a PNM file (internal function). 34306 const CImg<T>& _save_pnm(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const { 34307 if (!file && !filename) 34308 throw CImgArgumentException(_cimg_instance 34309 "save_pnm() : Specified filename is (null).", 34310 cimg_instance); 34311 if (is_empty()) 34312 throw CImgInstanceException(_cimg_instance 34313 "save_pnm() : Empty instance, for file '%s'.", 34314 cimg_instance, 34315 filename?filename:"(FILE*)"); 34316 34317 double stmin, stmax = (double)max_min(stmin); 34318 if (_depth>1) 34319 cimg::warn(_cimg_instance 34320 "save_pnm() : Instance is volumetric, only the first slice will be saved in file '%s'.", 34321 cimg_instance, 34322 filename?filename:"(FILE*)"); 34323 34324 if (_spectrum>3) 34325 cimg::warn(_cimg_instance 34326 "save_pnm() : Instance is multispectral, only the three first channels will be saved in file '%s'.", 34327 cimg_instance, 34328 filename?filename:"(FILE*)"); 34329 34330 if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) 34331 cimg::warn(_cimg_instance 34332 "save_pnm() : Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", 34333 cimg_instance, 34334 stmin,stmax,filename?filename:"(FILE*)"); 34335 34336 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 34337 const T 34338 *ptr_r = data(0,0,0,0), 34339 *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, 34340 *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; 34341 const unsigned int buf_size = cimg::min(1024*1024U,_width*_height*(_spectrum==1?1:3)); 34342 34343 std::fprintf(nfile,"P%c\n%u %u\n%u\n", 34344 (_spectrum==1?'5':'6'),_width,_height,stmax<256?255:(stmax<4096?4095:65535)); 34345 34346 switch (_spectrum) { 34347 case 1 : { // Scalar image 34348 if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits 34349 CImg<ucharT> buf(buf_size); 34350 for (int to_write = _width*_height; to_write>0; ) { 34351 const unsigned int N = cimg::min((unsigned int)to_write,buf_size); 34352 unsigned char *ptrd = buf._data; 34353 for (int i = (int)N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++); 34354 cimg::fwrite(buf._data,N,nfile); 34355 to_write-=N; 34356 } 34357 } else { // Binary PGM 16 bits 34358 CImg<ushortT> buf(buf_size); 34359 for (int to_write = _width*_height; to_write>0; ) { 34360 const unsigned int N = cimg::min((unsigned int)to_write,buf_size); 34361 unsigned short *ptrd = buf._data; 34362 for (int i = (int)N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++); 34363 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34364 cimg::fwrite(buf._data,N,nfile); 34365 to_write-=N; 34366 } 34367 } 34368 } break; 34369 case 2 : { // RG image 34370 if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits 34371 CImg<ucharT> buf(buf_size); 34372 for (int to_write = _width*_height; to_write>0; ) { 34373 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34374 unsigned char *ptrd = buf._data; 34375 for (int i = (int)N; i>0; --i) { 34376 *(ptrd++) = (unsigned char)*(ptr_r++); 34377 *(ptrd++) = (unsigned char)*(ptr_g++); 34378 *(ptrd++) = 0; 34379 } 34380 cimg::fwrite(buf._data,3*N,nfile); 34381 to_write-=N; 34382 } 34383 } else { // Binary PPM 16 bits 34384 CImg<ushortT> buf(buf_size); 34385 for (int to_write = _width*_height; to_write>0; ) { 34386 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34387 unsigned short *ptrd = buf._data; 34388 for (int i = (int)N; i>0; --i) { 34389 *(ptrd++) = (unsigned short)*(ptr_r++); 34390 *(ptrd++) = (unsigned short)*(ptr_g++); 34391 *(ptrd++) = 0; 34392 } 34393 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34394 cimg::fwrite(buf._data,3*N,nfile); 34395 to_write-=N; 34396 } 34397 } 34398 } break; 34399 default : { // RGB image 34400 if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits 34401 CImg<ucharT> buf(buf_size); 34402 for (int to_write = _width*_height; to_write>0; ) { 34403 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34404 unsigned char *ptrd = buf._data; 34405 for (int i = (int)N; i>0; --i) { 34406 *(ptrd++) = (unsigned char)*(ptr_r++); 34407 *(ptrd++) = (unsigned char)*(ptr_g++); 34408 *(ptrd++) = (unsigned char)*(ptr_b++); 34409 } 34410 cimg::fwrite(buf._data,3*N,nfile); 34411 to_write-=N; 34412 } 34413 } else { // Binary PPM 16 bits 34414 CImg<ushortT> buf(buf_size); 34415 for (int to_write = _width*_height; to_write>0; ) { 34416 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34417 unsigned short *ptrd = buf._data; 34418 for (int i = (int)N; i>0; --i) { 34419 *(ptrd++) = (unsigned short)*(ptr_r++); 34420 *(ptrd++) = (unsigned short)*(ptr_g++); 34421 *(ptrd++) = (unsigned short)*(ptr_b++); 34422 } 34423 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34424 cimg::fwrite(buf._data,3*N,nfile); 34425 to_write-=N; 34426 } 34427 } 34428 } 34429 } 34430 if (!file) cimg::fclose(nfile); 34431 return *this; 34432 } 34433 34434 //! Save the image as a PFM file. 34435 const CImg<T>& save_pfm(const char *const filename) const { 34436 return _save_pfm(0,filename); 34437 } 34438 34439 //! Save the image as a PFM file. 34440 const CImg<T>& save_pfm(std::FILE *const file) const { 34441 return _save_pfm(file,0); 34442 } 34443 34444 // Save the image as a PFM file (internal function). 34445 const CImg<T>& _save_pfm(std::FILE *const file, const char *const filename) const { 34446 if (!file && !filename) 34447 throw CImgArgumentException(_cimg_instance 34448 "save_pfm() : Specified filename is (null).", 34449 cimg_instance); 34450 if (is_empty()) 34451 throw CImgInstanceException(_cimg_instance 34452 "save_pfm() : Empty instance, for file '%s'.", 34453 cimg_instance, 34454 filename?filename:"(FILE*)"); 34455 if (_depth>1) 34456 cimg::warn(_cimg_instance 34457 "save_pfm() : Instance is volumetric, only the first slice will be saved in file '%s'.", 34458 cimg_instance, 34459 filename?filename:"(FILE*)"); 34460 34461 if (_spectrum>3) 34462 cimg::warn(_cimg_instance 34463 "save_pfm() : Instance image is multispectral, only the three first channels will be saved in file '%s'.", 34464 cimg_instance, 34465 filename?filename:"(FILE*)"); 34466 34467 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 34468 const T 34469 *ptr_r = data(0,0,0,0), 34470 *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, 34471 *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; 34472 const unsigned int buf_size = cimg::min(1024*1024U,_width*_height*(_spectrum==1?1:3)); 34473 34474 std::fprintf(nfile,"P%c\n%u %u\n1.0\n", 34475 (_spectrum==1?'f':'F'),_width,_height); 34476 34477 switch (_spectrum) { 34478 case 1 : { // Scalar image 34479 CImg<floatT> buf(buf_size); 34480 for (int to_write = _width*_height; to_write>0; ) { 34481 const unsigned int N = cimg::min((unsigned int)to_write,buf_size); 34482 float *ptrd = buf._data; 34483 for (int i = (int)N; i>0; --i) *(ptrd++) = (float)*(ptr_r++); 34484 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34485 cimg::fwrite(buf._data,N,nfile); 34486 to_write-=N; 34487 } 34488 } break; 34489 case 2 : { // RG image 34490 CImg<floatT> buf(buf_size); 34491 for (int to_write = _width*_height; to_write>0; ) { 34492 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34493 float *ptrd = buf._data; 34494 for (int i = (int)N; i>0; --i) { 34495 *(ptrd++) = (float)*(ptr_r++); 34496 *(ptrd++) = (float)*(ptr_g++); 34497 *(ptrd++) = 0; 34498 } 34499 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34500 cimg::fwrite(buf._data,3*N,nfile); 34501 to_write-=N; 34502 } 34503 } break; 34504 default : { // RGB image 34505 CImg<floatT> buf(buf_size); 34506 for (int to_write = _width*_height; to_write>0; ) { 34507 const unsigned int N = cimg::min((unsigned int)to_write,buf_size/3); 34508 float *ptrd = buf._data; 34509 for (int i = (int)N; i>0; --i) { 34510 *(ptrd++) = (float)*(ptr_r++); 34511 *(ptrd++) = (float)*(ptr_g++); 34512 *(ptrd++) = (float)*(ptr_b++); 34513 } 34514 if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); 34515 cimg::fwrite(buf._data,3*N,nfile); 34516 to_write-=N; 34517 } 34518 } 34519 } 34520 if (!file) cimg::fclose(nfile); 34521 return *this; 34522 } 34523 34524 // Save the image as a RGB file (internal). 34525 const CImg<T>& _save_rgb(std::FILE *const file, const char *const filename) const { 34526 if (!file && !filename) 34527 throw CImgArgumentException(_cimg_instance 34528 "save_rgb() : Specified filename is (null).", 34529 cimg_instance); 34530 if (is_empty()) 34531 throw CImgInstanceException(_cimg_instance 34532 "save_rgb() : Empty instance, for file '%s'.", 34533 cimg_instance, 34534 filename?filename:"(FILE*)"); 34535 if (_spectrum!=3) 34536 cimg::warn(_cimg_instance 34537 "save_rgb() : Instance image has not exactly 3 channels, for file '%s'.", 34538 cimg_instance, 34539 filename?filename:"(FILE*)"); 34540 34541 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 34542 const unsigned int wh = _width*_height; 34543 unsigned char *const buffer = new unsigned char[3*wh], *nbuffer = buffer; 34544 const T 34545 *ptr1 = data(0,0,0,0), 34546 *ptr2 = _spectrum>1?data(0,0,0,1):0, 34547 *ptr3 = _spectrum>2?data(0,0,0,2):0; 34548 switch (_spectrum) { 34549 case 1 : { // Scalar image 34550 for (unsigned int k = 0; k<wh; ++k) { 34551 const unsigned char val = (unsigned char)*(ptr1++); 34552 *(nbuffer++) = val; 34553 *(nbuffer++) = val; 34554 *(nbuffer++) = val; 34555 } 34556 } break; 34557 case 2 : { // RG image 34558 for (unsigned int k = 0; k<wh; ++k) { 34559 *(nbuffer++) = (unsigned char)(*(ptr1++)); 34560 *(nbuffer++) = (unsigned char)(*(ptr2++)); 34561 *(nbuffer++) = 0; 34562 } 34563 } break; 34564 default : { // RGB image 34565 for (unsigned int k = 0; k<wh; ++k) { 34566 *(nbuffer++) = (unsigned char)(*(ptr1++)); 34567 *(nbuffer++) = (unsigned char)(*(ptr2++)); 34568 *(nbuffer++) = (unsigned char)(*(ptr3++)); 34569 } 34570 } 34571 } 34572 cimg::fwrite(buffer,3*wh,nfile); 34573 if (!file) cimg::fclose(nfile); 34574 delete[] buffer; 34575 return *this; 34576 } 34577 34578 //! Save the image as a RGB file. 34579 const CImg<T>& save_rgb(const char *const filename) const { 34580 return _save_rgb(0,filename); 34581 } 34582 34583 //! Save the image as a RGB file. 34584 const CImg<T>& save_rgb(std::FILE *const file) const { 34585 return _save_rgb(file,0); 34586 } 34587 34588 // Save the image as a RGBA file (internal). 34589 const CImg<T>& _save_rgba(std::FILE *const file, const char *const filename) const { 34590 if (!file && !filename) 34591 throw CImgArgumentException(_cimg_instance 34592 "save_rgba() : Specified filename is (null).", 34593 cimg_instance); 34594 if (is_empty()) 34595 throw CImgInstanceException(_cimg_instance 34596 "save_rgba() : Empty instance, for file '%s'.", 34597 cimg_instance, 34598 filename?filename:"(FILE*)"); 34599 if (_spectrum!=4) 34600 cimg::warn(_cimg_instance 34601 "save_rgba() : Instance image has not exactly 4 channels, for file '%s'.", 34602 cimg_instance, 34603 filename?filename:"(FILE*)"); 34604 34605 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 34606 const unsigned int wh = _width*_height; 34607 unsigned char *const buffer = new unsigned char[4*wh], *nbuffer = buffer; 34608 const T 34609 *ptr1 = data(0,0,0,0), 34610 *ptr2 = _spectrum>1?data(0,0,0,1):0, 34611 *ptr3 = _spectrum>2?data(0,0,0,2):0, 34612 *ptr4 = _spectrum>3?data(0,0,0,3):0; 34613 switch (_spectrum) { 34614 case 1 : { // Scalar images 34615 for (unsigned int k = 0; k<wh; ++k) { 34616 const unsigned char val = (unsigned char)*(ptr1++); 34617 *(nbuffer++) = val; 34618 *(nbuffer++) = val; 34619 *(nbuffer++) = val; 34620 *(nbuffer++) = 255; 34621 } 34622 } break; 34623 case 2 : { // RG images 34624 for (unsigned int k = 0; k<wh; ++k) { 34625 *(nbuffer++) = (unsigned char)(*(ptr1++)); 34626 *(nbuffer++) = (unsigned char)(*(ptr2++)); 34627 *(nbuffer++) = 0; 34628 *(nbuffer++) = 255; 34629 } 34630 } break; 34631 case 3 : { // RGB images 34632 for (unsigned int k = 0; k<wh; ++k) { 34633 *(nbuffer++) = (unsigned char)(*(ptr1++)); 34634 *(nbuffer++) = (unsigned char)(*(ptr2++)); 34635 *(nbuffer++) = (unsigned char)(*(ptr3++)); 34636 *(nbuffer++) = 255; 34637 } 34638 } break; 34639 default : { // RGBA images 34640 for (unsigned int k = 0; k<wh; ++k) { 34641 *(nbuffer++) = (unsigned char)(*(ptr1++)); 34642 *(nbuffer++) = (unsigned char)(*(ptr2++)); 34643 *(nbuffer++) = (unsigned char)(*(ptr3++)); 34644 *(nbuffer++) = (unsigned char)(*(ptr4++)); 34645 } 34646 } 34647 } 34648 cimg::fwrite(buffer,4*wh,nfile); 34649 if (!file) cimg::fclose(nfile); 34650 delete[] buffer; 34651 return *this; 34652 } 34653 34654 //! Save the image as a RGBA file. 34655 const CImg<T>& save_rgba(const char *const filename) const { 34656 return _save_rgba(0,filename); 34657 } 34658 34659 //! Save the image as a RGBA file. 34660 const CImg<T>& save_rgba(std::FILE *const file) const { 34661 return _save_rgba(file,0); 34662 } 34663 34664 // Save a plane into a tiff file 34665 #ifdef cimg_use_tiff 34666 34667 #define _cimg_save_tif(types,typed) \ 34668 if (!std::strcmp(types,pixel_type())) { const typed foo = (typed)0; return _save_tiff(tif,directory,foo); } 34669 34670 template<typename t> 34671 const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const t& pixel_t) const { 34672 if (is_empty() || !tif || pixel_t) return *this; 34673 const char *const filename = TIFFFileName(tif); 34674 uint32 rowsperstrip = (uint32)-1; 34675 uint16 spp = _spectrum, bpp = sizeof(t)*8, photometric, compression = COMPRESSION_NONE; 34676 if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB; 34677 else photometric = PHOTOMETRIC_MINISBLACK; 34678 TIFFSetDirectory(tif,directory); 34679 TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,_width); 34680 TIFFSetField(tif,TIFFTAG_IMAGELENGTH,_height); 34681 TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT); 34682 TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp); 34683 if (cimg::type<t>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3); 34684 else if (cimg::type<t>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1); 34685 else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2); 34686 TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp); 34687 TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); 34688 TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric); 34689 TIFFSetField(tif,TIFFTAG_COMPRESSION,compression); 34690 rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip); 34691 TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip); 34692 TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB); 34693 TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg"); 34694 t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); 34695 if (buf) { 34696 for (unsigned int row = 0; row<_height; row+=rowsperstrip) { 34697 uint32 nrow = (row + rowsperstrip>_height?_height-row:rowsperstrip); 34698 tstrip_t strip = TIFFComputeStrip(tif,row,0); 34699 tsize_t i = 0; 34700 for (unsigned int rr = 0; rr<nrow; ++rr) 34701 for (unsigned int cc = 0; cc<_width; ++cc) 34702 for (unsigned int vv = 0; vv<spp; ++vv) 34703 buf[i++] = (t)(*this)(cc,row + rr,0,vv); 34704 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0) 34705 throw CImgException(_cimg_instance 34706 "save_tiff() : Invalid strip writting when saving file '%s'.", 34707 cimg_instance, 34708 filename?filename:"(FILE*)"); 34709 } 34710 _TIFFfree(buf); 34711 } 34712 TIFFWriteDirectory(tif); 34713 return (*this); 34714 } 34715 34716 const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const { 34717 _cimg_save_tif("bool",unsigned char); 34718 _cimg_save_tif("char",char); 34719 _cimg_save_tif("unsigned char",unsigned char); 34720 _cimg_save_tif("short",short); 34721 _cimg_save_tif("unsigned short",unsigned short); 34722 _cimg_save_tif("int",int); 34723 _cimg_save_tif("unsigned int",unsigned int); 34724 _cimg_save_tif("long",int); 34725 _cimg_save_tif("unsigned long",unsigned int); 34726 _cimg_save_tif("float",float); 34727 _cimg_save_tif("double",float); 34728 const char *const filename = TIFFFileName(tif); 34729 throw CImgException(_cimg_instance 34730 "save_tiff() : Unsupported pixel type '%s' for file '%s'.", 34731 cimg_instance, 34732 pixel_type(),filename?filename:"(FILE*)"); 34733 return *this; 34734 } 34735 #endif 34736 34737 //! Save a file in TIFF format. 34738 const CImg<T>& save_tiff(const char *const filename) const { 34739 if (!filename) 34740 throw CImgArgumentException(_cimg_instance 34741 "save_tiff() : Specified filename is (null).", 34742 cimg_instance); 34743 if (is_empty()) 34744 throw CImgInstanceException(_cimg_instance 34745 "save_tiff() : Empty instance, for file '%s'.", 34746 cimg_instance, 34747 filename); 34748 34749 #ifdef cimg_use_tiff 34750 TIFF *tif = TIFFOpen(filename,"w"); 34751 if (tif) { 34752 cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z); 34753 TIFFClose(tif); 34754 } else throw CImgException(_cimg_instance 34755 "save_tiff() : Failed to open file '%s' for writing.", 34756 cimg_instance, 34757 filename); 34758 #else 34759 return save_other(filename); 34760 #endif 34761 return *this; 34762 } 34763 34764 //! Save the image as an ANALYZE7.5 or NIFTI file. 34765 const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const { 34766 if (!filename) 34767 throw CImgArgumentException(_cimg_instance 34768 "save_analyze() : Specified filename is (null).", 34769 cimg_instance); 34770 if (is_empty()) 34771 throw CImgInstanceException(_cimg_instance 34772 "save_analyze() : Empty instance, for file '%s'.", 34773 cimg_instance, 34774 filename); 34775 34776 std::FILE *file; 34777 char header[348] = { 0 }, hname[1024] = { 0 }, iname[1024] = { 0 }; 34778 const char *const ext = cimg::split_filename(filename); 34779 short datatype=-1; 34780 std::memset(header,0,348); 34781 if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); } 34782 if (!cimg::strncasecmp(ext,"hdr",3)) { 34783 std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+std::strlen(iname)-3,"img"); 34784 } 34785 if (!cimg::strncasecmp(ext,"img",3)) { 34786 std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+std::strlen(iname)-3,"hdr"); 34787 } 34788 if (!cimg::strncasecmp(ext,"nii",3)) { 34789 std::strcpy(hname,filename); iname[0] = 0; 34790 } 34791 int *const iheader = (int*)header; 34792 iheader[0] = 348; 34793 std::strcpy(header+4,"CImg"); 34794 std::strcpy(header+14," "); 34795 ((short*)(header+36))[0] = 4096; 34796 ((char*)(header+38))[0] = 114; 34797 ((short*)(header+40))[0] = 4; 34798 ((short*)(header+40))[1] = _width; 34799 ((short*)(header+40))[2] = _height; 34800 ((short*)(header+40))[3] = _depth; 34801 ((short*)(header+40))[4] = _spectrum; 34802 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; 34803 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; 34804 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; 34805 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4; 34806 if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4; 34807 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8; 34808 if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8; 34809 if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8; 34810 if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8; 34811 if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16; 34812 if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64; 34813 if (datatype<0) 34814 throw CImgIOException(_cimg_instance 34815 "save_analyze() : Unsupported pixel type '%s' for file '%s'.", 34816 cimg_instance, 34817 pixel_type(),filename); 34818 34819 ((short*)(header+70))[0] = datatype; 34820 ((short*)(header+72))[0] = sizeof(T); 34821 ((float*)(header+112))[0] = 1; 34822 ((float*)(header+76))[0] = 0; 34823 if (voxsize) { 34824 ((float*)(header+76))[1] = voxsize[0]; 34825 ((float*)(header+76))[2] = voxsize[1]; 34826 ((float*)(header+76))[3] = voxsize[2]; 34827 } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1; 34828 file = cimg::fopen(hname,"wb"); 34829 cimg::fwrite(header,348,file); 34830 if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } 34831 cimg::fwrite(_data,size(),file); 34832 cimg::fclose(file); 34833 return *this; 34834 } 34835 34836 //! Save the image as a .cimg file. 34837 const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const { 34838 CImgList<T>(*this,true).save_cimg(filename,compress); 34839 return *this; 34840 } 34841 34842 // Save the image as a .cimg file. 34843 const CImg<T>& save_cimg(std::FILE *const file, const bool compress=false) const { 34844 CImgList<T>(*this,true).save_cimg(file,compress); 34845 return *this; 34846 } 34847 34848 //! Insert the image into an existing .cimg file, at specified coordinates. 34849 const CImg<T>& save_cimg(const char *const filename, 34850 const unsigned int n0, 34851 const unsigned int x0, const unsigned int y0, 34852 const unsigned int z0, const unsigned int c0) const { 34853 CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,c0); 34854 return *this; 34855 } 34856 34857 //! Insert the image into an existing .cimg file, at specified coordinates. 34858 const CImg<T>& save_cimg(std::FILE *const file, 34859 const unsigned int n0, 34860 const unsigned int x0, const unsigned int y0, 34861 const unsigned int z0, const unsigned int c0) const { 34862 CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,c0); 34863 return *this; 34864 } 34865 34866 //! Save an empty .cimg file with specified dimensions. 34867 static void save_empty_cimg(const char *const filename, 34868 const unsigned int dx, const unsigned int dy=1, 34869 const unsigned int dz=1, const unsigned int dc=1) { 34870 return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dc); 34871 } 34872 34873 //! Save an empty .cimg file with specified dimensions. 34874 static void save_empty_cimg(std::FILE *const file, 34875 const unsigned int dx, const unsigned int dy=1, 34876 const unsigned int dz=1, const unsigned int dc=1) { 34877 return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dc); 34878 } 34879 34880 // Save the image as an INRIMAGE-4 file (internal). 34881 const CImg<T>& _save_inr(std::FILE *const file, const char *const filename, const float *const voxsize) const { 34882 if (!file && !filename) 34883 throw CImgArgumentException(_cimg_instance 34884 "save_inr() : Specified filename is (null).", 34885 cimg_instance); 34886 if (is_empty()) 34887 throw CImgInstanceException(_cimg_instance 34888 "save_inr() : Empty instance, for file '%s'.", 34889 cimg_instance, 34890 filename?filename:"(FILE*)"); 34891 34892 int inrpixsize=-1; 34893 const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; 34894 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } 34895 if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } 34896 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; } 34897 if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; } 34898 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; } 34899 if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; } 34900 if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; } 34901 if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; } 34902 if (inrpixsize<=0) 34903 throw CImgIOException(_cimg_instance 34904 "save_inr() : Unsupported pixel type '%s' for file '%s'", 34905 cimg_instance, 34906 pixel_type(),filename?filename:"(FILE*)"); 34907 34908 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 34909 char header[257] = { 0 }; 34910 int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",_width,_height,_depth,_spectrum); 34911 if (voxsize) err+=std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]); 34912 err+=std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm"); 34913 std::memset(header+err,'\n',252-err); 34914 std::memcpy(header+252,"##}\n",4); 34915 cimg::fwrite(header,256,nfile); 34916 cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile); 34917 if (!file) cimg::fclose(nfile); 34918 return *this; 34919 } 34920 34921 //! Save the image as an INRIMAGE-4 file. 34922 const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const { 34923 return _save_inr(0,filename,voxsize); 34924 } 34925 34926 //! Save the image as an INRIMAGE-4 file. 34927 const CImg<T>& save_inr(std::FILE *const file, const float *const voxsize=0) const { 34928 return _save_inr(file,0,voxsize); 34929 } 34930 34931 //! Save the image as a EXR file. 34932 const CImg<T>& save_exr(const char *const filename) const { 34933 if (!filename) 34934 throw CImgArgumentException(_cimg_instance 34935 "save_exr() : Specified filename is (null).", 34936 cimg_instance); 34937 if (is_empty()) 34938 throw CImgInstanceException(_cimg_instance 34939 "save_exr() : Empty instance, for file '%s'.", 34940 cimg_instance, 34941 filename); 34942 if (_depth>1) 34943 cimg::warn(_cimg_instance 34944 "save_exr() : Instance is volumetric, only the first slice will be saved in file '%s'.", 34945 cimg_instance, 34946 filename); 34947 34948 #ifndef cimg_use_openexr 34949 return save_other(filename); 34950 #else 34951 Imf::Rgba *const ptrd0 = new Imf::Rgba[_width*_height], *ptrd = ptrd0, rgba; 34952 switch (_spectrum) { 34953 case 1 : { // Grayscale image. 34954 for (const T *ptr_r = data(), *const ptr_e = ptr_r + _width*_height; ptr_r<ptr_e;) { 34955 rgba.r = rgba.g = rgba.b = (half)(*(ptr_r++)); 34956 rgba.a = (half)1; 34957 *(ptrd++) = rgba; 34958 } 34959 } break; 34960 case 2 : { // RG image. 34961 for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *const ptr_e = ptr_r + _width*_height; ptr_r<ptr_e; ) { 34962 rgba.r = (half)(*(ptr_r++)); 34963 rgba.g = (half)(*(ptr_g++)); 34964 rgba.b = (half)0; 34965 rgba.a = (half)1; 34966 *(ptrd++) = rgba; 34967 } 34968 } break; 34969 case 3 : { // RGB image. 34970 for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *const ptr_e = ptr_r + _width*_height; ptr_r<ptr_e;) { 34971 rgba.r = (half)(*(ptr_r++)); 34972 rgba.g = (half)(*(ptr_g++)); 34973 rgba.b = (half)(*(ptr_b++)); 34974 rgba.a = (half)1; 34975 *(ptrd++) = rgba; 34976 } 34977 } break; 34978 default : { // RGBA image. 34979 for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3), 34980 *const ptr_e = ptr_r + _width*_height; ptr_r<ptr_e;) { 34981 rgba.r = (half)(*(ptr_r++)); 34982 rgba.g = (half)(*(ptr_g++)); 34983 rgba.b = (half)(*(ptr_b++)); 34984 rgba.a = (half)(*(ptr_a++)); 34985 *(ptrd++) = rgba; 34986 } 34987 } break; 34988 } 34989 Imf::RgbaOutputFile outFile(filename,_width,_height, 34990 _spectrum==1?Imf::WRITE_Y:_spectrum==2?Imf::WRITE_YA:_spectrum==3?Imf::WRITE_RGB:Imf::WRITE_RGBA); 34991 outFile.setFrameBuffer(ptrd0,1,_width); 34992 outFile.writePixels(_height); 34993 delete[] ptrd0; 34994 return *this; 34995 #endif 34996 } 34997 34998 // Save the image as a PANDORE-5 file (internal). 34999 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const { 35000 unsigned int nbdims = 0; 35001 if (id==2 || id==3 || id==4) { dims[0] = 1; dims[1] = _width; nbdims = 2; } 35002 if (id==5 || id==6 || id==7) { dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; } 35003 if (id==8 || id==9 || id==10) { dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; } 35004 if (id==16 || id==17 || id==18) { dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; } 35005 if (id==19 || id==20 || id==21) { dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; } 35006 if (id==22 || id==23 || id==25) { dims[0] = _spectrum; dims[1] = _width; nbdims = 2; } 35007 if (id==26 || id==27 || id==29) { dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; } 35008 if (id==30 || id==31 || id==33) { dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; } 35009 return nbdims; 35010 } 35011 35012 const CImg<T>& _save_pandore(std::FILE *const file, const char *const filename, const unsigned int colorspace) const { 35013 35014 #define __cimg_save_pandore_case(dtype) \ 35015 dtype *buffer = new dtype[size()]; \ 35016 const T *ptrs = _data; \ 35017 cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \ 35018 buffer-=size(); \ 35019 cimg::fwrite(buffer,size(),nfile); \ 35020 delete[] buffer 35021 35022 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \ 35023 if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \ 35024 unsigned int *iheader = (unsigned int*)(header+12); \ 35025 nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ 35026 cimg::fwrite(header,36,nfile); \ 35027 if (sizeof(unsigned long)==4) { unsigned long ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ 35028 else if (sizeof(unsigned int)==4) { unsigned int ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ 35029 else if (sizeof(unsigned short)==4) { unsigned short ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \ 35030 else throw CImgIOException(_cimg_instance \ 35031 "save_pandore() : Unsupported datatype for file '%s'.",\ 35032 cimg_instance, \ 35033 filename?filename:"(FILE*)"); \ 35034 if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ 35035 __cimg_save_pandore_case(unsigned char); \ 35036 } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ 35037 if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \ 35038 else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \ 35039 else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \ 35040 else throw CImgIOException(_cimg_instance \ 35041 "save_pandore() : Unsupported datatype for file '%s'.",\ 35042 cimg_instance, \ 35043 filename?filename:"(FILE*)"); \ 35044 } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ 35045 if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \ 35046 else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \ 35047 else throw CImgIOException(_cimg_instance \ 35048 "save_pandore() : Unsupported datatype for file '%s'.",\ 35049 cimg_instance, \ 35050 filename?filename:"(FILE*)"); \ 35051 } \ 35052 saved = true; \ 35053 } 35054 35055 if (!file && !filename) 35056 throw CImgArgumentException(_cimg_instance 35057 "save_pandore() : Specified filename is (null).", 35058 cimg_instance); 35059 if (is_empty()) 35060 throw CImgInstanceException(_cimg_instance 35061 "save_pandore() : Empty instance, for file '%s'.", 35062 cimg_instance, 35063 filename?filename:"(FILE*)"); 35064 35065 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 35066 unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, 35067 0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 }; 35068 unsigned int nbdims, dims[5] = { 0 }; 35069 bool saved = false; 35070 _cimg_save_pandore_case(1,1,1,"unsigned char",2); 35071 _cimg_save_pandore_case(1,1,1,"char",3); 35072 _cimg_save_pandore_case(1,1,1,"short",3); 35073 _cimg_save_pandore_case(1,1,1,"unsigned short",3); 35074 _cimg_save_pandore_case(1,1,1,"unsigned int",3); 35075 _cimg_save_pandore_case(1,1,1,"int",3); 35076 _cimg_save_pandore_case(1,1,1,"unsigned long",4); 35077 _cimg_save_pandore_case(1,1,1,"long",3); 35078 _cimg_save_pandore_case(1,1,1,"float",4); 35079 _cimg_save_pandore_case(1,1,1,"double",4); 35080 35081 _cimg_save_pandore_case(0,1,1,"unsigned char",5); 35082 _cimg_save_pandore_case(0,1,1,"char",6); 35083 _cimg_save_pandore_case(0,1,1,"short",6); 35084 _cimg_save_pandore_case(0,1,1,"unsigned short",6); 35085 _cimg_save_pandore_case(0,1,1,"unsigned int",6); 35086 _cimg_save_pandore_case(0,1,1,"int",6); 35087 _cimg_save_pandore_case(0,1,1,"unsigned long",7); 35088 _cimg_save_pandore_case(0,1,1,"long",6); 35089 _cimg_save_pandore_case(0,1,1,"float",7); 35090 _cimg_save_pandore_case(0,1,1,"double",7); 35091 35092 _cimg_save_pandore_case(0,0,1,"unsigned char",8); 35093 _cimg_save_pandore_case(0,0,1,"char",9); 35094 _cimg_save_pandore_case(0,0,1,"short",9); 35095 _cimg_save_pandore_case(0,0,1,"unsigned short",9); 35096 _cimg_save_pandore_case(0,0,1,"unsigned int",9); 35097 _cimg_save_pandore_case(0,0,1,"int",9); 35098 _cimg_save_pandore_case(0,0,1,"unsigned long",10); 35099 _cimg_save_pandore_case(0,0,1,"long",9); 35100 _cimg_save_pandore_case(0,0,1,"float",10); 35101 _cimg_save_pandore_case(0,0,1,"double",10); 35102 35103 _cimg_save_pandore_case(0,1,3,"unsigned char",16); 35104 _cimg_save_pandore_case(0,1,3,"char",17); 35105 _cimg_save_pandore_case(0,1,3,"short",17); 35106 _cimg_save_pandore_case(0,1,3,"unsigned short",17); 35107 _cimg_save_pandore_case(0,1,3,"unsigned int",17); 35108 _cimg_save_pandore_case(0,1,3,"int",17); 35109 _cimg_save_pandore_case(0,1,3,"unsigned long",18); 35110 _cimg_save_pandore_case(0,1,3,"long",17); 35111 _cimg_save_pandore_case(0,1,3,"float",18); 35112 _cimg_save_pandore_case(0,1,3,"double",18); 35113 35114 _cimg_save_pandore_case(0,0,3,"unsigned char",19); 35115 _cimg_save_pandore_case(0,0,3,"char",20); 35116 _cimg_save_pandore_case(0,0,3,"short",20); 35117 _cimg_save_pandore_case(0,0,3,"unsigned short",20); 35118 _cimg_save_pandore_case(0,0,3,"unsigned int",20); 35119 _cimg_save_pandore_case(0,0,3,"int",20); 35120 _cimg_save_pandore_case(0,0,3,"unsigned long",21); 35121 _cimg_save_pandore_case(0,0,3,"long",20); 35122 _cimg_save_pandore_case(0,0,3,"float",21); 35123 _cimg_save_pandore_case(0,0,3,"double",21); 35124 35125 _cimg_save_pandore_case(1,1,0,"unsigned char",22); 35126 _cimg_save_pandore_case(1,1,0,"char",23); 35127 _cimg_save_pandore_case(1,1,0,"short",23); 35128 _cimg_save_pandore_case(1,1,0,"unsigned short",23); 35129 _cimg_save_pandore_case(1,1,0,"unsigned int",23); 35130 _cimg_save_pandore_case(1,1,0,"int",23); 35131 _cimg_save_pandore_case(1,1,0,"unsigned long",25); 35132 _cimg_save_pandore_case(1,1,0,"long",23); 35133 _cimg_save_pandore_case(1,1,0,"float",25); 35134 _cimg_save_pandore_case(1,1,0,"double",25); 35135 35136 _cimg_save_pandore_case(0,1,0,"unsigned char",26); 35137 _cimg_save_pandore_case(0,1,0,"char",27); 35138 _cimg_save_pandore_case(0,1,0,"short",27); 35139 _cimg_save_pandore_case(0,1,0,"unsigned short",27); 35140 _cimg_save_pandore_case(0,1,0,"unsigned int",27); 35141 _cimg_save_pandore_case(0,1,0,"int",27); 35142 _cimg_save_pandore_case(0,1,0,"unsigned long",29); 35143 _cimg_save_pandore_case(0,1,0,"long",27); 35144 _cimg_save_pandore_case(0,1,0,"float",29); 35145 _cimg_save_pandore_case(0,1,0,"double",29); 35146 35147 _cimg_save_pandore_case(0,0,0,"unsigned char",30); 35148 _cimg_save_pandore_case(0,0,0,"char",31); 35149 _cimg_save_pandore_case(0,0,0,"short",31); 35150 _cimg_save_pandore_case(0,0,0,"unsigned short",31); 35151 _cimg_save_pandore_case(0,0,0,"unsigned int",31); 35152 _cimg_save_pandore_case(0,0,0,"int",31); 35153 _cimg_save_pandore_case(0,0,0,"unsigned long",33); 35154 _cimg_save_pandore_case(0,0,0,"long",31); 35155 _cimg_save_pandore_case(0,0,0,"float",33); 35156 _cimg_save_pandore_case(0,0,0,"double",33); 35157 35158 if (!file) cimg::fclose(nfile); 35159 return *this; 35160 } 35161 35162 //! Save the image as a PANDORE-5 file. 35163 const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const { 35164 return _save_pandore(0,filename,colorspace); 35165 } 35166 35167 //! Save the image as a PANDORE-5 file. 35168 const CImg<T>& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const { 35169 return _save_pandore(file,0,colorspace); 35170 } 35171 35172 // Save the image as a RAW file (internal). 35173 const CImg<T>& _save_raw(std::FILE *const file, const char *const filename, const bool multiplexed) const { 35174 if (!file && !filename) 35175 throw CImgArgumentException(_cimg_instance 35176 "save_raw() : Specified filename is (null).", 35177 cimg_instance); 35178 if (is_empty()) 35179 throw CImgInstanceException(_cimg_instance 35180 "save_raw() : empty instance, for file '%s'.", 35181 cimg_instance, 35182 filename?filename:"(FILE*)"); 35183 35184 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 35185 if (!multiplexed) cimg::fwrite(_data,size(),nfile); 35186 else { 35187 CImg<T> buf(_spectrum); 35188 cimg_forXYZ(*this,x,y,z) { 35189 cimg_forC(*this,c) buf[c] = (*this)(x,y,z,c); 35190 cimg::fwrite(buf._data,_spectrum,nfile); 35191 } 35192 } 35193 if (!file) cimg::fclose(nfile); 35194 return *this; 35195 } 35196 35197 //! Save the image as a RAW file. 35198 const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const { 35199 return _save_raw(0,filename,multiplexed); 35200 } 35201 35202 //! Save the image as a RAW file. 35203 const CImg<T>& save_raw(std::FILE *const file, const bool multiplexed=false) const { 35204 return _save_raw(file,0,multiplexed); 35205 } 35206 35207 //! Save the image as a video sequence file, using FFMPEG library. 35208 const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 35209 const unsigned int fps=25) const { 35210 if (!filename) 35211 throw CImgArgumentException(_cimg_instance 35212 "save_ffmpeg() : Specified filename is (null).", 35213 cimg_instance); 35214 if (is_empty()) 35215 throw CImgInstanceException(_cimg_instance 35216 "save_ffmpeg() : Empty instance, for file '%s'.", 35217 cimg_instance, 35218 filename); 35219 if (!fps) 35220 throw CImgArgumentException(_cimg_instance 35221 "save_ffmpeg() : Invalid specified framerate 0, for file '%s'.", 35222 cimg_instance, 35223 filename); 35224 35225 #ifndef cimg_use_ffmpeg 35226 return save_ffmpeg_external(filename,first_frame,last_frame); 35227 #else 35228 get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps); 35229 #endif 35230 return *this; 35231 } 35232 35233 //! Save the image as a YUV video sequence file. 35234 const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const { 35235 get_split('z').save_yuv(filename,rgb2yuv); 35236 return *this; 35237 } 35238 35239 //! Save the image as a YUV video sequence file. 35240 const CImg<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const { 35241 get_split('z').save_yuv(file,rgb2yuv); 35242 return *this; 35243 } 35244 35245 // Save OFF files (internal). 35246 template<typename tf, typename tc> 35247 const CImg<T>& _save_off(std::FILE *const file, const char *const filename, 35248 const CImgList<tf>& primitives, const CImgList<tc>& colors) const { 35249 if (!file && !filename) 35250 throw CImgArgumentException(_cimg_instance 35251 "save_off() : Specified filename is (null).", 35252 cimg_instance); 35253 if (is_empty()) 35254 throw CImgInstanceException(_cimg_instance 35255 "save_off() : Empty instance, for file '%s'.", 35256 cimg_instance, 35257 filename?filename:"(FILE*)"); 35258 35259 CImgList<T> opacities; 35260 char error_message[1024] = { 0 }; 35261 if (!is_object3d(primitives,colors,opacities,true,error_message)) 35262 throw CImgInstanceException(_cimg_instance 35263 "save_off() : Invalid specified 3d object, for file '%s' (%s).", 35264 cimg_instance, 35265 filename?filename:"(FILE*)",error_message); 35266 35267 const CImg<tc> default_color(1,3,1,1,200); 35268 std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); 35269 unsigned int supported_primitives = 0; 35270 cimglist_for(primitives,l) if (primitives[l].size()!=5) ++supported_primitives; 35271 std::fprintf(nfile,"OFF\n%u %u %u\n",_width,supported_primitives,3*primitives._width); 35272 cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2))); 35273 cimglist_for(primitives,l) { 35274 const CImg<tc>& color = l<colors.width()?colors[l]:default_color; 35275 const unsigned int psiz = primitives[l].size(), csiz = color.size(); 35276 const float r = color[0]/255.0f, g = (csiz>1?color[1]:r)/255.0f, b = (csiz>2?color[2]:g)/255.0f; 35277 switch (psiz) { 35278 case 1 : std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b); break; 35279 case 2 : std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; 35280 case 3 : std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2), 35281 (unsigned int)primitives(l,1),r,g,b); break; 35282 case 4 : std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3), 35283 (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break; 35284 case 6 : { 35285 const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3); 35286 const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; 35287 std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),rt,gt,bt); 35288 } break; 35289 case 9 : { 35290 const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4); 35291 const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; 35292 std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2), 35293 (unsigned int)primitives(l,1),rt,gt,bt); 35294 } break; 35295 case 12 : { 35296 const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5); 35297 const float rt = color.atXY(xt,yt,0)/255.0f, gt = (csiz>1?color.atXY(xt,yt,1):r)/255.0f, bt = (csiz>2?color.atXY(xt,yt,2):g)/255.0f; 35298 std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3), 35299 (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),rt,gt,bt); 35300 } break; 35301 } 35302 } 35303 if (!file) cimg::fclose(nfile); 35304 return *this; 35305 } 35306 35307 //! Save OFF files. 35308 template<typename tf, typename tc> 35309 const CImg<T>& save_off(const char *const filename, 35310 const CImgList<tf>& primitives, const CImgList<tc>& colors) const { 35311 return _save_off(0,filename,primitives,colors); 35312 } 35313 35314 //! Save OFF files. 35315 template<typename tf, typename tc> 35316 const CImg<T>& save_off(std::FILE *const file, 35317 const CImgList<tf>& primitives, const CImgList<tc>& colors) const { 35318 return _save_off(file,0,primitives,colors); 35319 } 35320 35321 //! Save the image as a video sequence file, using the external tool 'ffmpeg'. 35322 const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 35323 const char *const codec="mpeg2video") const { 35324 if (!filename) 35325 throw CImgArgumentException(_cimg_instance 35326 "save_ffmpeg_external() : Specified filename is (null).", 35327 cimg_instance); 35328 if (is_empty()) 35329 throw CImgInstanceException(_cimg_instance 35330 "save_ffmpeg_external() : Empty instance, for file '%s'.", 35331 cimg_instance, 35332 filename); 35333 35334 get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec); 35335 return *this; 35336 } 35337 35338 //! Save the image using GraphicsMagick's gm. 35339 /** Function that saves the image for other file formats that are not natively handled by CImg, 35340 using the tool 'gm' from the GraphicsMagick package.\n 35341 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install 35342 the GraphicsMagick package in order to get 35343 this function working properly (see http://www.graphicsmagick.org ). 35344 **/ 35345 const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const { 35346 if (!filename) 35347 throw CImgArgumentException(_cimg_instance 35348 "save_graphicsmagick_external() : Specified filename is (null).", 35349 cimg_instance); 35350 if (is_empty()) 35351 throw CImgInstanceException(_cimg_instance 35352 "save_graphicsmagick_external() : Empty instance, for file '%s'.", 35353 cimg_instance, 35354 filename); 35355 35356 char command[1024] = { 0 }, filetmp[512] = { 0 }; 35357 std::FILE *file; 35358 do { 35359 std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),_spectrum==1?"pgm":"ppm"); 35360 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 35361 } while (file); 35362 save_pnm(filetmp); 35363 std::sprintf(command,"%s -quality %u%% \"%s\" \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename); 35364 cimg::system(command); 35365 file = std::fopen(filename,"rb"); 35366 if (!file) 35367 throw CImgIOException(_cimg_instance 35368 "save_graphicsmagick_external() : Failed to save file '%s' with external command 'gm'.", 35369 cimg_instance, 35370 filename); 35371 35372 if (file) cimg::fclose(file); 35373 std::remove(filetmp); 35374 return *this; 35375 } 35376 35377 //! Save an image as a gzipped file, using external tool 'gzip'. 35378 const CImg<T>& save_gzip_external(const char *const filename) const { 35379 if (!filename) 35380 throw CImgArgumentException(_cimg_instance 35381 "save_gzip_external() : Specified filename is (null).", 35382 cimg_instance); 35383 if (is_empty()) 35384 throw CImgInstanceException(_cimg_instance 35385 "save_gzip_external() : Empty instance, for file '%s'.", 35386 cimg_instance, 35387 filename); 35388 35389 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 35390 const char 35391 *ext = cimg::split_filename(filename,body), 35392 *ext2 = cimg::split_filename(body,0); 35393 std::FILE *file; 35394 do { 35395 if (!cimg::strcasecmp(ext,"gz")) { 35396 if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); 35397 else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 35398 } else { 35399 if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); 35400 else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 35401 } 35402 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 35403 } while (file); 35404 save(filetmp); 35405 std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename); 35406 cimg::system(command); 35407 file = std::fopen(filename,"rb"); 35408 if (!file) 35409 throw CImgIOException(_cimg_instance 35410 "save_gzip_external() : Failed to save file '%s' with external command 'gzip'.", 35411 cimg_instance, 35412 filename); 35413 35414 else cimg::fclose(file); 35415 std::remove(filetmp); 35416 return *this; 35417 } 35418 35419 //! Save the image using ImageMagick's convert. 35420 /** Function that saves the image for other file formats that are not natively handled by CImg, 35421 using the tool 'convert' from the ImageMagick package.\n 35422 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install 35423 the ImageMagick package in order to get 35424 this function working properly (see http://www.imagemagick.org ). 35425 **/ 35426 const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const { 35427 if (!filename) 35428 throw CImgArgumentException(_cimg_instance 35429 "save_imagemagick_external() : Specified filename is (null).", 35430 cimg_instance); 35431 if (is_empty()) 35432 throw CImgInstanceException(_cimg_instance 35433 "save_imagemagick_external() : Empty instance, for file '%s'.", 35434 cimg_instance, 35435 filename); 35436 35437 char command[1024] = { 0 }, filetmp[512] = { 0 }; 35438 std::FILE *file; 35439 do { 35440 std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),_spectrum==1?"pgm":"ppm"); 35441 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 35442 } while (file); 35443 save_pnm(filetmp); 35444 std::sprintf(command,"%s -quality %u%% \"%s\" \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename); 35445 cimg::system(command); 35446 file = std::fopen(filename,"rb"); 35447 if (!file) 35448 throw CImgIOException(_cimg_instance 35449 "save_imagemagick_external() : Failed to save file '%s' with external command 'convert'.", 35450 cimg_instance, 35451 filename); 35452 35453 if (file) cimg::fclose(file); 35454 std::remove(filetmp); 35455 return *this; 35456 } 35457 35458 //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net ) 35459 const CImg<T>& save_medcon_external(const char *const filename) const { 35460 if (!filename) 35461 throw CImgArgumentException(_cimg_instance 35462 "save_medcon_external() : Specified filename is (null).", 35463 cimg_instance); 35464 if (is_empty()) 35465 throw CImgInstanceException(_cimg_instance 35466 "save_medcon_external() : Empty instance, for file '%s'.", 35467 cimg_instance, 35468 filename); 35469 35470 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 35471 std::FILE *file; 35472 do { 35473 std::sprintf(filetmp,"%s.hdr",cimg::filenamerand()); 35474 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 35475 } while (file); 35476 save_analyze(filetmp); 35477 std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp); 35478 cimg::system(command); 35479 std::remove(filetmp); 35480 cimg::split_filename(filetmp,body); 35481 std::sprintf(filetmp,"%s.img",body); 35482 std::remove(filetmp); 35483 std::sprintf(command,"m000-%s",filename); 35484 file = std::fopen(command,"rb"); 35485 if (!file) { 35486 cimg::fclose(cimg::fopen(filename,"r")); 35487 throw CImgIOException(_cimg_instance 35488 "save_medcon_external() : Failed to save file '%s' with external command 'medcon'.", 35489 cimg_instance, 35490 filename); 35491 35492 } else cimg::fclose(file); 35493 std::rename(command,filename); 35494 return *this; 35495 } 35496 35497 // Try to save the image if other extension is provided. 35498 const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const { 35499 if (!filename) 35500 throw CImgArgumentException(_cimg_instance 35501 "save_other() : Specified filename is (null).", 35502 cimg_instance); 35503 if (is_empty()) 35504 throw CImgInstanceException(_cimg_instance 35505 "save_other() : Empty instance, for file '%s'.", 35506 cimg_instance, 35507 filename); 35508 35509 const unsigned int omode = cimg::exception_mode(); 35510 bool is_saved = true; 35511 cimg::exception_mode() = 0; 35512 try { save_magick(filename); } 35513 catch (CImgException&) { 35514 try { save_imagemagick_external(filename,quality); } 35515 catch (CImgException&) { 35516 try { save_graphicsmagick_external(filename,quality); } 35517 catch (CImgException&) { 35518 is_saved = false; 35519 } 35520 } 35521 } 35522 cimg::exception_mode() = omode; 35523 if (!is_saved) 35524 throw CImgIOException(_cimg_instance 35525 "save_other() : Failed to save file '%s'. Format is not natively supported, and no external commands succeeded.", 35526 cimg_instance, 35527 filename); 35528 return *this; 35529 } 35530 35531 // Get a 40x38 color logo of a 'danger' item (internal). 35532 static CImg<T> logo40x38() { 35533 static bool first_time = true; 35534 static CImg<T> res(40,38,1,3); 35535 if (first_time) { 35536 const unsigned char *ptrs = cimg::logo40x38; 35537 T *ptr1 = res.data(0,0,0,0), *ptr2 = res.data(0,0,0,1), *ptr3 = res.data(0,0,0,2); 35538 for (unsigned int off = 0; off<res._width*res._height;) { 35539 const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++); 35540 for (unsigned int l = 0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; } 35541 } 35542 first_time = false; 35543 } 35544 return res; 35545 } 35546 35547 //@} 35548 }; 35549 35550 /* 35551 #----------------------------------------- 35552 # 35553 # 35554 # 35555 # Definition of the CImgList<T> structure 35556 # 35557 # 35558 # 35559 #------------------------------------------ 35560 */ 35561 35562 //! Class representing list of images CImg<T>. 35563 template<typename T> 35564 struct CImgList { 35565 35566 //! Size of the list (number of images). 35567 unsigned int _width; 35568 35569 //! Allocation size of the list. 35570 unsigned int _allocated_width; 35571 35572 //! Pointer to the first list element. 35573 CImg<T> *_data; 35574 35575 //! Define a CImgList<T>::iterator. 35576 typedef CImg<T>* iterator; 35577 35578 //! Define a CImgList<T>::const_iterator. 35579 typedef const CImg<T>* const_iterator; 35580 35581 //! Value type. 35582 typedef T value_type; 35583 35584 // Define common T-dependant types. 35585 typedef typename cimg::superset<T,bool>::type Tbool; 35586 typedef typename cimg::superset<T,unsigned char>::type Tuchar; 35587 typedef typename cimg::superset<T,char>::type Tchar; 35588 typedef typename cimg::superset<T,unsigned short>::type Tushort; 35589 typedef typename cimg::superset<T,short>::type Tshort; 35590 typedef typename cimg::superset<T,unsigned int>::type Tuint; 35591 typedef typename cimg::superset<T,int>::type Tint; 35592 typedef typename cimg::superset<T,unsigned long>::type Tulong; 35593 typedef typename cimg::superset<T,long>::type Tlong; 35594 typedef typename cimg::superset<T,float>::type Tfloat; 35595 typedef typename cimg::superset<T,double>::type Tdouble; 35596 typedef typename cimg::last<T,bool>::type boolT; 35597 typedef typename cimg::last<T,unsigned char>::type ucharT; 35598 typedef typename cimg::last<T,char>::type charT; 35599 typedef typename cimg::last<T,unsigned short>::type ushortT; 35600 typedef typename cimg::last<T,short>::type shortT; 35601 typedef typename cimg::last<T,unsigned int>::type uintT; 35602 typedef typename cimg::last<T,int>::type intT; 35603 typedef typename cimg::last<T,unsigned long>::type ulongT; 35604 typedef typename cimg::last<T,long>::type longT; 35605 typedef typename cimg::last<T,float>::type floatT; 35606 typedef typename cimg::last<T,double>::type doubleT; 35607 35608 //@} 35609 //--------------------------- 35610 // 35611 //! \name Plugins 35612 //@{ 35613 //--------------------------- 35614 #ifdef cimglist_plugin 35615 #include cimglist_plugin 35616 #endif 35617 #ifdef cimglist_plugin1 35618 #include cimglist_plugin1 35619 #endif 35620 #ifdef cimglist_plugin2 35621 #include cimglist_plugin2 35622 #endif 35623 #ifdef cimglist_plugin3 35624 #include cimglist_plugin3 35625 #endif 35626 #ifdef cimglist_plugin4 35627 #include cimglist_plugin4 35628 #endif 35629 #ifdef cimglist_plugin5 35630 #include cimglist_plugin5 35631 #endif 35632 #ifdef cimglist_plugin6 35633 #include cimglist_plugin6 35634 #endif 35635 #ifdef cimglist_plugin7 35636 #include cimglist_plugin7 35637 #endif 35638 #ifdef cimglist_plugin8 35639 #include cimglist_plugin8 35640 #endif 35641 35642 //@} 35643 //-------------------------------------------------------- 35644 // 35645 //! \name Constructors / Destructor / Instance Management 35646 //@{ 35647 //-------------------------------------------------------- 35648 35649 //! Destructor. 35650 ~CImgList() { 35651 if (_data) delete[] _data; 35652 } 35653 35654 //! Default constructor. 35655 CImgList(): 35656 _width(0),_allocated_width(0),_data(0) {} 35657 35658 //! Construct an image list containing n empty images. 35659 explicit CImgList(const unsigned int n):_width(n) { 35660 if (n) _data = new CImg<T>[_allocated_width = cimg::max(16UL,cimg::nearest_pow2(n))]; 35661 else { _allocated_width = 0; _data = 0; } 35662 } 35663 35664 //! Construct an image list containing n images with specified size. 35665 CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1, 35666 const unsigned int depth=1, const unsigned int spectrum=1): 35667 _width(0),_allocated_width(0),_data(0) { 35668 assign(n); 35669 cimglist_apply(*this,assign)(width,height,depth,spectrum); 35670 } 35671 35672 //! Construct an image list containing n images with specified size, filled with specified value. 35673 CImgList(const unsigned int n, const unsigned int width, const unsigned int height, 35674 const unsigned int depth, const unsigned int spectrum, const T val): 35675 _width(0),_allocated_width(0),_data(0) { 35676 assign(n); 35677 cimglist_apply(*this,assign)(width,height,depth,spectrum,val); 35678 } 35679 35680 //! Construct an image list containing n images with specified size and specified pixel values (int version). 35681 CImgList(const unsigned int n, const unsigned int width, const unsigned int height, 35682 const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...): 35683 _width(0),_allocated_width(0),_data(0) { 35684 #define _CImgList_stdarg(t) { \ 35685 assign(n,width,height,depth,spectrum); \ 35686 const unsigned int siz = width*height*depth*spectrum, nsiz = siz*n; \ 35687 T *ptrd = _data->_data; \ 35688 va_list ap; \ 35689 va_start(ap,val1); \ 35690 for (unsigned int l = 0, s = 0, i = 0; i<nsiz; ++i) { \ 35691 *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \ 35692 if ((++s)==siz) { ptrd = _data[++l]._data; s = 0; } \ 35693 } \ 35694 va_end(ap); \ 35695 } 35696 _CImgList_stdarg(int); 35697 } 35698 35699 //! Construct an image list containing n images with specified size and specified pixel values (double version). 35700 CImgList(const unsigned int n, const unsigned int width, const unsigned int height, 35701 const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...): 35702 _width(0),_allocated_width(0),_data(0) { 35703 _CImgList_stdarg(double); 35704 } 35705 35706 //! Construct a list containing n copies of the image img. 35707 template<typename t> 35708 CImgList(const unsigned int n, const CImg<t>& img, const bool shared=false): 35709 _width(0),_allocated_width(0),_data(0) { 35710 assign(n); 35711 cimglist_apply(*this,assign)(img,shared); 35712 } 35713 35714 //! Construct an image list from one image. 35715 template<typename t> 35716 explicit CImgList(const CImg<t>& img, const bool shared=false): 35717 _width(0),_allocated_width(0),_data(0) { 35718 assign(1); 35719 _data[0].assign(img,shared); 35720 } 35721 35722 //! Construct an image list from two images. 35723 template<typename t1, typename t2> 35724 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false): 35725 _width(0),_allocated_width(0),_data(0) { 35726 assign(2); 35727 _data[0].assign(img1,shared); _data[1].assign(img2,shared); 35728 } 35729 35730 //! Construct an image list from three images. 35731 template<typename t1, typename t2, typename t3> 35732 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false): 35733 _width(0),_allocated_width(0),_data(0) { 35734 assign(3); 35735 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); 35736 } 35737 35738 //! Construct an image list from four images. 35739 template<typename t1, typename t2, typename t3, typename t4> 35740 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared=false): 35741 _width(0),_allocated_width(0),_data(0) { 35742 assign(4); 35743 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35744 } 35745 35746 //! Construct an image list from five images. 35747 template<typename t1, typename t2, typename t3, typename t4, typename t5> 35748 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35749 const CImg<t5>& img5, const bool shared=false): 35750 _width(0),_allocated_width(0),_data(0) { 35751 assign(5); 35752 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35753 _data[4].assign(img5,shared); 35754 } 35755 35756 //! Construct an image list from six images. 35757 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6> 35758 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35759 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false): 35760 _width(0),_allocated_width(0),_data(0) { 35761 assign(6); 35762 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35763 _data[4].assign(img5,shared); _data[5].assign(img6,shared); 35764 } 35765 35766 //! Construct an image list from seven images. 35767 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7> 35768 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35769 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false): 35770 _width(0),_allocated_width(0),_data(0) { 35771 assign(7); 35772 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35773 _data[4].assign(img5,shared); _data[5].assign(img6,shared); _data[6].assign(img7,shared); 35774 } 35775 35776 //! Construct an image list from eight images. 35777 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8> 35778 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35779 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false): 35780 _width(0),_allocated_width(0),_data(0) { 35781 assign(8); 35782 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35783 _data[4].assign(img5,shared); _data[5].assign(img6,shared); _data[6].assign(img7,shared); _data[7].assign(img8,shared); 35784 } 35785 35786 //! Default copy constructor. 35787 template<typename t> 35788 CImgList(const CImgList<t>& list):_width(0),_allocated_width(0),_data(0) { 35789 assign(list._width); 35790 cimglist_for(*this,l) _data[l].assign(list[l],false); 35791 } 35792 35793 CImgList(const CImgList<T>& list):_width(0),_allocated_width(0),_data(0) { 35794 assign(list._width); 35795 cimglist_for(*this,l) _data[l].assign(list[l],list[l]._is_shared); 35796 } 35797 35798 //! Advanced copy constructor. 35799 template<typename t> 35800 CImgList(const CImgList<t>& list, const bool shared):_width(0),_allocated_width(0),_data(0) { 35801 assign(list._width); 35802 cimglist_for(*this,l) _data[l].assign(list[l],shared); 35803 } 35804 35805 //! Construct an image list from a filename. 35806 explicit CImgList(const char *const filename):_width(0),_allocated_width(0),_data(0) { 35807 assign(filename); 35808 } 35809 35810 //! Construct an image list from a display. 35811 explicit CImgList(const CImgDisplay &disp):_width(0),_allocated_width(0),_data(0) { 35812 assign(disp); 35813 } 35814 35815 //! Return a shared instance of the list. 35816 CImgList<T> get_shared() { 35817 CImgList<T> res(_width); 35818 cimglist_for(*this,l) res[l].assign(_data[l],true); 35819 return res; 35820 } 35821 35822 //! Return a shared instance of the list. 35823 const CImgList<T> get_shared() const { 35824 CImgList<T> res(_width); 35825 cimglist_for(*this,l) res[l].assign(_data[l],true); 35826 return res; 35827 } 35828 35829 //! In-place version of the default constructor. 35830 /** 35831 This function is strictly equivalent to \ref assign() and has been 35832 introduced for having a STL-compliant function name. 35833 **/ 35834 CImgList<T>& clear() { 35835 return assign(); 35836 } 35837 35838 //! In-place version of the default constructor and default destructor. 35839 CImgList<T>& assign() { 35840 if (_data) delete[] _data; 35841 _width = _allocated_width = 0; 35842 _data = 0; 35843 return *this; 35844 } 35845 35846 //! In-place version of the corresponding constructor. 35847 CImgList<T>& assign(const unsigned int n) { 35848 if (n) { 35849 if (_allocated_width<n || _allocated_width>(n<<2)) { 35850 if (_data) delete[] _data; 35851 _data = new CImg<T>[_allocated_width=cimg::max(16UL,cimg::nearest_pow2(n))]; 35852 } 35853 _width = n; 35854 } else assign(); 35855 return *this; 35856 } 35857 35858 //! In-place version of the corresponding constructor. 35859 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1, 35860 const unsigned int depth=1, const unsigned int spectrum=1) { 35861 assign(n); 35862 cimglist_apply(*this,assign)(width,height,depth,spectrum); 35863 return *this; 35864 } 35865 35866 //! In-place version of the corresponding constructor. 35867 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height, 35868 const unsigned int depth, const unsigned int spectrum, const T val) { 35869 assign(n); 35870 cimglist_apply(*this,assign)(width,height,depth,spectrum,val); 35871 return *this; 35872 } 35873 35874 //! In-place version of the corresponding constructor. 35875 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height, 35876 const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...) { 35877 _CImgList_stdarg(int); 35878 return *this; 35879 } 35880 35881 //! In-place version of the corresponding constructor. 35882 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height, 35883 const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...) { 35884 _CImgList_stdarg(double); 35885 return *this; 35886 } 35887 35888 //! In-place version of the copy constructor. 35889 template<typename t> 35890 CImgList<T>& assign(const CImgList<t>& list, const bool shared=false) { 35891 assign(list._width); 35892 cimglist_for(*this,l) _data[l].assign(list[l],shared); 35893 return *this; 35894 } 35895 35896 //! In-place version of the corresponding constructor. 35897 template<typename t> 35898 CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) { 35899 assign(n); 35900 cimglist_apply(*this,assign)(img,shared); 35901 return *this; 35902 } 35903 35904 //! In-place version of the corresponding constructor. 35905 template<typename t> 35906 CImgList<T>& assign(const CImg<t>& img, const bool shared=false) { 35907 assign(1); 35908 _data[0].assign(img,shared); 35909 return *this; 35910 } 35911 35912 //! In-place version of the corresponding constructor. 35913 template<typename t1, typename t2> 35914 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) { 35915 assign(2); 35916 _data[0].assign(img1,shared); _data[1].assign(img2,shared); 35917 return *this; 35918 } 35919 35920 //! In-place version of the corresponding constructor. 35921 template<typename t1, typename t2, typename t3> 35922 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) { 35923 assign(3); 35924 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); 35925 return *this; 35926 } 35927 35928 //! In-place version of the corresponding constructor. 35929 template<typename t1, typename t2, typename t3, typename t4> 35930 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35931 const bool shared=false) { 35932 assign(4); 35933 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35934 return *this; 35935 } 35936 35937 //! In-place version of the corresponding constructor. 35938 template<typename t1, typename t2, typename t3, typename t4, typename t5> 35939 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35940 const CImg<t5>& img5, const bool shared=false) { 35941 assign(5); 35942 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35943 _data[4].assign(img5,shared); 35944 return *this; 35945 } 35946 35947 //! In-place version of the corresponding constructor. 35948 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6> 35949 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35950 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) { 35951 assign(6); 35952 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35953 _data[4].assign(img5,shared); _data[5].assign(img6,shared); 35954 return *this; 35955 } 35956 35957 //! In-place version of the corresponding constructor. 35958 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7> 35959 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35960 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) { 35961 assign(7); 35962 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35963 _data[4].assign(img5,shared); _data[5].assign(img6,shared); _data[6].assign(img7,shared); 35964 return *this; 35965 } 35966 35967 //! In-place version of the corresponding constructor. 35968 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8> 35969 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, 35970 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, 35971 const bool shared=false) { 35972 assign(8); 35973 _data[0].assign(img1,shared); _data[1].assign(img2,shared); _data[2].assign(img3,shared); _data[3].assign(img4,shared); 35974 _data[4].assign(img5,shared); _data[5].assign(img6,shared); _data[6].assign(img7,shared); _data[7].assign(img8,shared); 35975 return *this; 35976 } 35977 35978 //! In-place version of the corresponding constructor. 35979 CImgList<T>& assign(const char *const filename) { 35980 return load(filename); 35981 } 35982 35983 //! In-place version of the corresponding constructor. 35984 CImgList<T>& assign(const CImgDisplay &disp) { 35985 return assign(CImg<T>(disp)); 35986 } 35987 35988 //! Move the content of the instance image list into another one. 35989 template<typename t> 35990 CImgList<T>& move_to(CImgList<t>& list) { 35991 list.assign(size()); 35992 cimglist_for(*this,l) _data[l].move_to(list[l]); 35993 assign(); 35994 return list; 35995 } 35996 35997 CImgList<T>& move_to(CImgList<T>& list) { 35998 list.assign(); 35999 return swap(list); 36000 } 36001 36002 template<typename t> 36003 CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos) { 36004 if (is_empty()) return list; 36005 const unsigned int npos = pos>list._width?list._width:pos; 36006 list.insert(_width,npos); 36007 cimglist_for(*this,l) (*this)[l].move_to(list.at(npos+l)); 36008 assign(); 36009 return list; 36010 } 36011 36012 //! Swap all fields of two CImgList instances (use with care !) 36013 CImgList<T>& swap(CImgList<T>& list) { 36014 cimg::swap(_width,list._width); 36015 cimg::swap(_allocated_width,list._allocated_width); 36016 cimg::swap(_data,list._data); 36017 return list; 36018 } 36019 36020 //! Return a reference to an empty list. 36021 static CImgList<T>& empty() { 36022 static CImgList<T> _empty; 36023 return _empty.assign(); 36024 } 36025 36026 //@} 36027 //------------------------------------------ 36028 // 36029 //! \name Overloaded Operators 36030 //@{ 36031 //------------------------------------------ 36032 36033 //! Return a reference to the i-th element of the image list. 36034 CImg<T>& operator()(const unsigned int pos) { 36035 #if cimg_verbosity>=3 36036 if (pos>=_width) { 36037 cimg::warn(_cimglist_instance 36038 "operator() : Invalid image request, at position [%u].", 36039 cimglist_instance, 36040 pos); 36041 return *_data; 36042 } 36043 #endif 36044 return _data[pos]; 36045 } 36046 36047 const CImg<T>& operator()(const unsigned int pos) const { 36048 return const_cast<CImgList<T>*>(this)->operator()(pos); 36049 } 36050 36051 //! Return a reference to (x,y,z,c) pixel of the pos-th image of the list 36052 T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, 36053 const unsigned int z=0, const unsigned int c=0) { 36054 return (*this)[pos](x,y,z,c); 36055 } 36056 const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, 36057 const unsigned int z=0, const unsigned int c=0) const { 36058 return (*this)[pos](x,y,z,c); 36059 } 36060 36061 //! Return address of the image vector. 36062 operator const CImg<T>*() const { 36063 return _data; 36064 } 36065 36066 operator CImg<T>*() { 36067 return _data; 36068 } 36069 36070 //! Operator=(). 36071 template<typename t> 36072 CImgList<T>& operator=(const CImg<t>& img) { 36073 return assign(img); 36074 } 36075 36076 //! Operator=(). 36077 CImgList<T>& operator=(const CImgDisplay& disp) { 36078 return assign(disp); 36079 } 36080 36081 //! Operator=(). 36082 template<typename t> 36083 CImgList<T>& operator=(const CImgList<t>& list) { 36084 return assign(list); 36085 } 36086 36087 CImgList<T>& operator=(const CImgList<T>& list) { 36088 return assign(list); 36089 } 36090 36091 //! Operator=(). 36092 CImgList<T>& operator=(const char *const filename) { 36093 return assign(filename); 36094 } 36095 36096 //! Operator+() (unary). 36097 /** 36098 Writting '+list' is a convenient shortcut to 'CImgList<T>(list,false)' 36099 (forces a copy with non-shared elements). 36100 **/ 36101 CImgList<T> operator+() const { 36102 return CImgList<T>(*this,false); 36103 } 36104 36105 //! Operator,(). 36106 template<typename t> 36107 CImgList<T>& operator,(const CImg<t>& img) { 36108 return insert(img); 36109 } 36110 36111 //! Operator,(). 36112 template<typename t> 36113 CImgList<T>& operator,(const CImgList<t>& list) { 36114 return insert(list); 36115 } 36116 36117 //! Operator>(). 36118 CImg<T> operator>(const char axis) const { 36119 return get_append(axis,'p'); 36120 } 36121 36122 //! Operator<(). 36123 CImgList<T> operator<(const char axis) const { 36124 return get_split(axis); 36125 } 36126 36127 //@} 36128 //------------------------------------- 36129 // 36130 //! \name Instance Characteristics 36131 //@{ 36132 //------------------------------------- 36133 36134 //! Return a string describing the type of the image pixels in the list (template parameter \p T). 36135 static const char* pixel_type() { 36136 return cimg::type<T>::string(); 36137 } 36138 36139 //! Return the size of the list. 36140 int width() const { 36141 return (int)_width; 36142 } 36143 36144 //! Return the size of the list. 36145 unsigned int size() const { 36146 return _width; 36147 } 36148 36149 //! Return a pointer to the image buffer. 36150 CImg<T> *data() { 36151 return _data; 36152 } 36153 36154 const CImg<T> *data() const { 36155 return _data; 36156 } 36157 36158 //! Return a pointer to the image buffer. 36159 #if cimg_verbosity>=3 36160 CImg<T> *data(const unsigned int l) { 36161 if (l>=size()) { 36162 cimg::warn(_cimglist_instance 36163 "data() : Invalid pointer request, at position [%u].", 36164 cimglist_instance, 36165 l); 36166 return _data; 36167 } 36168 return _data + l; 36169 } 36170 36171 const CImg<T> *data(const unsigned int l) const { 36172 return const_cast<CImgList<T>*>(this)->data(l); 36173 } 36174 #else 36175 CImg<T> *data(const unsigned int l) { 36176 return _data + l; 36177 } 36178 36179 const CImg<T> *data(const unsigned int l) const { 36180 return _data + l; 36181 } 36182 #endif 36183 36184 //! Returns an iterator to the beginning of the vector (STL-compliant name). 36185 iterator begin() { 36186 return _data; 36187 } 36188 36189 const_iterator begin() const { 36190 return _data; 36191 } 36192 36193 //! Returns an iterator just past the last element (STL-compliant name). 36194 iterator end() { 36195 return _data + _width; 36196 } 36197 36198 const_iterator end() const { 36199 return _data + _width; 36200 } 36201 36202 //! Returns a reference to the first element (STL-compliant name). 36203 CImg<T>& front() { 36204 return *_data; 36205 } 36206 36207 const CImg<T>& front() const { 36208 return *_data; 36209 } 36210 36211 //! Return a reference to the last image (STL-compliant name). 36212 const CImg<T>& back() const { 36213 return *(_data + _width - 1); 36214 } 36215 36216 CImg<T>& back() { 36217 return *(_data + _width - 1); 36218 } 36219 36220 //! Read an image in specified position. 36221 CImg<T>& at(const int pos) { 36222 if (is_empty()) 36223 throw CImgInstanceException(_cimglist_instance 36224 "at() : Empty instance.", 36225 cimglist_instance); 36226 36227 return _data[pos<0?0:pos>=(int)_width?(int)_width-1:pos]; 36228 } 36229 36230 //! Read a pixel value with Dirichlet boundary conditions. 36231 T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T out_val) { 36232 return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_val)=out_val):_data[pos].atXYZC(x,y,z,c,out_val); 36233 } 36234 36235 T atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T out_val) const { 36236 return (pos<0 || pos>=(int)_width)?out_val:_data[pos].atXYZC(x,y,z,c,out_val); 36237 } 36238 36239 //! Read a pixel value with Neumann boundary conditions. 36240 T& atNXYZC(const int pos, const int x, const int y, const int z, const int c) { 36241 if (is_empty()) 36242 throw CImgInstanceException(_cimglist_instance 36243 "atNXYZC() : Empty instance.", 36244 cimglist_instance); 36245 36246 return _atNXYZC(pos,x,y,z,c); 36247 } 36248 36249 T atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { 36250 if (is_empty()) 36251 throw CImgInstanceException(_cimglist_instance 36252 "atNXYZC() : Empty instance.", 36253 cimglist_instance); 36254 36255 return _atNXYZC(pos,x,y,z,c); 36256 } 36257 36258 T& _atNXYZC(const int pos, const int x, const int y, const int z, const int c) { 36259 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZC(x,y,z,c); 36260 } 36261 36262 T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { 36263 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZC(x,y,z,c); 36264 } 36265 36266 //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z). 36267 T& atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T out_val) { 36268 return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_val)=out_val):_data[pos].atXYZ(x,y,z,c,out_val); 36269 } 36270 36271 T atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T out_val) const { 36272 return (pos<0 || pos>=(int)_width)?out_val:_data[pos].atXYZ(x,y,z,c,out_val); 36273 } 36274 36275 //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z). 36276 T& atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { 36277 if (is_empty()) 36278 throw CImgInstanceException(_cimglist_instance 36279 "atNXYZ() : Empty instance.", 36280 cimglist_instance); 36281 36282 return _atNXYZ(pos,x,y,z,c); 36283 } 36284 36285 T atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { 36286 if (is_empty()) 36287 throw CImgInstanceException(_cimglist_instance 36288 "atNXYZ() : Empty instance.", 36289 cimglist_instance); 36290 36291 return _atNXYZ(pos,x,y,z,c); 36292 } 36293 36294 T& _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { 36295 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZ(x,y,z,c); 36296 } 36297 36298 T _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { 36299 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXYZ(x,y,z,c); 36300 } 36301 36302 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y). 36303 T& atNXY(const int pos, const int x, const int y, const int z, const int c, const T out_val) { 36304 return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_val)=out_val):_data[pos].atXY(x,y,z,c,out_val); 36305 } 36306 36307 T atNXY(const int pos, const int x, const int y, const int z, const int c, const T out_val) const { 36308 return (pos<0 || pos>=(int)_width)?out_val:_data[pos].atXY(x,y,z,c,out_val); 36309 } 36310 36311 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y). 36312 T& atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { 36313 if (is_empty()) 36314 throw CImgInstanceException(_cimglist_instance 36315 "atNXY() : Empty instance.", 36316 cimglist_instance); 36317 36318 return _atNXY(pos,x,y,z,c); 36319 } 36320 36321 T atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { 36322 if (is_empty()) 36323 throw CImgInstanceException(_cimglist_instance 36324 "atNXY() : Empty instance.", 36325 cimglist_instance); 36326 36327 return _atNXY(pos,x,y,z,c); 36328 } 36329 36330 T& _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { 36331 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXY(x,y,z,c); 36332 } 36333 36334 T _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { 36335 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atXY(x,y,z,c); 36336 } 36337 36338 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x). 36339 T& atNX(const int pos, const int x, const int y, const int z, const int c, const T out_val) { 36340 return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_val)=out_val):_data[pos].atX(x,y,z,c,out_val); 36341 } 36342 36343 T atNX(const int pos, const int x, const int y, const int z, const int c, const T out_val) const { 36344 return (pos<0 || pos>=(int)_width)?out_val:_data[pos].atX(x,y,z,c,out_val); 36345 } 36346 36347 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x). 36348 T& atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { 36349 if (is_empty()) 36350 throw CImgInstanceException(_cimglist_instance 36351 "atNX() : Empty instance.", 36352 cimglist_instance); 36353 36354 return _atNX(pos,x,y,z,c); 36355 } 36356 36357 T atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { 36358 if (is_empty()) 36359 throw CImgInstanceException(_cimglist_instance 36360 "atNX() : Empty instance.", 36361 cimglist_instance); 36362 36363 return _atNX(pos,x,y,z,c); 36364 } 36365 36366 T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { 36367 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atX(x,y,z,c); 36368 } 36369 36370 T _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { 36371 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)].atX(x,y,z,c); 36372 } 36373 36374 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos). 36375 T& atN(const int pos, const int x, const int y, const int z, const int c, const T out_val) { 36376 return (pos<0 || pos>=(int)_width)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,c); 36377 } 36378 36379 T atN(const int pos, const int x, const int y, const int z, const int c, const T out_val) const { 36380 return (pos<0 || pos>=(int)_width)?out_val:(*this)(pos,x,y,z,c); 36381 } 36382 36383 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos). 36384 T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { 36385 if (is_empty()) 36386 throw CImgInstanceException(_cimglist_instance 36387 "atN() : Empty instance.", 36388 cimglist_instance); 36389 return _atN(pos,x,y,z,c); 36390 } 36391 36392 T atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { 36393 if (is_empty()) 36394 throw CImgInstanceException(_cimglist_instance 36395 "atN() : Empty instance.", 36396 cimglist_instance); 36397 return _atN(pos,x,y,z,c); 36398 } 36399 36400 T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { 36401 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)](x,y,z,c); 36402 } 36403 36404 T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { 36405 return _data[pos<0?0:(pos>=(int)_width?(int)_width-1:pos)](x,y,z,c); 36406 } 36407 36408 //! Return a C-string containing the values of all images in the instance list. 36409 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const { 36410 if (is_empty()) return CImg<ucharT>(1,1,1,1,0); 36411 CImgList<charT> items; 36412 for (unsigned int l = 0; l<_width-1; ++l) { 36413 CImg<charT> item = _data[l].value_string(separator,0); 36414 item.back() = separator; 36415 item.move_to(items); 36416 } 36417 _data[_width-1].value_string(separator,0).move_to(items); 36418 CImg<charT> res; (items>'x').move_to(res); 36419 if (max_size) { res.crop(0,max_size); res(max_size) = 0; } 36420 return res; 36421 } 36422 36423 //@} 36424 //------------------------------------- 36425 // 36426 //! \name Instance Checking 36427 //@{ 36428 //------------------------------------- 36429 36430 //! Return \p true if list is empty. 36431 bool is_empty() const { 36432 return (!_data || !_width); 36433 } 36434 36435 //! Return \p true if list if of specified size. 36436 bool is_sameN(const unsigned int n) const { 36437 return (_width==n); 36438 } 36439 36440 //! Return \p true if list if of specified size. 36441 template<typename t> 36442 bool is_sameN(const CImgList<t>& list) const { 36443 return (_width==list._width); 36444 } 36445 36446 // Define useful dimension check functions. 36447 // (not documented because they are macro-generated). 36448 #define _cimglist_def_is_same1(axis) \ 36449 bool is_same##axis(const unsigned int val) const { \ 36450 bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(val); return res; \ 36451 } \ 36452 bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \ 36453 return is_sameN(n) && is_same##axis(val); \ 36454 } \ 36455 36456 #define _cimglist_def_is_same2(axis1,axis2) \ 36457 bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \ 36458 bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2(val1,val2); return res; \ 36459 } \ 36460 bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \ 36461 return is_sameN(n) && is_same##axis1##axis2(val1,val2); \ 36462 } \ 36463 36464 #define _cimglist_def_is_same3(axis1,axis2,axis3) \ 36465 bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \ 36466 bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2##axis3(val1,val2,val3); return res; \ 36467 } \ 36468 bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \ 36469 return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \ 36470 } \ 36471 36472 #define _cimglist_def_is_same(axis) \ 36473 template<typename t> bool is_same##axis(const CImg<t>& img) const { \ 36474 bool res = true; for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(img); return res; \ 36475 } \ 36476 template<typename t> bool is_same##axis(const CImgList<t>& list) const { \ 36477 const unsigned int lmin = cimg::min(_width,list._width); \ 36478 bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = _data[l].is_same##axis(list[l]); return res; \ 36479 } \ 36480 template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \ 36481 return (is_sameN(n) && is_same##axis(img)); \ 36482 } \ 36483 template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \ 36484 return (is_sameN(list) && is_same##axis(list)); \ 36485 } 36486 36487 _cimglist_def_is_same(XY) 36488 _cimglist_def_is_same(XZ) 36489 _cimglist_def_is_same(XC) 36490 _cimglist_def_is_same(YZ) 36491 _cimglist_def_is_same(YC) 36492 _cimglist_def_is_same(XYZ) 36493 _cimglist_def_is_same(XYC) 36494 _cimglist_def_is_same(YZC) 36495 _cimglist_def_is_same(XYZC) 36496 _cimglist_def_is_same1(X) 36497 _cimglist_def_is_same1(Y) 36498 _cimglist_def_is_same1(Z) 36499 _cimglist_def_is_same1(C) 36500 _cimglist_def_is_same2(X,Y) 36501 _cimglist_def_is_same2(X,Z) 36502 _cimglist_def_is_same2(X,C) 36503 _cimglist_def_is_same2(Y,Z) 36504 _cimglist_def_is_same2(Y,C) 36505 _cimglist_def_is_same2(Z,C) 36506 _cimglist_def_is_same3(X,Y,Z) 36507 _cimglist_def_is_same3(X,Y,C) 36508 _cimglist_def_is_same3(X,Z,C) 36509 _cimglist_def_is_same3(Y,Z,C) 36510 36511 bool is_sameXYZC(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) const { 36512 bool res = true; 36513 for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_sameXYZC(dx,dy,dz,dc); 36514 return res; 36515 } 36516 36517 bool is_sameNXYZC(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dc) const { 36518 return is_sameN(n) && is_sameXYZC(dx,dy,dz,dc); 36519 } 36520 36521 //! Return \c true if the list contains the pixel (n,x,y,z,c). 36522 bool containsNXYZC(const int n, const int x=0, const int y=0, const int z=0, const int c=0) const { 36523 if (is_empty()) return false; 36524 return n>=0 && n<(int)_width && x>=0 && x<_data[n].width() && y>=0 && y<_data[n].height() && 36525 z>=0 && z<_data[n].depth() && c>=0 && c<_data[n].spectrum(); 36526 } 36527 36528 //! Return \c true if the list contains the image (n). 36529 bool containsN(const int n) const { 36530 if (is_empty()) return false; 36531 return n>=0 && n<(int)_width; 36532 } 36533 36534 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,c). 36535 template<typename t> 36536 bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& c) const { 36537 if (is_empty()) return false; 36538 cimglist_for(*this,l) if (_data[l].contains(pixel,x,y,z,c)) { n = (t)l; return true; } 36539 return false; 36540 } 36541 36542 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z). 36543 template<typename t> 36544 bool contains(const T& pixel, t& n, t& x, t&y, t& z) const { 36545 t c; 36546 return contains(pixel,n,x,y,z,c); 36547 } 36548 36549 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y). 36550 template<typename t> 36551 bool contains(const T& pixel, t& n, t& x, t&y) const { 36552 t z, c; 36553 return contains(pixel,n,x,y,z,c); 36554 } 36555 36556 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x). 36557 template<typename t> 36558 bool contains(const T& pixel, t& n, t& x) const { 36559 t y, z, c; 36560 return contains(pixel,n,x,y,z,c); 36561 } 36562 36563 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n). 36564 template<typename t> 36565 bool contains(const T& pixel, t& n) const { 36566 t x, y, z, c; 36567 return contains(pixel,n,x,y,z,c); 36568 } 36569 36570 //! Return \c true if one of the image list contains the specified referenced value. 36571 bool contains(const T& pixel) const { 36572 unsigned int n, x, y, z, c; 36573 return contains(pixel,n,x,y,z,c); 36574 } 36575 36576 //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list. 36577 template<typename t> 36578 bool contains(const CImg<T>& img, t& n) const { 36579 if (is_empty()) return false; 36580 const CImg<T> *const ptr = &img; 36581 cimglist_for(*this,i) if (_data+i==ptr) { n = (t)i; return true; } 36582 return false; 36583 } 36584 36585 //! Return \c true if the list contains the image img. 36586 bool contains(const CImg<T>& img) const { 36587 unsigned int n; 36588 return contains(img,n); 36589 } 36590 36591 //@} 36592 //------------------------------------- 36593 // 36594 //! \name Mathematical Functions 36595 //@{ 36596 //------------------------------------- 36597 36598 //! Return a reference to the minimum pixel value of the instance list. 36599 T& min() { 36600 if (is_empty()) 36601 throw CImgInstanceException(_cimglist_instance 36602 "min() : Empty instance.", 36603 cimglist_instance); 36604 T *ptr_min = _data->_data; 36605 T min_value = *ptr_min; 36606 cimglist_for(*this,l) { 36607 const CImg<T>& img = _data[l]; 36608 cimg_for(img,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs); 36609 } 36610 return *ptr_min; 36611 } 36612 36613 const T& min() const { 36614 if (is_empty()) 36615 throw CImgInstanceException(_cimglist_instance 36616 "min() : Empty instance.", 36617 cimglist_instance); 36618 const T *ptr_min = _data->_data; 36619 T min_value = *ptr_min; 36620 cimglist_for(*this,l) { 36621 const CImg<T>& img = _data[l]; 36622 cimg_for(img,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs); 36623 } 36624 return *ptr_min; 36625 } 36626 36627 //! Return a reference to the maximum pixel value of the instance list. 36628 T& max() { 36629 if (is_empty()) 36630 throw CImgInstanceException(_cimglist_instance 36631 "max() : Empty instance.", 36632 cimglist_instance); 36633 T *ptr_max = _data->_data; 36634 T max_value = *ptr_max; 36635 cimglist_for(*this,l) { 36636 const CImg<T>& img = _data[l]; 36637 cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); 36638 } 36639 return *ptr_max; 36640 } 36641 36642 const T& max() const { 36643 if (is_empty()) 36644 throw CImgInstanceException(_cimglist_instance 36645 "max() : Empty instance.", 36646 cimglist_instance); 36647 const T *ptr_max = _data->_data; 36648 T max_value = *ptr_max; 36649 cimglist_for(*this,l) { 36650 const CImg<T>& img = _data[l]; 36651 cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); 36652 } 36653 return *ptr_max; 36654 } 36655 36656 //! Return a reference to the minimum pixel value of the instance list. 36657 template<typename t> 36658 T& min_max(t& max_val) { 36659 if (is_empty()) 36660 throw CImgInstanceException(_cimglist_instance 36661 "min_max() : Empty instance.", 36662 cimglist_instance); 36663 T *ptr_min = _data->_data; 36664 T min_value = *ptr_min, max_value = min_value; 36665 cimglist_for(*this,l) { 36666 const CImg<T>& img = _data[l]; 36667 cimg_for(img,ptrs,T) { 36668 const T val = *ptrs; 36669 if (val<min_value) { min_value = val; ptr_min = ptrs; } 36670 if (val>max_value) max_value = val; 36671 } 36672 } 36673 max_val = (t)max_value; 36674 return *ptr_min; 36675 } 36676 36677 template<typename t> 36678 const T& min_max(t& max_val) const { 36679 if (is_empty()) 36680 throw CImgInstanceException(_cimglist_instance 36681 "min_max() : Empty instance.", 36682 cimglist_instance); 36683 const T *ptr_min = _data->_data; 36684 T min_value = *ptr_min, max_value = min_value; 36685 cimglist_for(*this,l) { 36686 const CImg<T>& img = _data[l]; 36687 cimg_for(img,ptrs,T) { 36688 const T val = *ptrs; 36689 if (val<min_value) { min_value = val; ptr_min = ptrs; } 36690 if (val>max_value) max_value = val; 36691 } 36692 } 36693 max_val = (t)max_value; 36694 return *ptr_min; 36695 } 36696 36697 //! Return a reference to the minimum pixel value of the instance list. 36698 template<typename t> 36699 T& max_min(t& min_val) { 36700 if (is_empty()) 36701 throw CImgInstanceException(_cimglist_instance 36702 "max_min() : Empty instance.", 36703 cimglist_instance); 36704 T *ptr_max = _data->_data; 36705 T min_value = *ptr_max, max_value = min_value; 36706 cimglist_for(*this,l) { 36707 const CImg<T>& img = _data[l]; 36708 cimg_for(img,ptrs,T) { 36709 const T val = *ptrs; 36710 if (val>max_value) { max_value = val; ptr_max = ptrs; } 36711 if (val<min_value) min_value = val; 36712 } 36713 } 36714 min_val = (t)min_value; 36715 return *ptr_max; 36716 } 36717 36718 template<typename t> 36719 const T& max_min(t& min_val) const { 36720 if (is_empty()) 36721 throw CImgInstanceException(_cimglist_instance 36722 "max_min() : Empty instance.", 36723 cimglist_instance); 36724 const T *ptr_max = _data->_data; 36725 T min_value = *ptr_max, max_value = min_value; 36726 cimglist_for(*this,l) { 36727 const CImg<T>& img = _data[l]; 36728 cimg_for(img,ptrs,T) { 36729 const T val = *ptrs; 36730 if (val>max_value) { max_value = val; ptr_max = ptrs; } 36731 if (val<min_value) min_value = val; 36732 } 36733 } 36734 min_val = (t)min_value; 36735 return *ptr_max; 36736 } 36737 36738 //@} 36739 //--------------------------- 36740 // 36741 //! \name List Manipulation 36742 //@{ 36743 //--------------------------- 36744 36745 //! Insert a copy of the image \p img into the current image list, at position \p pos. 36746 template<typename t> 36747 CImgList<T>& insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) { 36748 const unsigned int npos = pos==~0U?_width:pos; 36749 if (npos>_width) 36750 throw CImgArgumentException(_cimglist_instance 36751 "insert() : Invalid insertion request of specified image (%u,%u,%u,%u,%p) at position %u.", 36752 cimglist_instance, 36753 img._width,img._height,img._depth,img._spectrum,img._data,npos); 36754 if (shared) 36755 throw CImgArgumentException(_cimglist_instance 36756 "insert() : Invalid insertion request of specified shared image CImg<%s>(%u,%u,%u,%u,%p) at position %u " 36757 "(pixel types are different).", 36758 cimglist_instance, 36759 img.pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data,npos); 36760 36761 CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):(_allocated_width=16)]:0; 36762 if (!_width || !_data) { 36763 _data = new_data; 36764 *_data = img; 36765 } else { 36766 if (new_data) { 36767 if (npos) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos); 36768 if (npos!=_width-1) std::memcpy(new_data+npos+1,_data+npos,sizeof(CImg<T>)*(_width-1-npos)); 36769 std::memset(_data,0,sizeof(CImg<T>)*(_width-1)); 36770 delete[] _data; 36771 _data = new_data; 36772 } 36773 else if (npos!=_width-1) std::memmove(_data+npos+1,_data+npos,sizeof(CImg<T>)*(_width-1-npos)); 36774 _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; _data[npos]._data = 0; 36775 _data[npos] = img; 36776 } 36777 return *this; 36778 } 36779 36780 CImgList<T>& insert(const CImg<T>& img, const unsigned int pos=~0U, const bool shared=false) { 36781 const unsigned int npos = pos==~0U?_width:pos; 36782 if (npos>_width) 36783 throw CImgArgumentException(_cimglist_instance 36784 "insert() : Invalid insertion request of specified image (%u,%u,%u,%u,%p) at position %u.", 36785 cimglist_instance, 36786 img._width,img._height,img._depth,img._spectrum,img._data,npos); 36787 36788 // if (&img>=data() && &img<end()) return insert(+img,pos,shared); 36789 36790 CImg<T> *const new_data = (++_width>_allocated_width)?new CImg<T>[_allocated_width?(_allocated_width<<=1):(_allocated_width=16)]:0; 36791 if (!_width || !_data) { 36792 _data = new_data; 36793 if (shared && img) { 36794 _data->_width = img._width; _data->_height = img._height; _data->_depth = img._depth; _data->_spectrum = img._spectrum; 36795 _data->_is_shared = true; _data->_data = img._data; 36796 } else *_data = img; 36797 } 36798 else { 36799 if (new_data) { 36800 if (npos) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos); 36801 if (npos!=_width-1) std::memcpy(new_data+npos+1,_data+npos,sizeof(CImg<T>)*(_width-1-npos)); 36802 if (shared && img) { 36803 new_data[npos]._width = img._width; new_data[npos]._height = img._height; new_data[npos]._depth = img._depth; 36804 new_data[npos]._spectrum = img._spectrum; new_data[npos]._is_shared = true; new_data[npos]._data = img._data; 36805 } else { 36806 new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0; new_data[npos]._data = 0; 36807 new_data[npos] = img; 36808 } 36809 std::memset(_data,0,sizeof(CImg<T>)*(_width-1)); 36810 delete[] _data; 36811 _data = new_data; 36812 } else { 36813 if (npos!=_width-1) std::memmove(_data+npos+1,_data+npos,sizeof(CImg<T>)*(_width-1-npos)); 36814 if (shared && img) { 36815 _data[npos]._width = img._width; _data[npos]._height = img._height; _data[npos]._depth = img._depth; _data[npos]._spectrum = img._spectrum; 36816 _data[npos]._is_shared = true; _data[npos]._data = img._data; 36817 } else { 36818 _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; _data[npos]._data = 0; 36819 _data[npos] = img; 36820 } 36821 } 36822 } 36823 return *this; 36824 } 36825 36826 template<typename t> 36827 CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const { 36828 return (+*this).insert(img,pos,shared); 36829 } 36830 36831 //! Insert n empty images img into the current image list, at position \p pos. 36832 CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) { 36833 CImg<T> foo; 36834 if (!n) return *this; 36835 const unsigned int npos = pos==~0U?_width:pos; 36836 for (unsigned int i = 0; i<n; ++i) insert(foo,npos+i); 36837 return *this; 36838 } 36839 36840 CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const { 36841 return (+*this).insert(n,pos); 36842 } 36843 36844 //! Insert n copies of the image \p img into the current image list, at position \p pos. 36845 template<typename t> 36846 CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) { 36847 if (!n) return *this; 36848 const unsigned int npos = pos==~0U?_width:pos; 36849 insert(img,npos,shared); 36850 for (unsigned int i = 1; i<n; ++i) insert(_data[npos],npos+i,shared); 36851 return *this; 36852 } 36853 36854 template<typename t> 36855 CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const { 36856 return (+*this).insert(n,img,pos,shared); 36857 } 36858 36859 //! Insert a copy of the image list \p list into the current image list, starting from position \p pos. 36860 template<typename t> 36861 CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) { 36862 const unsigned int npos = pos==~0U?_width:pos; 36863 if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared); 36864 else insert(CImgList<T>(list),npos,shared); 36865 return *this; 36866 } 36867 36868 template<typename t> 36869 CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const { 36870 return (+*this).insert(list,pos,shared); 36871 } 36872 36873 //! Insert n copies of the list \p list at position \p pos of the current list. 36874 template<typename t> 36875 CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) { 36876 if (!n) return *this; 36877 const unsigned int npos = pos==~0U?_width:pos; 36878 for (unsigned int i = 0; i<n; ++i) insert(list,npos,shared); 36879 return *this; 36880 } 36881 36882 template<typename t> 36883 CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const { 36884 return (+*this).insert(n,list,pos,shared); 36885 } 36886 36887 //! Remove the images from positions \p pos1 to \p pos2. 36888 CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) { 36889 const unsigned int 36890 npos1 = pos1<pos2?pos1:pos2, 36891 tpos2 = pos1<pos2?pos2:pos1, 36892 npos2 = tpos2<_width?tpos2:_width-1; 36893 if (npos1>=_width) 36894 throw CImgArgumentException(_cimglist_instance 36895 "remove() : Invalid remove request at positions %u->%u.", 36896 cimglist_instance, 36897 npos1,tpos2); 36898 else { 36899 if (tpos2>=_width) 36900 throw CImgArgumentException(_cimglist_instance 36901 "remove() : Invalid remove request at positions %u->%u.", 36902 cimglist_instance, 36903 npos1,tpos2); 36904 36905 for (unsigned int k = npos1; k<=npos2; ++k) _data[k].assign(); 36906 const unsigned int nb = 1 + npos2 - npos1; 36907 if (!(_width-=nb)) return assign(); 36908 if (_width>(_allocated_width>>2) || _allocated_width<=8) { // Removing items without reallocation. 36909 if (npos1!=_width) std::memmove(_data+npos1,_data+npos2+1,sizeof(CImg<T>)*(_width - npos1)); 36910 std::memset(_data + _width,0,sizeof(CImg<T>)*nb); 36911 } else { // Removing items with reallocation. 36912 _allocated_width>>=2; 36913 while (_allocated_width>8 && _width<(_allocated_width>>1)) _allocated_width>>=1; 36914 CImg<T> *const new_data = new CImg<T>[_allocated_width]; 36915 if (npos1) std::memcpy(new_data,_data,sizeof(CImg<T>)*npos1); 36916 if (npos1!=_width) std::memcpy(new_data+npos1,_data+npos2+1,sizeof(CImg<T>)*(_width-npos1)); 36917 if (_width!=_allocated_width) std::memset(new_data+_width,0,sizeof(_allocated_width - _width)); 36918 std::memset(_data,0,sizeof(CImg<T>)*(_width+nb)); 36919 delete[] _data; 36920 _data = new_data; 36921 } 36922 } 36923 return *this; 36924 } 36925 36926 CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const { 36927 return (+*this).remove(pos1,pos2); 36928 } 36929 36930 //! Remove the image at position \p pos from the image list. 36931 CImgList<T>& remove(const unsigned int pos) { 36932 return remove(pos,pos); 36933 } 36934 36935 CImgList<T> get_remove(const unsigned int pos) const { 36936 return (+*this).remove(pos); 36937 } 36938 36939 //! Remove the last image from the image list. 36940 CImgList<T>& remove() { 36941 return remove(_width-1); 36942 } 36943 36944 CImgList<T> get_remove() const { 36945 return (+*this).remove(); 36946 } 36947 36948 //! Reverse list order. 36949 CImgList<T>& reverse() { 36950 for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width-1-l]); 36951 return *this; 36952 } 36953 36954 CImgList<T> get_reverse() const { 36955 return (+*this).reverse(); 36956 } 36957 36958 //! Get a sub-list. 36959 CImgList<T>& images(const unsigned int i0, const unsigned int i1) { 36960 return get_images(i0,i1).move_to(*this); 36961 } 36962 36963 CImgList<T> get_images(const unsigned int i0, const unsigned int i1) const { 36964 if (i0>i1 || i1>=_width) 36965 throw CImgArgumentException(_cimglist_instance 36966 "images() : Specified sub-list indices (%u->%u) are out of bounds.", 36967 cimglist_instance, 36968 i0,i1); 36969 CImgList<T> res(i1-i0+1); 36970 cimglist_for(res,l) res[l].assign(_data[i0+l]); 36971 return res; 36972 } 36973 36974 //! Get a shared sub-list. 36975 CImgList<T> get_shared_images(const unsigned int i0, const unsigned int i1) { 36976 if (i0>i1 || i1>=_width) 36977 throw CImgArgumentException(_cimglist_instance 36978 "get_shared_images() : Specified sub-list indices (%u->%u) are out of bounds.", 36979 cimglist_instance, 36980 i0,i1); 36981 CImgList<T> res(i1-i0+1); 36982 cimglist_for(res,l) res[l].assign(_data[i0+l],true); 36983 return res; 36984 } 36985 36986 const CImgList<T> get_shared_images(const unsigned int i0, const unsigned int i1) const { 36987 if (i0>i1 || i1>=_width) 36988 throw CImgArgumentException(_cimglist_instance 36989 "get_shared_images() : Specified sub-list indices (%u->%u) are out of bounds.", 36990 cimglist_instance, 36991 i0,i1); 36992 CImgList<T> res(i1-i0+1); 36993 cimglist_for(res,l) res[l].assign(_data[i0+l],true); 36994 return res; 36995 } 36996 36997 //! Return a single image which is the concatenation of all images of the current CImgList instance. 36998 /** 36999 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'c'. 37000 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). 37001 \return A CImg<T> image corresponding to the concatenation is returned. 37002 **/ 37003 CImg<T> get_append(const char axis, const char align='p') const { 37004 if (align!='p' && align!='c' && align!='n') 37005 throw CImgArgumentException(_cimglist_instance 37006 "get_append() : Invalid alignment parameter '%c' " 37007 "(should be { p | c | n }).", 37008 cimglist_instance, 37009 align); 37010 37011 if (is_empty()) return CImg<T>(); 37012 if (_width==1) return +((*this)[0]); 37013 unsigned int dx = 0, dy = 0, dz = 0, dc = 0, pos = 0; 37014 CImg<T> res; 37015 switch (cimg::uncase(axis)) { 37016 case 'x' : { // Along the X-axis. 37017 cimglist_for(*this,l) { 37018 const CImg<T>& img = (*this)[l]; 37019 dx+=img._width; dy = cimg::max(dy,img._height); dz = cimg::max(dz,img._depth); dc = cimg::max(dc,img._spectrum); 37020 } 37021 res.assign(dx,dy,dz,dc,0); 37022 if (res) switch (cimg::uncase(align)) { 37023 case 'p' : { 37024 cimglist_for(*this,l) { 37025 res.draw_image(pos,(*this)[l]); 37026 pos+=(*this)[l]._width; 37027 } 37028 } break; 37029 case 'c' : { 37030 cimglist_for(*this,l) { 37031 res.draw_image(pos,(dy-(*this)[l]._height)/2,(dz-(*this)[l]._depth)/2,(dc-(*this)[l]._spectrum)/2,(*this)[l]); 37032 pos+=(*this)[l]._width; 37033 } 37034 } break; 37035 default : { 37036 cimglist_for(*this,l) { 37037 res.draw_image(pos,dy-(*this)[l]._height,dz-(*this)[l]._depth,dc-(*this)[l]._spectrum,(*this)[l]); 37038 pos+=(*this)[l]._width; 37039 } 37040 } 37041 } 37042 } break; 37043 case 'y' : { // Along the Y-axis. 37044 cimglist_for(*this,l) { 37045 const CImg<T>& img = (*this)[l]; 37046 dx = cimg::max(dx,img._width); dy+=img._height; dz = cimg::max(dz,img._depth); dc = cimg::max(dc,img._spectrum); 37047 } 37048 res.assign(dx,dy,dz,dc,0); 37049 if (res) switch (cimg::uncase(align)) { 37050 case 'p' : { 37051 cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l]._height; } 37052 } break; 37053 case 'c' : { 37054 cimglist_for(*this,l) { 37055 res.draw_image((dx-(*this)[l]._width)/2,pos,(dz-(*this)[l]._depth)/2,(dc-(*this)[l]._spectrum)/2,(*this)[l]); 37056 pos+=(*this)[l]._height; 37057 } 37058 } break; 37059 default : { 37060 cimglist_for(*this,l) { 37061 res.draw_image(dx-(*this)[l]._width,pos,dz-(*this)[l]._depth,dc-(*this)[l]._spectrum,(*this)[l]); 37062 pos+=(*this)[l]._height; 37063 } 37064 } 37065 } 37066 } break; 37067 case 'z' : { // Along the Z-axis. 37068 cimglist_for(*this,l) { 37069 const CImg<T>& img = (*this)[l]; 37070 dx = cimg::max(dx,img._width); dy = cimg::max(dy,img._height); dz+=img._depth; dc = cimg::max(dc,img._spectrum); 37071 } 37072 res.assign(dx,dy,dz,dc,0); 37073 if (res) switch (cimg::uncase(align)) { 37074 case 'p' : { 37075 cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l]._depth; } 37076 } break; 37077 case 'c' : { 37078 cimglist_for(*this,l) { 37079 res.draw_image((dx-(*this)[l]._width)/2,(dy-(*this)[l]._height)/2,pos,(dc-(*this)[l]._spectrum)/2,(*this)[l]); 37080 pos+=(*this)[l]._depth; 37081 } 37082 } break; 37083 default : { 37084 cimglist_for(*this,l) { 37085 res.draw_image(dx-(*this)[l]._width,dy-(*this)[l]._height,pos,dc-(*this)[l]._spectrum,(*this)[l]); 37086 pos+=(*this)[l]._depth; 37087 } 37088 } 37089 } 37090 } break; 37091 default : { // Along the C-axis. 37092 cimglist_for(*this,l) { 37093 const CImg<T>& img = (*this)[l]; 37094 dx = cimg::max(dx,img._width); dy = cimg::max(dy,img._height); dz = cimg::max(dz,img._depth); dc+=img._spectrum; 37095 } 37096 res.assign(dx,dy,dz,dc,0); 37097 if (res) switch (cimg::uncase(align)) { 37098 case 'p' : { 37099 cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l]._spectrum; } 37100 } break; 37101 case 'c' : { 37102 cimglist_for(*this,l) { 37103 res.draw_image((dx-(*this)[l]._width)/2,(dy-(*this)[l]._height)/2,(dz-(*this)[l]._depth)/2,pos,(*this)[l]); 37104 pos+=(*this)[l]._spectrum; 37105 } 37106 } break; 37107 default : { 37108 cimglist_for(*this,l) { 37109 res.draw_image(dx-(*this)[l]._width,dy-(*this)[l]._height,dz-(*this)[l]._depth,pos,(*this)[l]); 37110 pos+=(*this)[l]._spectrum; 37111 } 37112 } 37113 } 37114 } 37115 } 37116 return res; 37117 } 37118 37119 //! Return a list where each image has been split along the specified axis. 37120 CImgList<T>& split(const char axis, const int nb=0) { 37121 return get_split(axis,nb).move_to(*this); 37122 } 37123 37124 CImgList<T> get_split(const char axis, const int nb=0) const { 37125 CImgList<T> res; 37126 cimglist_for(*this,l) _data[l].get_split(axis,nb).move_to(res,~0U); 37127 return res; 37128 } 37129 37130 //! Insert image \p img at the end of the list (STL-compliant name). 37131 template<typename t> 37132 CImgList<T>& push_back(const CImg<t>& img) { 37133 return insert(img); 37134 } 37135 37136 //! Insert image \p img at the front of the list (STL-compliant name). 37137 template<typename t> 37138 CImgList<T>& push_front(const CImg<t>& img) { 37139 return insert(img,0); 37140 } 37141 37142 //! Insert list \p list at the end of the current list (STL-compliant name). 37143 template<typename t> 37144 CImgList<T>& push_back(const CImgList<t>& list) { 37145 return insert(list); 37146 } 37147 37148 //! Insert list \p list at the front of the current list (STL-compliant name). 37149 template<typename t> 37150 CImgList<T>& push_front(const CImgList<t>& list) { 37151 return insert(list,0); 37152 } 37153 37154 //! Remove last element of the list (STL-compliant name). 37155 CImgList<T>& pop_back() { 37156 return remove(_width-1); 37157 } 37158 37159 //! Remove first element of the list (STL-compliant name). 37160 CImgList<T>& pop_front() { 37161 return remove(0); 37162 } 37163 37164 //! Remove the element pointed by iterator \p iter (STL-compliant name). 37165 CImgList<T>& erase(const iterator iter) { 37166 return remove(iter-_data); 37167 } 37168 37169 //@} 37170 //---------------------------------- 37171 // 37172 //! \name Data Input 37173 //@{ 37174 //---------------------------------- 37175 37176 //! Load an image list from a file. 37177 CImgList<T>& load(const char *const filename) { 37178 if (!filename) 37179 throw CImgArgumentException(_cimglist_instance 37180 "load() : Specified filename is (null).", 37181 cimglist_instance); 37182 37183 const char *const ext = cimg::split_filename(filename); 37184 const unsigned int omode = cimg::exception_mode(); 37185 cimg::exception_mode() = 0; 37186 try { 37187 #ifdef cimglist_load_plugin 37188 cimglist_load_plugin(filename); 37189 #endif 37190 #ifdef cimglist_load_plugin1 37191 cimglist_load_plugin1(filename); 37192 #endif 37193 #ifdef cimglist_load_plugin2 37194 cimglist_load_plugin2(filename); 37195 #endif 37196 #ifdef cimglist_load_plugin3 37197 cimglist_load_plugin3(filename); 37198 #endif 37199 #ifdef cimglist_load_plugin4 37200 cimglist_load_plugin4(filename); 37201 #endif 37202 #ifdef cimglist_load_plugin5 37203 cimglist_load_plugin5(filename); 37204 #endif 37205 #ifdef cimglist_load_plugin6 37206 cimglist_load_plugin6(filename); 37207 #endif 37208 #ifdef cimglist_load_plugin7 37209 cimglist_load_plugin7(filename); 37210 #endif 37211 #ifdef cimglist_load_plugin8 37212 cimglist_load_plugin8(filename); 37213 #endif 37214 if (!cimg::strcasecmp(ext,"tif") || 37215 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); 37216 else if (!cimg::strcasecmp(ext,"cimg") || 37217 !cimg::strcasecmp(ext,"cimgz") || 37218 !ext[0]) load_cimg(filename); 37219 else if (!cimg::strcasecmp(ext,"rec") || 37220 !cimg::strcasecmp(ext,"par")) load_parrec(filename); 37221 else if (!cimg::strcasecmp(ext,"avi") || 37222 !cimg::strcasecmp(ext,"mov") || 37223 !cimg::strcasecmp(ext,"asf") || 37224 !cimg::strcasecmp(ext,"divx") || 37225 !cimg::strcasecmp(ext,"flv") || 37226 !cimg::strcasecmp(ext,"mpg") || 37227 !cimg::strcasecmp(ext,"m1v") || 37228 !cimg::strcasecmp(ext,"m2v") || 37229 !cimg::strcasecmp(ext,"m4v") || 37230 !cimg::strcasecmp(ext,"mjp") || 37231 !cimg::strcasecmp(ext,"mkv") || 37232 !cimg::strcasecmp(ext,"mpe") || 37233 !cimg::strcasecmp(ext,"movie") || 37234 !cimg::strcasecmp(ext,"ogm") || 37235 !cimg::strcasecmp(ext,"qt") || 37236 !cimg::strcasecmp(ext,"rm") || 37237 !cimg::strcasecmp(ext,"vob") || 37238 !cimg::strcasecmp(ext,"wmv") || 37239 !cimg::strcasecmp(ext,"xvid") || 37240 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename); 37241 else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); 37242 else throw CImgIOException("CImgList<%s>::load()", 37243 pixel_type()); 37244 } catch (CImgIOException& e) { 37245 if (!cimg::strncasecmp(e.what(),"cimg::fopen()",13)) { 37246 cimg::exception_mode() = omode; 37247 throw CImgIOException(_cimglist_instance 37248 "load() : Failed to open file '%s'.", 37249 cimglist_instance, 37250 filename); 37251 } else try { 37252 assign(1); 37253 _data->load(filename); 37254 } catch (CImgException&) { 37255 throw CImgIOException(_cimglist_instance 37256 "load() : Failed to recognize format of file '%s'.", 37257 cimglist_instance, 37258 filename); 37259 } 37260 } 37261 cimg::exception_mode() = omode; 37262 return *this; 37263 } 37264 37265 static CImgList<T> get_load(const char *const filename) { 37266 return CImgList<T>().load(filename); 37267 } 37268 37269 //! Load an image list from a .cimg file. 37270 CImgList<T>& load_cimg(const char *const filename) { 37271 return _load_cimg(0,filename); 37272 } 37273 37274 static CImgList<T> get_load_cimg(const char *const filename) { 37275 return CImgList<T>().load_cimg(filename); 37276 } 37277 37278 //! Load an image list from a .cimg file. 37279 CImgList<T>& load_cimg(std::FILE *const file) { 37280 return _load_cimg(file,0); 37281 } 37282 37283 static CImgList<T> get_load_cimg(std::FILE *const file) { 37284 return CImgList<T>().load_cimg(file); 37285 } 37286 37287 CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename) { 37288 #ifdef cimg_use_zlib 37289 #define _cimgz_load_cimg_case(Tss) { \ 37290 Bytef *const cbuf = new Bytef[csiz]; \ 37291 cimg::fread(cbuf,csiz,nfile); \ 37292 raw.assign(W,H,D,C); \ 37293 unsigned long destlen = (unsigned long)raw.size()*sizeof(T); \ 37294 uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \ 37295 delete[] cbuf; \ 37296 const Tss *ptrs = raw._data; \ 37297 for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \ 37298 } 37299 #else 37300 #define _cimgz_load_cimg_case(Tss) \ 37301 throw CImgIOException(_cimglist_instance \ 37302 "load_cimg() : Unable to load compressed data from file '%s' unless zlib is enabled.", \ 37303 cimglist_instance, \ 37304 filename?filename:"(FILE*)"); 37305 #endif 37306 37307 #define _cimg_load_cimg_case(Ts,Tss) \ 37308 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ 37309 for (unsigned int l = 0; l<N; ++l) { \ 37310 j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \ 37311 W = H = D = C = 0; csiz = 0; \ 37312 if ((err = std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&C,&csiz))<4) \ 37313 throw CImgIOException(_cimglist_instance \ 37314 "load_cimg() : Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ 37315 cimglist_instance, \ 37316 W,H,D,C,l,filename?filename:("(FILE*)")); \ 37317 if (W*H*D*C>0) { \ 37318 CImg<Tss> raw; \ 37319 CImg<T> &img = _data[l]; \ 37320 img.assign(W,H,D,C); \ 37321 T *ptrd = img._data; \ 37322 if (err==5) _cimgz_load_cimg_case(Tss) \ 37323 else for (int toread = (int)img.size(); toread>0; ) { \ 37324 raw.assign(cimg::min(toread,cimg_iobuffer)); \ 37325 cimg::fread(raw._data,raw._width,nfile); \ 37326 if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ 37327 toread-=raw._width; \ 37328 const Tss *ptrs = raw._data; \ 37329 for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ 37330 } \ 37331 } \ 37332 } \ 37333 loaded = true; \ 37334 } 37335 37336 if (!filename && !file) 37337 throw CImgArgumentException(_cimglist_instance 37338 "load_cimg() : Specified filename is (null).", 37339 cimglist_instance); 37340 37341 const int cimg_iobuffer = 12*1024*1024; 37342 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 37343 bool loaded = false, endian = cimg::endianness(); 37344 char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; 37345 unsigned int j, err, N = 0, W, H, D, C, csiz; 37346 int i; 37347 do { 37348 j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; 37349 } while (*tmp=='#' && i!=EOF); 37350 err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); 37351 if (err<2) { 37352 if (!file) cimg::fclose(nfile); 37353 throw CImgIOException(_cimglist_instance 37354 "load_cimg() : CImg header not found in file '%s'.", 37355 cimglist_instance, 37356 filename?filename:"(FILE*)"); 37357 } 37358 if (!cimg::strncasecmp("little",str_endian,6)) endian = false; 37359 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; 37360 assign(N); 37361 _cimg_load_cimg_case("bool",bool); 37362 _cimg_load_cimg_case("unsigned_char",unsigned char); 37363 _cimg_load_cimg_case("uchar",unsigned char); 37364 _cimg_load_cimg_case("char",char); 37365 _cimg_load_cimg_case("unsigned_short",unsigned short); 37366 _cimg_load_cimg_case("ushort",unsigned short); 37367 _cimg_load_cimg_case("short",short); 37368 _cimg_load_cimg_case("unsigned_int",unsigned int); 37369 _cimg_load_cimg_case("uint",unsigned int); 37370 _cimg_load_cimg_case("int",int); 37371 _cimg_load_cimg_case("unsigned_long",unsigned long); 37372 _cimg_load_cimg_case("ulong",unsigned long); 37373 _cimg_load_cimg_case("long",long); 37374 _cimg_load_cimg_case("float",float); 37375 _cimg_load_cimg_case("double",double); 37376 if (!loaded) { 37377 if (!file) cimg::fclose(nfile); 37378 throw CImgIOException(_cimglist_instance 37379 "load_cimg() : Unsupported pixel type '%s' for file '%s'.", 37380 cimglist_instance, 37381 str_pixeltype,filename?filename:"(FILE*)"); 37382 } 37383 if (!file) cimg::fclose(nfile); 37384 return *this; 37385 } 37386 37387 //! Load a sub-image list from a non compressed .cimg file. 37388 CImgList<T>& load_cimg(const char *const filename, 37389 const unsigned int n0, const unsigned int n1, 37390 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 37391 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { 37392 return _load_cimg(0,filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 37393 } 37394 37395 static CImgList<T> get_load_cimg(const char *const filename, 37396 const unsigned int n0, const unsigned int n1, 37397 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 37398 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { 37399 return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 37400 } 37401 37402 //! Load a sub-image list from a non compressed .cimg file. 37403 CImgList<T>& load_cimg(std::FILE *const file, 37404 const unsigned int n0, const unsigned int n1, 37405 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 37406 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { 37407 return _load_cimg(file,0,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 37408 } 37409 37410 static CImgList<T> get_load_cimg(std::FILE *const file, 37411 const unsigned int n0, const unsigned int n1, 37412 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 37413 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { 37414 return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); 37415 } 37416 37417 CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename, 37418 const unsigned int n0, const unsigned int n1, 37419 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int c0, 37420 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int c1) { 37421 #define _cimg_load_cimg_case2(Ts,Tss) \ 37422 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \ 37423 for (unsigned int l = 0; l<=nn1; ++l) { \ 37424 j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \ 37425 W = H = D = C = 0; \ 37426 if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ 37427 throw CImgIOException(_cimglist_instance \ 37428 "load_cimg() : Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ 37429 cimglist_instance, \ 37430 W,H,D,C,l,filename?filename:"(FILE*)"); \ 37431 if (W*H*D*C>0) { \ 37432 if (l<n0 || x0>=W || y0>=H || z0>=D || c0>=D) std::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ 37433 else { \ 37434 const unsigned int \ 37435 nx1 = x1>=W?W-1:x1, \ 37436 ny1 = y1>=H?H-1:y1, \ 37437 nz1 = z1>=D?D-1:z1, \ 37438 nc1 = c1>=C?C-1:c1; \ 37439 CImg<Tss> raw(1 + nx1 - x0); \ 37440 CImg<T> &img = _data[l - n0]; \ 37441 img.assign(1 + nx1 - x0,1 + ny1 - y0,1 + nz1 - z0,1 + nc1 - c0); \ 37442 T *ptrd = img._data; \ 37443 const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \ 37444 if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \ 37445 for (unsigned int v = 1 + nc1 - c0; v; --v) { \ 37446 const unsigned int skipzb = z0*W*H*sizeof(Tss); \ 37447 if (skipzb) std::fseek(nfile,skipzb,SEEK_CUR); \ 37448 for (unsigned int z = 1 + nz1 - z0; z; --z) { \ 37449 const unsigned int skipyb = y0*W*sizeof(Tss); \ 37450 if (skipyb) std::fseek(nfile,skipyb,SEEK_CUR); \ 37451 for (unsigned int y = 1 + ny1 - y0; y; --y) { \ 37452 const unsigned int skipxb = x0*sizeof(Tss); \ 37453 if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \ 37454 cimg::fread(raw._data,raw._width,nfile); \ 37455 if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ 37456 const Tss *ptrs = raw._data; \ 37457 for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ 37458 const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \ 37459 if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \ 37460 } \ 37461 const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \ 37462 if (skipye) std::fseek(nfile,skipye,SEEK_CUR); \ 37463 } \ 37464 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \ 37465 if (skipze) std::fseek(nfile,skipze,SEEK_CUR); \ 37466 } \ 37467 const unsigned int skipve = (C-1-nc1)*W*H*D*sizeof(Tss); \ 37468 if (skipve) std::fseek(nfile,skipve,SEEK_CUR); \ 37469 } \ 37470 } \ 37471 } \ 37472 loaded = true; \ 37473 } 37474 37475 if (!filename && !file) 37476 throw CImgArgumentException(_cimglist_instance 37477 "load_cimg() : Specified filename is (null).", 37478 cimglist_instance); 37479 37480 if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || c1<c0) 37481 throw CImgArgumentException(_cimglist_instance 37482 "load_cimg() : Invalid specified sub-region coordinates [%u->%u] (%u,%u,%u,%u)->(%u,%u,%u,%u) for file '%s'.", 37483 cimglist_instance, 37484 n0,n1,x0,y0,z0,c0,x1,y1,z1,filename?filename:"(FILE*)"); 37485 37486 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 37487 bool loaded = false, endian = cimg::endianness(); 37488 char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; 37489 unsigned int j, err, N, W, H, D, C; 37490 int i; 37491 j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; 37492 err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); 37493 if (err<2) { 37494 if (!file) cimg::fclose(nfile); 37495 throw CImgIOException(_cimglist_instance 37496 "load_cimg() : CImg header not found in file '%s'.", 37497 cimglist_instance, 37498 filename?filename:"(FILE*)"); 37499 } 37500 if (!cimg::strncasecmp("little",str_endian,6)) endian = false; 37501 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; 37502 const unsigned int nn1 = n1>=N?N-1:n1; 37503 assign(1+nn1-n0); 37504 _cimg_load_cimg_case2("bool",bool); 37505 _cimg_load_cimg_case2("unsigned_char",unsigned char); 37506 _cimg_load_cimg_case2("uchar",unsigned char); 37507 _cimg_load_cimg_case2("char",char); 37508 _cimg_load_cimg_case2("unsigned_short",unsigned short); 37509 _cimg_load_cimg_case2("ushort",unsigned short); 37510 _cimg_load_cimg_case2("short",short); 37511 _cimg_load_cimg_case2("unsigned_int",unsigned int); 37512 _cimg_load_cimg_case2("uint",unsigned int); 37513 _cimg_load_cimg_case2("int",int); 37514 _cimg_load_cimg_case2("unsigned_long",unsigned long); 37515 _cimg_load_cimg_case2("ulong",unsigned long); 37516 _cimg_load_cimg_case2("long",long); 37517 _cimg_load_cimg_case2("float",float); 37518 _cimg_load_cimg_case2("double",double); 37519 if (!loaded) { 37520 if (!file) cimg::fclose(nfile); 37521 throw CImgIOException(_cimglist_instance 37522 "load_cimg() : Unsupported pixel type '%s' for file '%s'.", 37523 cimglist_instance, 37524 str_pixeltype,filename?filename:"(FILE*)"); 37525 } 37526 if (!file) cimg::fclose(nfile); 37527 return *this; 37528 } 37529 37530 //! Load an image list from a PAR/REC (Philips) file. 37531 CImgList<T>& load_parrec(const char *const filename) { 37532 if (!filename) 37533 throw CImgArgumentException(_cimglist_instance 37534 "load_parrec() : Specified filename is (null).", 37535 cimglist_instance); 37536 37537 char body[1024] = { 0 }, filenamepar[1024] = { 0 }, filenamerec[1024] = { 0 }; 37538 const char *const ext = cimg::split_filename(filename,body); 37539 if (!std::strcmp(ext,"par")) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.rec",body); } 37540 if (!std::strcmp(ext,"PAR")) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.REC",body); } 37541 if (!std::strcmp(ext,"rec")) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.par",body); } 37542 if (!std::strcmp(ext,"REC")) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.PAR",body); } 37543 std::FILE *file = cimg::fopen(filenamepar,"r"); 37544 37545 // Parse header file 37546 CImgList<floatT> st_slices; 37547 CImgList<uintT> st_global; 37548 int err; 37549 char line[256] = { 0 }; 37550 do { err=std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.')); 37551 do { 37552 unsigned int sn,sizex,sizey,pixsize; 37553 float rs,ri,ss; 37554 err = std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss); 37555 if (err==7) { 37556 CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0).move_to(st_slices); 37557 unsigned int i; for (i = 0; i<st_global._width && sn<=st_global[i][2]; ++i) {} 37558 if (i==st_global._width) CImg<uintT>::vector(sizex,sizey,sn).move_to(st_global); 37559 else { 37560 CImg<uintT> &vec = st_global[i]; 37561 if (sizex>vec[0]) vec[0] = sizex; 37562 if (sizey>vec[1]) vec[1] = sizey; 37563 vec[2] = sn; 37564 } 37565 st_slices[st_slices._width-1][7] = (float)i; 37566 } 37567 } while (err==7); 37568 37569 // Read data 37570 std::FILE *file2 = cimg::fopen(filenamerec,"rb"); 37571 cimglist_for(st_global,l) { 37572 const CImg<uintT>& vec = st_global[l]; 37573 CImg<T>(vec[0],vec[1],vec[2]).move_to(*this); 37574 } 37575 37576 cimglist_for(st_slices,l) { 37577 const CImg<floatT>& vec = st_slices[l]; 37578 const unsigned int 37579 sn = (unsigned int)vec[0]-1, 37580 pixsize = (unsigned int)vec[1], 37581 sizex = (unsigned int)vec[2], 37582 sizey = (unsigned int)vec[3], 37583 imn = (unsigned int)vec[7]; 37584 const float ri = vec[4], rs = vec[5], ss = vec[6]; 37585 switch (pixsize) { 37586 case 8 : { 37587 CImg<ucharT> buf(sizex,sizey); 37588 cimg::fread(buf._data,sizex*sizey,file2); 37589 if (cimg::endianness()) cimg::invert_endianness(buf._data,sizex*sizey); 37590 CImg<T>& img = (*this)[imn]; 37591 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); 37592 } break; 37593 case 16 : { 37594 CImg<ushortT> buf(sizex,sizey); 37595 cimg::fread(buf._data,sizex*sizey,file2); 37596 if (cimg::endianness()) cimg::invert_endianness(buf._data,sizex*sizey); 37597 CImg<T>& img = (*this)[imn]; 37598 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); 37599 } break; 37600 case 32 : { 37601 CImg<uintT> buf(sizex,sizey); 37602 cimg::fread(buf._data,sizex*sizey,file2); 37603 if (cimg::endianness()) cimg::invert_endianness(buf._data,sizex*sizey); 37604 CImg<T>& img = (*this)[imn]; 37605 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); 37606 } break; 37607 default : 37608 cimg::fclose(file); 37609 cimg::fclose(file2); 37610 throw CImgIOException(_cimglist_instance 37611 "load_parrec() : Unsupported %d-bits pixel type for file '%s'.", 37612 cimglist_instance, 37613 pixsize,filename); 37614 } 37615 } 37616 cimg::fclose(file); 37617 cimg::fclose(file2); 37618 if (!_width) 37619 throw CImgIOException(_cimglist_instance 37620 "load_parrec() : Failed to recognize valid PAR-REC data in file '%s'.", 37621 cimglist_instance, 37622 filename); 37623 return *this; 37624 } 37625 37626 static CImgList<T> get_load_parrec(const char *const filename) { 37627 return CImgList<T>().load_parrec(filename); 37628 } 37629 37630 //! Load an image sequence from a YUV file. 37631 CImgList<T>& load_yuv(const char *const filename, 37632 const unsigned int sizex, const unsigned int sizey, 37633 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37634 const unsigned int step_frame=1, const bool yuv2rgb=true) { 37635 return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb); 37636 } 37637 37638 static CImgList<T> get_load_yuv(const char *const filename, 37639 const unsigned int sizex, const unsigned int sizey=1, 37640 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37641 const unsigned int step_frame=1, const bool yuv2rgb=true) { 37642 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb); 37643 } 37644 37645 //! Load an image sequence from a YUV file. 37646 CImgList<T>& load_yuv(std::FILE *const file, 37647 const unsigned int sizex, const unsigned int sizey, 37648 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37649 const unsigned int step_frame=1, const bool yuv2rgb=true) { 37650 return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb); 37651 } 37652 37653 static CImgList<T> get_load_yuv(std::FILE *const file, 37654 const unsigned int sizex, const unsigned int sizey=1, 37655 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37656 const unsigned int step_frame=1, const bool yuv2rgb=true) { 37657 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb); 37658 } 37659 37660 CImgList<T>& _load_yuv(std::FILE *const file, const char *const filename, 37661 const unsigned int sizex, const unsigned int sizey, 37662 const unsigned int first_frame, const unsigned int last_frame, 37663 const unsigned int step_frame, const bool yuv2rgb) { 37664 if (!filename && !file) 37665 throw CImgArgumentException(_cimglist_instance 37666 "load_yuv() : Specified filename is (null).", 37667 cimglist_instance); 37668 if (sizex%2 || sizey%2) 37669 throw CImgArgumentException(_cimglist_instance 37670 "load_yuv() : Invalid odd XY dimensions %ux%u in file '%s'.", 37671 cimglist_instance, 37672 sizex,sizey,filename?filename:"(FILE*)"); 37673 if (!sizex || !sizey) 37674 throw CImgArgumentException(_cimglist_instance 37675 "load_yuv() : Invalid sequence size (%u,%u) in file '%s'.", 37676 cimglist_instance, 37677 sizex,sizey,filename?filename:"(FILE*)"); 37678 37679 const unsigned int 37680 nfirst_frame = first_frame<last_frame?first_frame:last_frame, 37681 nlast_frame = first_frame<last_frame?last_frame:first_frame, 37682 nstep_frame = step_frame?step_frame:1; 37683 37684 CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2); 37685 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 37686 bool stopflag = false; 37687 int err; 37688 if (nfirst_frame) { 37689 err = std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR); 37690 if (err) { 37691 if (!file) cimg::fclose(nfile); 37692 throw CImgIOException(_cimglist_instance 37693 "load_yuv() : File '%s' doesn't contain frame number %u.", 37694 cimglist_instance, 37695 filename?filename:"(FILE*)",nfirst_frame); 37696 } 37697 } 37698 unsigned int frame; 37699 for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) { 37700 tmp.fill(0); 37701 // *TRY* to read the luminance part, do not replace by cimg::fread ! 37702 err = (int)std::fread((void*)(tmp._data),1,(size_t)(tmp._width*tmp._height),nfile); 37703 if (err!=(int)(tmp._width*tmp._height)) { 37704 stopflag = true; 37705 if (err>0) 37706 cimg::warn(_cimglist_instance 37707 "load_yuv() : File '%s' contains incomplete data or given image dimensions (%u,%u) are incorrect.", 37708 cimglist_instance, 37709 filename?filename:"(FILE*)",sizex,sizey); 37710 } else { 37711 UV.fill(0); 37712 // *TRY* to read the luminance part, do not replace by cimg::fread ! 37713 err = (int)std::fread((void*)(UV._data),1,(size_t)(UV.size()),nfile); 37714 if (err!=(int)(UV.size())) { 37715 stopflag = true; 37716 if (err>0) 37717 cimg::warn(_cimglist_instance 37718 "load_yuv() : File '%s' contains incomplete data or given image dimensions (%u,%u) are incorrect.", 37719 cimglist_instance, 37720 filename?filename:"(FILE*)",sizex,sizey); 37721 } else { 37722 cimg_forXY(UV,x,y) { 37723 const int x2 = x*2, y2 = y*2; 37724 tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0); 37725 tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1); 37726 } 37727 if (yuv2rgb) tmp.YCbCrtoRGB(); 37728 insert(tmp); 37729 if (nstep_frame>1) std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR); 37730 } 37731 } 37732 } 37733 if (stopflag && nlast_frame!=~0U && frame!=nlast_frame) 37734 cimg::warn(_cimglist_instance 37735 "load_yuv() : Frame %d not reached since only %u frames were found in file '%s'.", 37736 cimglist_instance, 37737 nlast_frame,frame-1,filename?filename:"(FILE*)"); 37738 37739 if (!file) cimg::fclose(nfile); 37740 return *this; 37741 } 37742 37743 //! Load an image from a video file, using ffmpeg libraries. 37744 // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net) 37745 // I modified it afterwards for direct inclusion in the library core. 37746 CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37747 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) { 37748 if (!filename) 37749 throw CImgArgumentException(_cimglist_instance 37750 "load_ffmpeg() : Specified filename is (null).", 37751 cimglist_instance); 37752 37753 const unsigned int 37754 nfirst_frame = first_frame<last_frame?first_frame:last_frame, 37755 nlast_frame = first_frame<last_frame?last_frame:first_frame, 37756 nstep_frame = step_frame?step_frame:1; 37757 assign(); 37758 37759 #ifndef cimg_use_ffmpeg 37760 if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format))) 37761 throw CImgArgumentException(_cimglist_instance 37762 "load_ffmpeg() : Unable to load sub-frames from file '%s' unless libffmpeg is enabled.", 37763 cimglist_instance, 37764 filename); 37765 37766 return load_ffmpeg_external(filename); 37767 #else 37768 const PixelFormat ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8; 37769 avcodec_register_all(); 37770 av_register_all(); 37771 static AVFormatContext *format_ctx = 0; 37772 static AVCodecContext *codec_ctx = 0; 37773 static AVCodec *codec = 0; 37774 static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame(); 37775 static int vstream = 0; 37776 37777 if (resume) { 37778 if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame) 37779 throw CImgArgumentException(_cimglist_instance 37780 "load_ffmpeg() : Failed to resume loading of file '%s', due to unallocated FFMPEG structures.", 37781 cimglist_instance, 37782 filename); 37783 } else { 37784 // Open video file, find main video stream and codec. 37785 if (format_ctx) av_close_input_file(format_ctx); 37786 if (av_open_input_file(&format_ctx,filename,0,0,0)!=0) 37787 throw CImgIOException(_cimglist_instance 37788 "load_ffmpeg() : Failed to open file '%s'.", 37789 cimglist_instance, 37790 filename); 37791 37792 if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) { 37793 av_close_input_file(format_ctx); format_ctx = 0; 37794 return load_ffmpeg_external(filename); 37795 } 37796 #if cimg_verbosity>=3 37797 dump_format(format_ctx,0,0,0); 37798 #endif 37799 37800 // Special command : Return informations on main video stream. 37801 // as a vector 1x4 containing : (nb_frames,width,height,fps). 37802 if (!first_frame && !last_frame && !step_frame) { 37803 for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream) 37804 if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break; 37805 if (vstream==(int)format_ctx->nb_streams) assign(); 37806 else { 37807 CImgList<doubleT> timestamps; 37808 int nb_frames; 37809 AVPacket packet; 37810 // Count frames and store timestamps. 37811 for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet)) 37812 if (packet.stream_index==vstream) { 37813 CImg<doubleT>::vector((double)packet.pts).move_to(timestamps); 37814 ++nb_frames; 37815 } 37816 // Get frame with, height and fps. 37817 const int 37818 framew = format_ctx->streams[vstream]->codec->width, 37819 frameh = format_ctx->streams[vstream]->codec->height; 37820 const float 37821 num = (float)(format_ctx->streams[vstream]->r_frame_rate).num, 37822 den = (float)(format_ctx->streams[vstream]->r_frame_rate).den, 37823 fps = num/den; 37824 // Return infos as a list. 37825 assign(2); 37826 (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps); 37827 (*this)[1] = (timestamps>'y'); 37828 } 37829 av_close_input_file(format_ctx); format_ctx = 0; 37830 return *this; 37831 } 37832 37833 for (vstream = 0; vstream<(int)(format_ctx->nb_streams) && 37834 format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream; 37835 if (vstream==(int)format_ctx->nb_streams) { 37836 av_close_input_file(format_ctx); format_ctx = 0; 37837 return load_ffmpeg_external(filename); 37838 } 37839 codec_ctx = format_ctx->streams[vstream]->codec; 37840 codec = avcodec_find_decoder(codec_ctx->codec_id); 37841 if (!codec) { 37842 return load_ffmpeg_external(filename); 37843 } 37844 if (avcodec_open(codec_ctx,codec)<0) { // Open codec 37845 return load_ffmpeg_external(filename); 37846 } 37847 } 37848 37849 // Read video frames 37850 const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height); 37851 uint8_t *const buffer = new uint8_t[numBytes]; 37852 avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height); 37853 const T foo = (T)0; 37854 AVPacket packet; 37855 for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) { 37856 if (packet.stream_index==(int)vstream) { 37857 int decoded = 0; 37858 #if LIBAVCODEC_VERSION_MAJOR<53 37859 avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data, packet.size); 37860 #else 37861 avcodec_decode_video2(codec_ctx,avframe,&decoded,&packet); 37862 #endif 37863 if (decoded) { 37864 if (frame==next_frame) { 37865 SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width, 37866 codec_ctx->height,ffmpeg_pixfmt,1,0,0,0); 37867 sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize); 37868 if (ffmpeg_pixfmt==PIX_FMT_RGB24) { 37869 CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true); 37870 next_image._get_permute_axes("yzcx",foo).move_to(*this); 37871 } else { 37872 CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true); 37873 next_image._get_permute_axes("yzcx",foo).move_to(*this); 37874 } 37875 next_frame+=nstep_frame; 37876 } 37877 ++frame; 37878 } 37879 av_free_packet(&packet); 37880 if (next_frame>nlast_frame) break; 37881 } 37882 } 37883 delete[] buffer; 37884 #endif 37885 return *this; 37886 } 37887 37888 static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37889 const unsigned int step_frame=1, const bool pixel_format=true) { 37890 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format); 37891 } 37892 37893 //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'. 37894 CImgList<T>& load_ffmpeg_external(const char *const filename) { 37895 if (!filename) 37896 throw CImgArgumentException(_cimglist_instance 37897 "load_ffmpeg_external() : Specified filename is (null).", 37898 cimglist_instance); 37899 37900 char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; 37901 std::FILE *file = 0; 37902 do { 37903 std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 37904 std::sprintf(filetmp2,"%s_000001.ppm",filetmp); 37905 if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file); 37906 } while (file); 37907 std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp); 37908 #if cimg_OS!=2 37909 std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2); 37910 #else 37911 std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2); 37912 #endif 37913 cimg::system(command,0); 37914 const unsigned int omode = cimg::exception_mode(); 37915 cimg::exception_mode() = 0; 37916 assign(); 37917 unsigned int i = 1; 37918 for (bool stopflag = false; !stopflag; ++i) { 37919 std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i); 37920 CImg<T> img; 37921 try { img.load_pnm(filetmp2); } 37922 catch (CImgException&) { stopflag = true; } 37923 if (img) { img.move_to(*this); std::remove(filetmp2); } 37924 } 37925 cimg::exception_mode() = omode; 37926 if (is_empty()) 37927 throw CImgIOException(_cimglist_instance 37928 "load_ffmpeg_external() : Failed to open file '%s' with external command 'ffmpeg'.", 37929 cimglist_instance, 37930 filename); 37931 return *this; 37932 } 37933 37934 static CImgList<T> get_load_ffmpeg_external(const char *const filename) { 37935 return CImgList<T>().load_ffmpeg_external(filename); 37936 } 37937 37938 //! Load a gzipped list, using external tool 'gunzip'. 37939 CImgList<T>& load_gzip_external(const char *const filename) { 37940 if (!filename) 37941 throw CImgIOException(_cimglist_instance 37942 "load_gzip_external() : Specified filename is (null).", 37943 cimglist_instance); 37944 37945 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 37946 const char 37947 *ext = cimg::split_filename(filename,body), 37948 *ext2 = cimg::split_filename(body,0); 37949 std::FILE *file = 0; 37950 do { 37951 if (!cimg::strcasecmp(ext,"gz")) { 37952 if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); 37953 else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 37954 } else { 37955 if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); 37956 else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 37957 } 37958 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 37959 } while (file); 37960 std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp); 37961 cimg::system(command); 37962 if (!(file = std::fopen(filetmp,"rb"))) { 37963 cimg::fclose(cimg::fopen(filename,"r")); 37964 throw CImgIOException(_cimglist_instance 37965 "load_gzip_external() : Failed to open file '%s'.", 37966 cimglist_instance, 37967 filename); 37968 37969 } else cimg::fclose(file); 37970 load(filetmp); 37971 std::remove(filetmp); 37972 return *this; 37973 } 37974 37975 static CImgList<T> get_load_gzip_external(const char *const filename) { 37976 return CImgList<T>().load_gzip_external(filename); 37977 } 37978 37979 //! Load a 3d object from a .OFF file. 37980 template<typename tf, typename tc> 37981 CImgList<T>& load_off(const char *const filename, 37982 CImgList<tf>& primitives, CImgList<tc>& colors) { 37983 return get_load_off(filename,primitives,colors).move_to(*this); 37984 } 37985 37986 template<typename tf, typename tc> 37987 static CImgList<T> get_load_off(const char *const filename, 37988 CImgList<tf>& primitives, CImgList<tc>& colors) { 37989 return CImg<T>().load_off(filename,primitives,colors)<'x'; 37990 } 37991 37992 //! Load a TIFF file. 37993 CImgList<T>& load_tiff(const char *const filename, 37994 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 37995 const unsigned int step_frame=1) { 37996 const unsigned int 37997 nfirst_frame = first_frame<last_frame?first_frame:last_frame, 37998 nstep_frame = step_frame?step_frame:1; 37999 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame; 38000 #ifndef cimg_use_tiff 38001 if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1) 38002 throw CImgArgumentException(_cimglist_instance 38003 "load_tiff() : Unable to load sub-images from file '%s' unless libtiff is enabled.", 38004 cimglist_instance, 38005 filename); 38006 38007 return assign(CImg<T>::get_load_tiff(filename)); 38008 #else 38009 TIFF *tif = TIFFOpen(filename,"r"); 38010 if (tif) { 38011 unsigned int nb_images = 0; 38012 do ++nb_images; while (TIFFReadDirectory(tif)); 38013 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) 38014 cimg::warn(_cimglist_instance 38015 "load_tiff() : Invalid specified frame range is [%u,%u] (step %u) since file '%s' contains %u image(s).", 38016 cimglist_instance, 38017 nfirst_frame,nlast_frame,nstep_frame,filename,nb_images); 38018 38019 if (nfirst_frame>=nb_images) return assign(); 38020 if (nlast_frame>=nb_images) nlast_frame = nb_images-1; 38021 assign(1+(nlast_frame-nfirst_frame)/nstep_frame); 38022 TIFFSetDirectory(tif,0); 38023 #if cimg_verbosity>=3 38024 TIFFSetWarningHandler(0); 38025 TIFFSetErrorHandler(0); 38026 #endif 38027 cimglist_for(*this,l) _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame); 38028 TIFFClose(tif); 38029 } else throw CImgException(_cimglist_instance 38030 "load_tiff() : Failed to open file '%s'.", 38031 cimglist_instance, 38032 filename); 38033 return *this; 38034 #endif 38035 } 38036 38037 static CImgList<T> get_load_tiff(const char *const filename, 38038 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 38039 const unsigned int step_frame=1) { 38040 return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame); 38041 } 38042 38043 //@} 38044 //---------------------------------- 38045 // 38046 //! \name Data Output 38047 //@{ 38048 //---------------------------------- 38049 38050 //! Print informations about the list on the standard output. 38051 const CImgList<T>& print(const char *const title=0, const bool display_stats=true) const { 38052 unsigned int msiz = 0; 38053 cimglist_for(*this,l) msiz+=_data[l].size(); 38054 msiz*=sizeof(T); 38055 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2); 38056 char ntitle[64] = { 0 }; 38057 if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type()); 38058 std::fprintf(cimg::output(),"%s: this = %p, size = %u [%u %s], data = (CImg<%s>*)%p", 38059 title?title:ntitle,(void*)this,_width, 38060 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), 38061 mdisp==0?"b":(mdisp==1?"Kb":"Mb"), 38062 pixel_type(),(void*)begin()); 38063 if (_data) std::fprintf(cimg::output(),"..%p.\n",(void*)((char*)end()-1)); 38064 else std::fprintf(cimg::output(),".\n"); 38065 38066 char tmp[16] = { 0 }; 38067 cimglist_for(*this,ll) { 38068 std::sprintf(tmp,"[%d]",ll); 38069 std::fprintf(cimg::output()," "); 38070 _data[ll].print(tmp,display_stats); 38071 if (ll==3 && _width>8) { ll = _width-5; std::fprintf(cimg::output()," ...\n"); } 38072 } 38073 std::fflush(cimg::output()); 38074 return *this; 38075 } 38076 38077 //! Display the current CImgList instance in an existing CImgDisplay window (by reference). 38078 /** 38079 This function displays the list images of the current CImgList instance into an existing CImgDisplay window. 38080 Images of the list are concatenated in a single temporarly image for visualization purposes. 38081 The function returns immediately. 38082 \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed. 38083 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'c'. 38084 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). 38085 \return A reference to the current CImgList instance is returned. 38086 **/ 38087 const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const { 38088 get_append(axis,align).display(disp); 38089 return *this; 38090 } 38091 38092 //! Display the current CImgList instance in a new display window. 38093 /** 38094 This function opens a new window with a specific title and displays the list images of the current CImgList instance into it. 38095 Images of the list are concatenated in a single temporarly image for visualization purposes. 38096 The function returns when a key is pressed or the display window is closed by the user. 38097 \param title : specify the title of the opening display window. 38098 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'c'. 38099 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). 38100 \return A reference to the current CImgList instance is returned. 38101 **/ 38102 const CImgList<T>& display(CImgDisplay &disp, const bool display_info, 38103 const char axis='x', const char align='p') const { 38104 if (is_empty()) 38105 throw CImgInstanceException(_cimglist_instance 38106 "display() : Empty instance.", 38107 cimglist_instance); 38108 38109 const CImg<T> visu = get_append(axis,align); 38110 if (display_info) print(disp.title()); 38111 visu.display(disp,false); 38112 return *this; 38113 } 38114 38115 //! Display the current CImgList instance in a new display window. 38116 const CImgList<T>& display(const char *const title=0, const bool display_info=true, 38117 const char axis='x', const char align='p') const { 38118 const CImg<T> visu = get_append(axis,align); 38119 char ntitle[64] = { 0 }; 38120 if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type()); 38121 if (display_info) print(title?title:ntitle); 38122 visu.display(title?title:ntitle,false); 38123 return *this; 38124 } 38125 38126 //! Save an image list into a file. 38127 /** 38128 Depending on the extension of the given filename, a file format is chosen for the output file. 38129 **/ 38130 const CImgList<T>& save(const char *const filename, const int number=-1) const { 38131 if (!filename) 38132 throw CImgArgumentException(_cimglist_instance 38133 "save() : Specified filename is (null).", 38134 cimglist_instance); 38135 // Do not test for empty instances, since .cimg format is able to manage empty instances. 38136 const char *const ext = cimg::split_filename(filename); 38137 char nfilename[1024] = { 0 }; 38138 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename; 38139 #ifdef cimglist_save_plugin 38140 cimglist_save_plugin(fn); 38141 #endif 38142 #ifdef cimglist_save_plugin1 38143 cimglist_save_plugin1(fn); 38144 #endif 38145 #ifdef cimglist_save_plugin2 38146 cimglist_save_plugin2(fn); 38147 #endif 38148 #ifdef cimglist_save_plugin3 38149 cimglist_save_plugin3(fn); 38150 #endif 38151 #ifdef cimglist_save_plugin4 38152 cimglist_save_plugin4(fn); 38153 #endif 38154 #ifdef cimglist_save_plugin5 38155 cimglist_save_plugin5(fn); 38156 #endif 38157 #ifdef cimglist_save_plugin6 38158 cimglist_save_plugin6(fn); 38159 #endif 38160 #ifdef cimglist_save_plugin7 38161 cimglist_save_plugin7(fn); 38162 #endif 38163 #ifdef cimglist_save_plugin8 38164 cimglist_save_plugin8(fn); 38165 #endif 38166 if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); 38167 else if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false); 38168 else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true); 38169 else if (!cimg::strcasecmp(ext,"avi") || 38170 !cimg::strcasecmp(ext,"mov") || 38171 !cimg::strcasecmp(ext,"asf") || 38172 !cimg::strcasecmp(ext,"divx") || 38173 !cimg::strcasecmp(ext,"flv") || 38174 !cimg::strcasecmp(ext,"mpg") || 38175 !cimg::strcasecmp(ext,"m1v") || 38176 !cimg::strcasecmp(ext,"m2v") || 38177 !cimg::strcasecmp(ext,"m4v") || 38178 !cimg::strcasecmp(ext,"mjp") || 38179 !cimg::strcasecmp(ext,"mkv") || 38180 !cimg::strcasecmp(ext,"mpe") || 38181 !cimg::strcasecmp(ext,"movie") || 38182 !cimg::strcasecmp(ext,"ogm") || 38183 !cimg::strcasecmp(ext,"qt") || 38184 !cimg::strcasecmp(ext,"rm") || 38185 !cimg::strcasecmp(ext,"vob") || 38186 !cimg::strcasecmp(ext,"wmv") || 38187 !cimg::strcasecmp(ext,"xvid") || 38188 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn); 38189 #ifdef cimg_use_tiff 38190 else if (!cimg::strcasecmp(ext,"tif") || 38191 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); 38192 #endif 38193 else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); 38194 else { if (_width==1) _data[0].save(fn,-1); else cimglist_for(*this,l) _data[l].save(fn,l); } 38195 return *this; 38196 } 38197 38198 // Tell if a CImgList can be saved as one single file. 38199 static bool is_saveable(const char *const filename) { 38200 const char *const ext = cimg::split_filename(filename); 38201 if (!cimg::strcasecmp(ext,"cimgz") || 38202 #ifdef cimg_use_tiff 38203 !cimg::strcasecmp(ext,"tif") || 38204 !cimg::strcasecmp(ext,"tiff") || 38205 #endif 38206 !cimg::strcasecmp(ext,"yuv") || 38207 !cimg::strcasecmp(ext,"avi") || 38208 !cimg::strcasecmp(ext,"mov") || 38209 !cimg::strcasecmp(ext,"asf") || 38210 !cimg::strcasecmp(ext,"divx") || 38211 !cimg::strcasecmp(ext,"flv") || 38212 !cimg::strcasecmp(ext,"mpg") || 38213 !cimg::strcasecmp(ext,"m1v") || 38214 !cimg::strcasecmp(ext,"m2v") || 38215 !cimg::strcasecmp(ext,"m4v") || 38216 !cimg::strcasecmp(ext,"mjp") || 38217 !cimg::strcasecmp(ext,"mkv") || 38218 !cimg::strcasecmp(ext,"mpe") || 38219 !cimg::strcasecmp(ext,"movie") || 38220 !cimg::strcasecmp(ext,"ogm") || 38221 !cimg::strcasecmp(ext,"qt") || 38222 !cimg::strcasecmp(ext,"rm") || 38223 !cimg::strcasecmp(ext,"vob") || 38224 !cimg::strcasecmp(ext,"wmv") || 38225 !cimg::strcasecmp(ext,"xvid") || 38226 !cimg::strcasecmp(ext,"mpeg")) return true; 38227 return false; 38228 } 38229 38230 //! Save an image sequence, using FFMPEG library. 38231 // This piece of code has been originally written by David. G. Starkweather. 38232 const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 38233 const unsigned int fps=25) const { 38234 if (!filename) 38235 throw CImgArgumentException(_cimglist_instance 38236 "save_ffmpeg() : Specified filename is (null).", 38237 cimglist_instance); 38238 if (is_empty()) 38239 throw CImgInstanceException(_cimglist_instance 38240 "save_ffmpeg() : Empty instance, for file '%s'.", 38241 cimglist_instance, 38242 filename); 38243 if (!fps) 38244 throw CImgArgumentException(_cimglist_instance 38245 "save_ffmpeg() : Invalid specified framerate 0, for file '%s'.", 38246 cimglist_instance, 38247 filename); 38248 38249 const unsigned int nlast_frame = last_frame==~0U?_width-1:last_frame; 38250 if (first_frame>=_width || nlast_frame>=_width) 38251 throw CImgArgumentException(_cimglist_instance 38252 "save_ffmpeg() : Out of range specified frames [%u,%u], for file '%s'.", 38253 cimglist_instance, 38254 first_frame,last_frame,filename); 38255 38256 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!_data[ll].is_sameXYZ(_data[0])) 38257 throw CImgInstanceException(_cimglist_instance 38258 "save_ffmpeg() : Invalid instance dimensions, for file '%s'.", 38259 cimglist_instance, 38260 filename); 38261 38262 #ifndef cimg_use_ffmpeg 38263 return save_ffmpeg_external(filename,first_frame,last_frame); 38264 #else 38265 avcodec_register_all(); 38266 av_register_all(); 38267 const int 38268 frame_dimx = _data[first_frame].width(), 38269 frame_dimy = _data[first_frame].height(), 38270 frame_dimv = _data[first_frame].spectrum(); 38271 if (frame_dimv!=1 && frame_dimv!=3) 38272 throw CImgInstanceException(_cimglist_instance 38273 "save_ffmpeg() : Image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels, for file '%s'.", 38274 cimglist_instance, 38275 _data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum,_data,filename); 38276 38277 PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P; 38278 PixelFormat src_pxl_fmt = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8; 38279 38280 int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now). 38281 AVOutputFormat *fmt = 0; 38282 fmt = guess_format(0,filename,0); 38283 if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg". 38284 if (!fmt) 38285 throw CImgArgumentException(_cimglist_instance 38286 "save_ffmpeg() : Unable to determine codec for file '%s'.", 38287 cimglist_instance, 38288 filename); 38289 38290 AVFormatContext *oc = 0; 38291 #ifdef LIBAVFORMAT_VERSION_MAJOR 38292 oc = avformat_alloc_context(); 38293 #else 38294 oc = av_alloc_format_context(); 38295 #endif 38296 if (!oc) // Failed to allocate format context. 38297 throw CImgIOException(_cimglist_instance 38298 "save_ffmpeg() : Failed to allocate FFMPEG structure for format context, for file '%s'.", 38299 cimglist_instance, 38300 filename); 38301 38302 AVCodec *codec = 0; 38303 AVFrame *picture = 0; 38304 AVFrame *tmp_pict = 0; 38305 oc->oformat = fmt; 38306 std::sprintf(oc->filename,"%s",filename); 38307 38308 // Add video stream. 38309 int stream_index = 0; 38310 AVStream *video_str = 0; 38311 if (fmt->video_codec!=CODEC_ID_NONE) { 38312 video_str = av_new_stream(oc,stream_index); 38313 if (!video_str) { // Failed to allocate stream. 38314 av_free(oc); 38315 throw CImgIOException(_cimglist_instance 38316 "save_ffmpeg() : Failed to allocate FFMPEG structure for video stream, for file '%s'.", 38317 cimglist_instance, 38318 filename); 38319 } 38320 } else { // No codec identified. 38321 av_free(oc); 38322 throw CImgIOException(_cimglist_instance 38323 "save_ffmpeg() : Failed to identify proper codec, for file '%s'.", 38324 cimglist_instance, 38325 filename); 38326 } 38327 38328 AVCodecContext *c = video_str->codec; 38329 c->codec_id = fmt->video_codec; 38330 c->codec_type = CODEC_TYPE_VIDEO; 38331 c->bit_rate = 400000; 38332 c->width = frame_dimx; 38333 c->height = frame_dimy; 38334 c->time_base.num = 1; 38335 c->time_base.den = fps; 38336 c->gop_size = 12; 38337 c->pix_fmt = dest_pxl_fmt; 38338 if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2; 38339 if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2; 38340 38341 if (av_set_parameters(oc,0)<0) { // Parameters not properly set. 38342 av_free(oc); 38343 throw CImgIOException(_cimglist_instance 38344 "save_ffmpeg() : Invalid parameters set for avcodec, for file '%s'.", 38345 cimglist_instance, 38346 filename); 38347 } 38348 38349 // Open codecs and alloc buffers. 38350 codec = avcodec_find_encoder(c->codec_id); 38351 if (!codec) { // Failed to find codec. 38352 av_free(oc); 38353 throw CImgIOException(_cimglist_instance 38354 "save_ffmpeg() : No valid codec found for file '%s'.", 38355 cimglist_instance, 38356 filename); 38357 } 38358 if (avcodec_open(c,codec)<0) // Failed to open codec. 38359 throw CImgIOException(_cimglist_instance 38360 "save_ffmpeg() : Failed to open codec for file '%s'.", 38361 cimglist_instance, 38362 filename); 38363 38364 tmp_pict = avcodec_alloc_frame(); 38365 if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame. 38366 avcodec_close(video_str->codec); 38367 av_free(oc); 38368 throw CImgIOException(_cimglist_instance 38369 "save_ffmpeg() : Failed to allocate data buffer for file '%s'.", 38370 cimglist_instance, 38371 filename); 38372 } 38373 tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx; 38374 tmp_pict->type = FF_BUFFER_TYPE_USER; 38375 int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy); 38376 uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size); 38377 if (!tmp_buffer) { // Failed to allocate memory for tmp buffer. 38378 av_free(tmp_pict); 38379 avcodec_close(video_str->codec); 38380 av_free(oc); 38381 throw CImgIOException(_cimglist_instance 38382 "save_ffmpeg() : Failed to allocate data buffer for file '%s'.", 38383 cimglist_instance, 38384 filename); 38385 } 38386 38387 // Associate buffer with tmp_pict. 38388 avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy); 38389 picture = avcodec_alloc_frame(); 38390 if (!picture) { // Failed to allocate picture frame. 38391 av_free(tmp_pict->data[0]); 38392 av_free(tmp_pict); 38393 avcodec_close(video_str->codec); 38394 av_free(oc); 38395 throw CImgIOException(_cimglist_instance 38396 "save_ffmpeg() : Failed to allocate data buffer for file '%s'.", 38397 cimglist_instance, 38398 filename); 38399 } 38400 38401 int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy); 38402 uint8_t *buffer = (uint8_t*)av_malloc(size); 38403 if (!buffer) { // Failed to allocate picture frame buffer. 38404 av_free(picture); 38405 av_free(tmp_pict->data[0]); 38406 av_free(tmp_pict); 38407 avcodec_close(video_str->codec); 38408 av_free(oc); 38409 throw CImgIOException(_cimglist_instance 38410 "save_ffmpeg() : Failed to allocate data buffer for file '%s'.", 38411 cimglist_instance, 38412 filename); 38413 } 38414 38415 // Associate the buffer with picture. 38416 avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy); 38417 38418 // Open file. 38419 if (!(fmt->flags&AVFMT_NOFILE)) { 38420 if (url_fopen(&oc->pb,filename,URL_WRONLY)<0) 38421 throw CImgIOException(_cimglist_instance 38422 "save_ffmpeg() : Failed to open file '%s'.", 38423 cimglist_instance, 38424 filename); 38425 } 38426 38427 if (av_write_header(oc)<0) 38428 throw CImgIOException(_cimglist_instance 38429 "save_ffmpeg() : Failed to write header in file '%s'.", 38430 cimglist_instance, 38431 filename); 38432 38433 double video_pts; 38434 SwsContext *img_convert_context = 0; 38435 img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt, 38436 c->width,c->height,c->pix_fmt,sws_flags,0,0,0); 38437 if (!img_convert_context) { // Failed to get swscale context. 38438 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb); 38439 av_free(picture->data); 38440 av_free(picture); 38441 av_free(tmp_pict->data[0]); 38442 av_free(tmp_pict); 38443 avcodec_close(video_str->codec); 38444 av_free(oc); 38445 throw CImgIOException(_cimglist_instance 38446 "save_ffmpeg() : Failed to get conversion context for file '%s'.", 38447 cimglist_instance, 38448 filename); 38449 } 38450 int ret = 0, out_size; 38451 uint8_t *video_outbuf = 0; 38452 int video_outbuf_size = 1000000; 38453 video_outbuf = (uint8_t*)av_malloc(video_outbuf_size); 38454 if (!video_outbuf) { 38455 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb); 38456 av_free(picture->data); 38457 av_free(picture); 38458 av_free(tmp_pict->data[0]); 38459 av_free(tmp_pict); 38460 avcodec_close(video_str->codec); 38461 av_free(oc); 38462 throw CImgIOException(_cimglist_instance 38463 "save_ffmpeg() : Failed to allocate buffer memory, for file '%s'.", 38464 cimglist_instance, 38465 filename); 38466 } 38467 38468 // Loop through each desired image in list. 38469 for (unsigned int i = first_frame; i<=nlast_frame; ++i) { 38470 CImg<uint8_t> currentIm = _data[i], red, green, blue, gray; 38471 if (src_pxl_fmt == PIX_FMT_RGB24) { 38472 red = currentIm.get_shared_channel(0); 38473 green = currentIm.get_shared_channel(1); 38474 blue = currentIm.get_shared_channel(2); 38475 cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format. 38476 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X] = red(X,Y); 38477 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y); 38478 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y); 38479 } 38480 } else { 38481 gray = currentIm.get_shared_channel(0); 38482 cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y); 38483 } 38484 38485 if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den); 38486 else video_pts = 0.0; 38487 if (!video_str) break; 38488 if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break; 38489 out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture); 38490 if (out_size>0) { 38491 AVPacket pkt; 38492 av_init_packet(&pkt); 38493 pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base); 38494 if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY; 38495 pkt.stream_index = video_str->index; 38496 pkt.data = video_outbuf; 38497 pkt.size = out_size; 38498 ret = av_write_frame(oc,&pkt); 38499 } else if (out_size<0) break; 38500 if (ret) break; // Error occured in writing frame. 38501 } 38502 38503 // Close codec. 38504 if (video_str) { 38505 avcodec_close(video_str->codec); 38506 av_free(picture->data[0]); 38507 av_free(picture); 38508 av_free(tmp_pict->data[0]); 38509 av_free(tmp_pict); 38510 } 38511 if (av_write_trailer(oc)<0) 38512 throw CImgIOException(_cimglist_instance 38513 "save_ffmpeg() : Failed to write trailer for file '%s'.", 38514 cimglist_instance, 38515 filename); 38516 38517 av_freep(&oc->streams[stream_index]->codec); 38518 av_freep(&oc->streams[stream_index]); 38519 if (!(fmt->flags&AVFMT_NOFILE)) { 38520 /*if (url_fclose(oc->pb)<0) 38521 throw CImgIOException(_cimglist_instance 38522 "save_ffmpeg() : File '%s', failed to close file.", 38523 cimglist_instance, 38524 filename); 38525 */ 38526 } 38527 av_free(oc); 38528 av_free(video_outbuf); 38529 #endif 38530 return *this; 38531 } 38532 38533 // Save an image sequence into a YUV file (internal). 38534 const CImgList<T>& _save_yuv(std::FILE *const file, const char *const filename, const bool rgb2yuv) const { 38535 if (!file && !filename) 38536 throw CImgArgumentException(_cimglist_instance 38537 "save_yuv() : Specified filename is (null).", 38538 cimglist_instance); 38539 if (is_empty()) 38540 throw CImgInstanceException(_cimglist_instance 38541 "save_yuv() : Empty instance, for file '%s'.", 38542 cimglist_instance, 38543 filename?filename:"(FILE*)"); 38544 38545 if ((*this)[0].width()%2 || (*this)[0].height()%2) 38546 throw CImgInstanceException(_cimglist_instance 38547 "save_yuv() : Invalid odd instance dimensions (%u,%u) for file '%s'.", 38548 cimglist_instance, 38549 (*this)[0].width(),(*this)[0].height(), 38550 filename?filename:"(FILE*)"); 38551 38552 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 38553 cimglist_for(*this,l) { 38554 CImg<ucharT> YCbCr((*this)[l]); 38555 if (rgb2yuv) YCbCr.RGBtoYCbCr(); 38556 cimg::fwrite(YCbCr._data,YCbCr._width*YCbCr._height,nfile); 38557 cimg::fwrite(YCbCr.get_resize(YCbCr._width/2, YCbCr._height/2,1,3,3).data(0,0,0,1), 38558 YCbCr._width*YCbCr._height/2,nfile); 38559 } 38560 if (!file) cimg::fclose(nfile); 38561 return *this; 38562 } 38563 38564 //! Save an image sequence into a YUV file. 38565 const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const { 38566 return _save_yuv(0,filename,rgb2yuv); 38567 } 38568 38569 //! Save an image sequence into a YUV file. 38570 const CImgList<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const { 38571 return _save_yuv(file,0,rgb2yuv); 38572 } 38573 38574 //! Save an image list into a .cimg file. 38575 /** 38576 A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images. 38577 \param filename : name of the output file. 38578 \return A reference to the current CImgList instance is returned. 38579 **/ 38580 const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, const bool compression) const { 38581 if (!file && !filename) 38582 throw CImgArgumentException(_cimglist_instance 38583 "save_cimg() : Specified filename is (null).", 38584 cimglist_instance); 38585 #ifndef cimg_use_zlib 38586 if (compression) 38587 cimg::warn(_cimglist_instance 38588 "save_cimg() : Unable to save compressed data in file '%s' unless zlib is enabled, saving them uncompressed.", 38589 cimglist_instance, 38590 filename?filename:"(FILE*)"); 38591 #endif 38592 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 38593 const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; 38594 if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",_width,ptype+9,etype); 38595 else std::fprintf(nfile,"%u %s %s_endian\n",_width,ptype,etype); 38596 cimglist_for(*this,l) { 38597 const CImg<T>& img = _data[l]; 38598 std::fprintf(nfile,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); 38599 if (img._data) { 38600 CImg<T> tmp; 38601 if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } 38602 const CImg<T>& ref = cimg::endianness()?tmp:img; 38603 bool compressed = false; 38604 if (compression) { 38605 #ifdef cimg_use_zlib 38606 const unsigned long siz = sizeof(T)*ref.size(); 38607 unsigned long csiz = siz + siz/100 + 16; 38608 Bytef *const cbuf = new Bytef[csiz]; 38609 if (compress(cbuf,&csiz,(Bytef*)ref._data,siz)) { 38610 cimg::warn(_cimglist_instance 38611 "save_cimg() : Failed to save compressed data for file '%s', saving them uncompressed.", 38612 cimglist_instance, 38613 filename?filename:"(FILE*)"); 38614 38615 compressed = false; 38616 } else { 38617 std::fprintf(nfile," #%lu\n",csiz); 38618 cimg::fwrite(cbuf,csiz,nfile); 38619 delete[] cbuf; 38620 compressed = true; 38621 } 38622 #else 38623 compressed = false; 38624 #endif 38625 } 38626 if (!compressed) { 38627 std::fputc('\n',nfile); 38628 cimg::fwrite(ref._data,ref.size(),nfile); 38629 } 38630 } else std::fputc('\n',nfile); 38631 } 38632 if (!file) cimg::fclose(nfile); 38633 return *this; 38634 } 38635 38636 //! Save an image list into a CImg file (RAW binary file + simple header) 38637 const CImgList<T>& save_cimg(std::FILE *file, const bool compress=false) const { 38638 return _save_cimg(file,0,compress); 38639 } 38640 38641 //! Save an image list into a CImg file (RAW binary file + simple header) 38642 const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const { 38643 return _save_cimg(0,filename,compress); 38644 } 38645 38646 // Insert the instance image into into an existing .cimg file, at specified coordinates. 38647 const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, 38648 const unsigned int n0, 38649 const unsigned int x0, const unsigned int y0, 38650 const unsigned int z0, const unsigned int c0) const { 38651 #define _cimg_save_cimg_case(Ts,Tss) \ 38652 if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \ 38653 for (unsigned int l = 0; l<lmax; ++l) { \ 38654 j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \ 38655 W = H = D = C = 0; \ 38656 if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ 38657 throw CImgIOException(_cimglist_instance \ 38658 "save_cimg() : Invalid size (%u,%u,%u,%u) of image[%u], for file '%s'.", \ 38659 cimglist_instance, \ 38660 W,H,D,C,l,filename?filename:"(FILE*)"); \ 38661 if (W*H*D*C>0) { \ 38662 if (l<n0 || x0>=W || y0>=H || z0>=D || c0>=D) std::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ 38663 else { \ 38664 const CImg<T>& img = (*this)[l - n0]; \ 38665 const T *ptrs = img._data; \ 38666 const unsigned int \ 38667 x1 = x0 + img._width - 1, \ 38668 y1 = y0 + img._height - 1, \ 38669 z1 = z0 + img._depth - 1, \ 38670 c1 = c0 + img._spectrum - 1, \ 38671 nx1 = x1>=W?W-1:x1, \ 38672 ny1 = y1>=H?H-1:y1, \ 38673 nz1 = z1>=D?D-1:z1, \ 38674 nc1 = c1>=C?C-1:c1; \ 38675 CImg<Tss> raw(1+nx1-x0); \ 38676 const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \ 38677 if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \ 38678 for (unsigned int v = 1 + nc1 - c0; v; --v) { \ 38679 const unsigned int skipzb = z0*W*H*sizeof(Tss); \ 38680 if (skipzb) std::fseek(nfile,skipzb,SEEK_CUR); \ 38681 for (unsigned int z = 1 + nz1 - z0; z; --z) { \ 38682 const unsigned int skipyb = y0*W*sizeof(Tss); \ 38683 if (skipyb) std::fseek(nfile,skipyb,SEEK_CUR); \ 38684 for (unsigned int y = 1 + ny1 - y0; y; --y) { \ 38685 const unsigned int skipxb = x0*sizeof(Tss); \ 38686 if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \ 38687 raw.assign(ptrs, raw._width); \ 38688 ptrs+=img._width; \ 38689 if (endian) cimg::invert_endianness(raw._data,raw._width); \ 38690 cimg::fwrite(raw._data,raw._width,nfile); \ 38691 const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \ 38692 if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \ 38693 } \ 38694 const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \ 38695 if (skipye) std::fseek(nfile,skipye,SEEK_CUR); \ 38696 } \ 38697 const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \ 38698 if (skipze) std::fseek(nfile,skipze,SEEK_CUR); \ 38699 } \ 38700 const unsigned int skipve = (C - 1 - nc1)*W*H*D*sizeof(Tss); \ 38701 if (skipve) std::fseek(nfile,skipve,SEEK_CUR); \ 38702 } \ 38703 } \ 38704 } \ 38705 saved = true; \ 38706 } 38707 38708 if (!file && !filename) 38709 throw CImgArgumentException(_cimglist_instance 38710 "save_cimg() : Specified filename is (null).", 38711 cimglist_instance); 38712 if (is_empty()) 38713 throw CImgInstanceException(_cimglist_instance 38714 "save_cimg() : Empty instance, for file '%s'.", 38715 cimglist_instance, 38716 filename?filename:"(FILE*)"); 38717 38718 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+"); 38719 bool saved = false, endian = cimg::endianness(); 38720 char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 }; 38721 unsigned int j, err, N, W, H, D, C; 38722 int i; 38723 j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; 38724 err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian); 38725 if (err<2) { 38726 if (!file) cimg::fclose(nfile); 38727 throw CImgIOException(_cimglist_instance 38728 "save_cimg() : CImg header not found in file '%s'.", 38729 cimglist_instance, 38730 filename?filename:"(FILE*)"); 38731 } 38732 if (!cimg::strncasecmp("little",str_endian,6)) endian = false; 38733 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; 38734 const unsigned int lmax = cimg::min(N,n0+_width); 38735 _cimg_save_cimg_case("bool",bool); 38736 _cimg_save_cimg_case("unsigned_char",unsigned char); 38737 _cimg_save_cimg_case("uchar",unsigned char); 38738 _cimg_save_cimg_case("char",char); 38739 _cimg_save_cimg_case("unsigned_short",unsigned short); 38740 _cimg_save_cimg_case("ushort",unsigned short); 38741 _cimg_save_cimg_case("short",short); 38742 _cimg_save_cimg_case("unsigned_int",unsigned int); 38743 _cimg_save_cimg_case("uint",unsigned int); 38744 _cimg_save_cimg_case("int",int); 38745 _cimg_save_cimg_case("unsigned_long",unsigned long); 38746 _cimg_save_cimg_case("ulong",unsigned long); 38747 _cimg_save_cimg_case("long",long); 38748 _cimg_save_cimg_case("float",float); 38749 _cimg_save_cimg_case("double",double); 38750 if (!saved) { 38751 if (!file) cimg::fclose(nfile); 38752 throw CImgIOException(_cimglist_instance 38753 "save_cimg() : Unsupported data type '%s' for file '%s'.", 38754 cimglist_instance, 38755 filename?filename:"(FILE*)",str_pixeltype); 38756 } 38757 if (!file) cimg::fclose(nfile); 38758 return *this; 38759 } 38760 38761 //! Insert the instance image into into an existing .cimg file, at specified coordinates. 38762 const CImgList<T>& save_cimg(const char *const filename, 38763 const unsigned int n0, 38764 const unsigned int x0, const unsigned int y0, 38765 const unsigned int z0, const unsigned int c0) const { 38766 return _save_cimg(0,filename,n0,x0,y0,z0,c0); 38767 } 38768 38769 //! Insert the instance image into into an existing .cimg file, at specified coordinates. 38770 const CImgList<T>& save_cimg(std::FILE *const file, 38771 const unsigned int n0, 38772 const unsigned int x0, const unsigned int y0, 38773 const unsigned int z0, const unsigned int c0) const { 38774 return _save_cimg(file,0,n0,x0,y0,z0,c0); 38775 } 38776 38777 // Create an empty .cimg file with specified dimensions (internal) 38778 static void _save_empty_cimg(std::FILE *const file, const char *const filename, 38779 const unsigned int nb, 38780 const unsigned int dx, const unsigned int dy, 38781 const unsigned int dz, const unsigned int dc) { 38782 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 38783 const unsigned int siz = dx*dy*dz*dc*sizeof(T); 38784 std::fprintf(nfile,"%u %s\n",nb,pixel_type()); 38785 for (unsigned int i=nb; i; --i) { 38786 std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dc); 38787 for (unsigned int off=siz; off; --off) std::fputc(0,nfile); 38788 } 38789 if (!file) cimg::fclose(nfile); 38790 } 38791 38792 //! Create an empty .cimg file with specified dimensions. 38793 static void save_empty_cimg(const char *const filename, 38794 const unsigned int nb, 38795 const unsigned int dx, const unsigned int dy=1, 38796 const unsigned int dz=1, const unsigned int dc=1) { 38797 return _save_empty_cimg(0,filename,nb,dx,dy,dz,dc); 38798 } 38799 38800 //! Create an empty .cimg file with specified dimensions. 38801 static void save_empty_cimg(std::FILE *const file, 38802 const unsigned int nb, 38803 const unsigned int dx, const unsigned int dy=1, 38804 const unsigned int dz=1, const unsigned int dc=1) { 38805 return _save_empty_cimg(file,0,nb,dx,dy,dz,dc); 38806 } 38807 38808 //! Save a file in TIFF format. 38809 #ifdef cimg_use_tiff 38810 const CImgList<T>& save_tiff(const char *const filename) const { 38811 if (!filename) 38812 throw CImgArgumentException(_cimglist_instance 38813 "save_tiff() : Specified filename is (null).", 38814 cimglist_instance); 38815 if (is_empty()) 38816 throw CImgInstanceException(_cimglist_instance 38817 "save_tiff() : Empty instance, for file '%s'.", 38818 cimglist_instance, 38819 filename); 38820 38821 TIFF *tif = TIFFOpen(filename,"w"); 38822 if (tif) { 38823 for (unsigned int dir = 0, l = 0; l<_width; ++l) { 38824 const CImg<T>& img = (*this)[l]; 38825 if (img) { 38826 if (img._depth==1) img._save_tiff(tif,dir++); 38827 else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++); 38828 } 38829 } 38830 TIFFClose(tif); 38831 } else 38832 throw CImgException(_cimglist_instance 38833 "save_tiff() : Failed to open stream for file '%s'.", 38834 cimglist_instance, 38835 filename); 38836 return *this; 38837 } 38838 #endif 38839 38840 //! Save an image list as a gzipped file, using external tool 'gzip'. 38841 const CImgList<T>& save_gzip_external(const char *const filename) const { 38842 if (!filename) 38843 throw CImgIOException(_cimglist_instance 38844 "save_gzip_external() : Specified filename is (null).", 38845 cimglist_instance); 38846 38847 char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 }; 38848 const char 38849 *ext = cimg::split_filename(filename,body), 38850 *ext2 = cimg::split_filename(body,0); 38851 std::FILE *file; 38852 do { 38853 if (!cimg::strcasecmp(ext,"gz")) { 38854 if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); 38855 else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 38856 } else { 38857 if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); 38858 else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 38859 } 38860 if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); 38861 } while (file); 38862 38863 if (is_saveable(body)) { 38864 save(filetmp); 38865 std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename); 38866 cimg::system(command); 38867 file = std::fopen(filename,"rb"); 38868 if (!file) 38869 throw CImgIOException(_cimglist_instance 38870 "save_gzip_external() : Failed to save file '%s' with external command 'gzip'.", 38871 cimglist_instance, 38872 filename); 38873 else cimg::fclose(file); 38874 std::remove(filetmp); 38875 } else { 38876 char nfilename[1024] = { 0 }; 38877 cimglist_for(*this,l) { 38878 cimg::number_filename(body,l,6,nfilename); 38879 if (*ext) std::sprintf(nfilename+std::strlen(nfilename),".%s",ext); 38880 _data[l].save_gzip_external(nfilename); 38881 } 38882 } 38883 return *this; 38884 } 38885 38886 //! Save an image sequence using the external tool 'ffmpeg'. 38887 const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, 38888 const char *const codec="mpeg2video") const { 38889 if (!filename) 38890 throw CImgArgumentException(_cimglist_instance 38891 "save_ffmpeg_external() : Specified filename is (null).", 38892 cimglist_instance); 38893 if (is_empty()) 38894 throw CImgInstanceException(_cimglist_instance 38895 "save_ffmpeg_external() : Empty instance, for file '%s'.", 38896 cimglist_instance, 38897 filename); 38898 38899 char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 }; 38900 std::FILE *file = 0; 38901 const unsigned int nlast_frame = last_frame==~0U?_width-1:last_frame; 38902 if (first_frame>=_width || nlast_frame>=_width) 38903 throw CImgArgumentException(_cimglist_instance 38904 "save_ffmpeg_external() : Out of range specified frames [%u,%u] for file '%s'.", 38905 cimglist_instance, 38906 filename,first_frame,last_frame); 38907 38908 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!_data[ll].is_sameXYZ(_data[0])) 38909 throw CImgInstanceException(_cimglist_instance 38910 "save_ffmpeg_external() : Invalid instance dimensions for file '%s'.", 38911 cimglist_instance, 38912 filename); 38913 do { 38914 std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); 38915 std::sprintf(filetmp2,"%s_000001.ppm",filetmp); 38916 if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file); 38917 } while (file); 38918 for (unsigned int l = first_frame; l<=nlast_frame; ++l) { 38919 std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1); 38920 if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2); 38921 else _data[l].save_pnm(filetmp2); 38922 } 38923 #if cimg_OS!=2 38924 std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename); 38925 #else 38926 std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename); 38927 #endif 38928 38929 cimg::system(command); 38930 file = std::fopen(filename,"rb"); 38931 if (!file) 38932 throw CImgIOException(_cimglist_instance 38933 "save_ffmpeg_external() : Failed to save file '%s' with external command 'ffmpeg'.", 38934 cimglist_instance, 38935 filename); 38936 38937 else cimg::fclose(file); 38938 cimglist_for(*this,lll) { std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); std::remove(filetmp2); } 38939 38940 return *this; 38941 } 38942 38943 //@} 38944 //---------------------------------- 38945 // 38946 //! \name Others 38947 //@{ 38948 //---------------------------------- 38949 38950 //! Create an auto-cropped font (along the X axis) from a input font \p font. 38951 CImgList<T>& crop_font() { 38952 return get_crop_font().move_to(*this); 38953 } 38954 38955 CImgList<T> get_crop_font() const { 38956 CImgList<T> res; 38957 cimglist_for(*this,l) { 38958 const CImg<T>& letter = (*this)[l]; 38959 int xmin = letter._width, xmax = 0; 38960 cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin = x; if (x>xmax) xmax = x; } 38961 if (xmin>xmax) CImg<T>(letter._width,letter._height,1,letter._spectrum,0).move_to(res); 38962 else letter.get_crop(xmin,0,xmax,letter._height-1).move_to(res); 38963 } 38964 res[' '].resize(res['f']._width,-100,-100,-100,0); 38965 res[' '+256].resize(res['f']._width,-100,-100,-100,0); 38966 return res; 38967 } 38968 38969 38970 //! Return a CImg pre-defined font with desired size. 38971 /** 38972 \param font_height = height of the desired font (exact match for 11,13,17,19,24,32,38,57) 38973 \param fixed_size = tell if the font has a fixed or variable width. 38974 **/ 38975 static const CImgList<T>& font(const unsigned int font_height, const bool variable_size=true) { 38976 38977 #define _cimg_font(sx,sy) \ 38978 if (!variable_size && (!font || font[0]._height!=sy)) font = _font(cimg::font##sx##x##sy,sx,sy,false); \ 38979 if (variable_size && (!vfont || vfont[0]._height!=sy)) vfont = _font(cimg::font##sx##x##sy,sx,sy,true); \ 38980 if (font_height==sy) return variable_size?vfont:font; \ 38981 if (variable_size) { \ 38982 if (cvfont && font_height==cvfont[0]._height) return cvfont; \ 38983 cvfont = vfont; \ 38984 cimglist_for(cvfont,l) \ 38985 cvfont[l].resize(cimg::max(1U,cvfont[l]._width*font_height/cvfont[l]._height),font_height,-100,-100, \ 38986 cvfont[0]._height>font_height?2:5); \ 38987 return cvfont; \ 38988 } else { \ 38989 if (cfont && font_height==cfont[0]._height) return cfont; \ 38990 cfont = font; \ 38991 cimglist_for(cfont,l) \ 38992 cfont[l].resize(cimg::max(1U,cfont[l]._width*font_height/cfont[l]._height),font_height,-100,-100, \ 38993 cfont[0]._height>font_height?2:5); \ 38994 return cfont; \ 38995 } \ 38996 38997 static CImgList<T> font, vfont, cfont, cvfont; 38998 if (!font_height) return CImgList<T>::empty(); 38999 if (font_height<=13) { _cimg_font(10,13); } // [1,13] -> ref 13 39000 if (font_height<=28) { _cimg_font(12,24); } // [14,28] -> ref 24 39001 if (font_height<=32) { _cimg_font(16,32); } // [29,32] -> ref 32 39002 _cimg_font(29,57); // [33,+inf] -> ref 57 39003 } 39004 39005 static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h, const bool variable_size) { 39006 CImgList<T> res = CImgList<T>(256,w,h,1,3); 39007 res.insert(256); cimglist_for_in(res,256,511,l) res[l].assign(w,h,1,1); 39008 const unsigned int *ptr = font; 39009 unsigned int m = 0, val = 0; 39010 for (unsigned int y = 0; y<h; ++y) 39011 for (unsigned int x = 0; x<256*w; ++x) { 39012 m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); } 39013 CImg<T>& img = res[x/w], &mask = res[x/w+256]; 39014 unsigned int xm = x%w; 39015 img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0); 39016 } 39017 if (variable_size) res.crop_font(); 39018 return res; 39019 } 39020 39021 //! Compute a 1-D Fast Fourier Transform, along specified axis. 39022 CImgList<T>& FFT(const char axis, const bool invert=false) { 39023 if (is_empty()) return *this; 39024 if (_width==1) insert(1); 39025 if (_width>2) 39026 cimg::warn(_cimglist_instance 39027 "FFT() : Instance has more than 2 images", 39028 cimglist_instance); 39029 39030 CImg<T>::FFT(_data[0],_data[1],axis,invert); 39031 return *this; 39032 } 39033 39034 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const { 39035 return CImgList<Tfloat>(*this,false).FFT(axis,invert); 39036 } 39037 39038 //! Compute a n-d Fast Fourier Transform. 39039 CImgList<T>& FFT(const bool invert=false) { 39040 if (is_empty()) return *this; 39041 if (_width==1) insert(1); 39042 if (_width>2) 39043 cimg::warn(_cimglist_instance 39044 "FFT() : Instance has more than 2 images", 39045 cimglist_instance); 39046 39047 CImg<T>::FFT(_data[0],_data[1],invert); 39048 return *this; 39049 } 39050 39051 CImgList<Tfloat> get_FFT(const bool invert=false) const { 39052 return CImgList<Tfloat>(*this,false).FFT(invert); 39053 } 39054 39055 //! Invert primitives orientation of a 3d object. 39056 CImgList<T>& reverse_object3d() { 39057 cimglist_for(*this,l) { 39058 CImg<T>& p = _data[l]; 39059 const unsigned int siz = p.size(); 39060 if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]); 39061 else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]); 39062 } 39063 return *this; 39064 } 39065 39066 CImgList<T> get_reverse_object3d() const { 39067 return (+*this).reverse_object3d(); 39068 } 39069 39070 //@} 39071 }; 39072 39073 /* 39074 #--------------------------------------------- 39075 # 39076 # Completion of previously declared functions 39077 # 39078 #---------------------------------------------- 39079 */ 39080 39081 namespace cimg { 39082 39083 //! Display a dialog box, where a user can click standard buttons. 39084 /** 39085 Up to 6 buttons can be defined in the dialog window. 39086 This function returns when a user clicked one of the button or closed the dialog window. 39087 \param title = Title of the dialog window. 39088 \param msg = Main message displayed inside the dialog window. 39089 \param button1_label = Label of the 1st button. 39090 \param button2_label = Label of the 2nd button. 39091 \param button3_label = Label of the 3rd button. 39092 \param button4_label = Label of the 4th button. 39093 \param button5_label = Label of the 5th button. 39094 \param button6_label = Label of the 6th button. 39095 \param logo = Logo image displayed at the left of the main message. This parameter is optional. 39096 \param centering = Tell to center the dialog window on the screen. 39097 \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user. 39098 \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in 39099 the dialog box. At least one button is necessary. 39100 **/ 39101 template<typename t> 39102 inline int dialog(const char *const title, const char *const msg, 39103 const char *const button1_label, const char *const button2_label, 39104 const char *const button3_label, const char *const button4_label, 39105 const char *const button5_label, const char *const button6_label, 39106 const CImg<t>& logo, const bool centering = false) { 39107 #if cimg_display==0 39108 cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label,logo._data,centering); 39109 throw CImgDisplayException("cimg::dialog() : No display available."); 39110 #else 39111 const unsigned char 39112 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 }; 39113 39114 // Create buttons and canvas graphics 39115 CImgList<unsigned char> buttons, cbuttons, sbuttons; 39116 if (button1_label) { CImg<unsigned char>().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons); 39117 if (button2_label) { CImg<unsigned char>().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons); 39118 if (button3_label) { CImg<unsigned char>().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons); 39119 if (button4_label) { CImg<unsigned char>().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons); 39120 if (button5_label) { CImg<unsigned char>().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons); 39121 if (button6_label) { CImg<unsigned char>().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons); 39122 }}}}}} 39123 if (!buttons._width) 39124 throw CImgArgumentException("cimg::dialog() : No buttons have been defined."); 39125 39126 unsigned int bw = 0, bh = 0; 39127 cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l]._width); bh = cimg::max(bh,buttons[l]._height); } 39128 bw+=8; bh+=8; 39129 if (bw<64) bw=64; 39130 if (bw>128) bw=128; 39131 if (bh<24) bh=24; 39132 if (bh>48) bh=48; 39133 39134 CImg<unsigned char> button(bw,bh,1,3); 39135 button.draw_rectangle(0,0,bw-1,bh-1,gray); 39136 button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white); 39137 button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black); 39138 button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2); 39139 CImg<unsigned char> sbutton(bw,bh,1,3); 39140 sbutton.draw_rectangle(0,0,bw-1,bh-1,gray); 39141 sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black); 39142 sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black); 39143 sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white); 39144 sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black); 39145 sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2); 39146 sbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false); 39147 sbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false); 39148 CImg<unsigned char> cbutton(bw,bh,1,3); 39149 cbutton.draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray); 39150 cbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false); 39151 cbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false); 39152 39153 cimglist_for(buttons,ll) { 39154 CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].width())/2,1+(bh-buttons[ll].height())/2,buttons[ll]). 39155 move_to(cbuttons); 39156 CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].width())/2,(bh-buttons[ll].height())/2,buttons[ll]). 39157 move_to(sbuttons); 39158 CImg<unsigned char>(button).draw_image((bw-buttons[ll].width())/2,(bh-buttons[ll].height())/2,buttons[ll]). 39159 move_to(buttons[ll]); 39160 } 39161 39162 CImg<unsigned char> canvas; 39163 if (msg) CImg<unsigned char>().draw_text(0,0,"%s",black,gray,1,13,msg).move_to(canvas); 39164 const unsigned int 39165 bwall = (buttons._width-1)*(12+bw) + bw, 39166 w = cimg::max(196U,36+logo._width+canvas._width,24+bwall), 39167 h = cimg::max(96U,36+canvas._height+bh,36+logo._height+bh), 39168 lx = 12 + (canvas._data?0:((w-24-logo._width)/2)), 39169 ly = (h-12-bh-logo._height)/2, 39170 tx = lx+logo._width+12, 39171 ty = (h-12-bh-canvas._height)/2, 39172 bx = (w-bwall)/2, 39173 by = h-12-bh; 39174 39175 if (canvas._data) 39176 canvas = CImg<unsigned char>(w,h,1,3). 39177 draw_rectangle(0,0,w-1,h-1,gray). 39178 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). 39179 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black). 39180 draw_image(tx,ty,canvas); 39181 else 39182 canvas = CImg<unsigned char>(w,h,1,3). 39183 draw_rectangle(0,0,w-1,h-1,gray). 39184 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). 39185 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black); 39186 if (logo._data) canvas.draw_image(lx,ly,logo); 39187 39188 unsigned int xbuttons[6] = { 0 }; 39189 cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); } 39190 39191 // Open window and enter events loop 39192 CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false); 39193 if (centering) disp.move((CImgDisplay::screen_width() - disp.width())/2, 39194 (CImgDisplay::screen_height() - disp.height())/2); 39195 bool stopflag = false, refresh = false; 39196 int oselected = -1, oclicked = -1, selected = -1, clicked = -1; 39197 while (!disp.is_closed() && !stopflag) { 39198 if (refresh) { 39199 if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp); 39200 else { 39201 if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp); 39202 else canvas.display(disp); 39203 } 39204 refresh = false; 39205 } 39206 disp.wait(15); 39207 if (disp.is_resized()) disp.resize(disp); 39208 39209 if (disp.button()&1) { 39210 oclicked = clicked; 39211 clicked = -1; 39212 cimglist_for(buttons,l) 39213 if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by+bh) && 39214 disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l]+bw)) { 39215 clicked = selected = l; 39216 refresh = true; 39217 } 39218 if (clicked!=oclicked) refresh = true; 39219 } else if (clicked>=0) stopflag = true; 39220 39221 if (disp.key()) { 39222 oselected = selected; 39223 switch (disp.key()) { 39224 case cimg::keyESC : selected=-1; stopflag=true; break; 39225 case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break; 39226 case cimg::keyTAB : 39227 case cimg::keyARROWRIGHT : 39228 case cimg::keyARROWDOWN : selected = (selected+1)%buttons._width; break; 39229 case cimg::keyARROWLEFT : 39230 case cimg::keyARROWUP : selected = (selected+buttons._width-1)%buttons._width; break; 39231 } 39232 disp.set_key(); 39233 if (selected!=oselected) refresh = true; 39234 } 39235 } 39236 if (!disp) selected = -1; 39237 return selected; 39238 #endif 39239 } 39240 39241 inline int dialog(const char *const title, const char *const msg, 39242 const char *const button1_label, const char *const button2_label, const char *const button3_label, 39243 const char *const button4_label, const char *const button5_label, const char *const button6_label, 39244 const bool centering) { 39245 return dialog(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, 39246 CImg<unsigned char>::logo40x38(),centering); 39247 } 39248 39249 //! Evaluate math expression. 39250 inline double eval(const char *const expression, const double x, const double y, const double z, const double c) { 39251 static const CImg<float> empty; 39252 return empty.eval(expression,x,y,z,c); 39253 } 39254 39255 // End of cimg:: namespace 39256 } 39257 39258 // End of cimg_library:: namespace 39259 } 39260 39261 #ifdef _cimg_redefine_None 39262 #define None 0 39263 #endif 39264 #ifdef _cimg_redefine_min 39265 #define min(a,b) (((a)<(b))?(a):(b)) 39266 #endif 39267 #ifdef _cimg_redefine_max 39268 #define max(a,b) (((a)>(b))?(a):(b)) 39269 #endif 39270 #ifdef _cimg_redefine_PI 39271 #define PI 3.141592653589793238462643383 39272 #endif 39273 39274 #endif 39275 // Local Variables: 39276 // mode: c++ 39277 // End: