The C++ Template Image Processing Library. |
[Introduction]- [News]- [Download]- [Screenshots]- [Tutorial]- [Forums]- [Reference]- [SourceForge Repository ]

Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members

# CImg.h

    00001 /*------------------------------------------------------------------------------------------------------
    00002
    00003   File        : CImg.h
    00004
    00005   Description : The C++ Template Image Processing Library
    00006
    00007   Author      : David Tschumperlé
    00008
    00009   This software is governed by the CeCILL  license under French law and
    00010   abiding by the rules of distribution of free software.  You can  use,
    00011   modify and/ or redistribute the software under the terms of the CeCILL
    00012   license as circulated by CEA, CNRS and INRIA at the following URL
    00013   "http://www.cecill.info".
    00014
    00015   As a counterpart to the access to the source code and  rights to copy,
    00016   modify and redistribute granted by the license, users are provided only
    00017   with a limited warranty  and the software's author,  the holder of the
    00018   economic rights,  and the successive licensors  have only  limited
    00019   liability.
    00020
    00021   In this respect, the user's attention is drawn to the risks associated
    00022   with loading,  using,  modifying and/or developing or reproducing the
    00023   software by the user in light of its specific status of free software,
    00024   that may mean  that it is complicated to manipulate,  and  that  also
    00025   therefore means  that it is reserved for developers  and  experienced
    00026   professionals having in-depth computer knowledge. Users are therefore
    00027   encouraged to load and test the software's suitability as regards their
    00028   requirements in conditions enabling the security of their systems and/or
    00029   data to be ensured and,  more generally, to use and operate it in the
    00030   same conditions as regards security.
    00031
    00032   The fact that you are presently reading this means that you have had
    00033   knowledge of the CeCILL license and that you accept its terms.
    00034
    00035   ----------------------------------------------------------------------------------------------------*/
    00036
    00037 #ifndef cimg_version
    00038 #define cimg_version 1.07
    00039 #include <cstdio>
    00040 #include <cstdlib>
    00041 #include <cstdarg>
    00042 #include <cmath>
    00043 #include <cstring>
    00044 #include <ctime>
    00045
    00046 // Overcome VisualC++ 6.0 and DMC compilers namespace 'std::' bug
    00047 #if ( defined(_MSC_VER) && _MSC_VER<=1200 ) || defined(__DMC__)
    00048 #define std
    00049 #endif
    00050
    00051 /*-------------------------------------------------------------
    00052
    00053
    00054   Auto-detect and set CImg Library configuration flags.
    00055
    00056
    00057   If compilation flags are not adapted to your system,
    00058   you may override their values, before including
    00059   the header file "CImg.h" (use the #define directive).
    00060
    00061   -------------------------------------------------------------*/
    00062
    00063 #ifndef cimg_OS
    00064 #if defined(sun) || defined(__sun)
    00065 // Sun/Solaris configuration
    00066 #define cimg_OS            0
    00067 #ifndef cimg_display_type
    00068 #define cimg_display_type  1
    00069 #endif
    00070 #ifndef cimg_color_terminal
    00071 #define cimg_color_terminal
    00072 #endif
    00073 #elif defined(linux) || defined(__linux) || defined(__CYGWIN__)
    00074 // PC Linux configuration
    00075 #define cimg_OS            1
    00076 #ifndef cimg_display_type
    00077 #define cimg_display_type  1
    00078 #endif
    00079 #ifndef cimg_color_terminal
    00080 #define cimg_color_terminal
    00081 #endif
    00082 #elif defined(_WIN32) || defined(__WIN32__)
    00083 // PC Windows configuration
    00084 #define cimg_OS            2
    00085 #ifndef cimg_display_type
    00086 #define cimg_display_type  2
    00087 #endif
    00088 #elif defined(__MACOSX__) || defined(__APPLE__)
    00089 // Mac OS X configuration
    00090 #define cimg_OS            3
    00091 #ifndef cimg_display_type
    00092 #define cimg_display_type  1
    00093 #endif
    00094 #elif defined(__FreeBSD__)
    00095 // FreeBSD configuration
    00096 #define cimg_OS            4
    00097 #ifndef cimg_display_type
    00098 #define cimg_display_type  1
    00099 #endif
    00100 #ifndef cimg_color_terminal
    00101 #define cimg_color_terminal
    00102 #endif
    00103 #else
    00104 // Unknown configuration : minimal dependencies.
    00105 #define cimg_OS           -1
    00106 #ifndef cimg_display_type
    00107 #define cimg_display_type  0
    00108 #endif
    00109 #endif
    00110 #endif
    00111
    00112 // Debug configuration.
    00113 //--------------------
    00114 // Define 'cimg_debug' to : 0 to remove dynamic debug messages (exceptions are still thrown)
    00115 //                          1 to display dynamic debug messages (default behavior).
    00116 //                          2 to add extra memory access controls (may slow down the code)
    00117 #ifndef cimg_debug
    00118 #define cimg_debug         1
    00119 #endif
    00120
    00121 // Architecture-dependent includes
    00122 //---------------------------------
    00123 #if cimg_OS!=2
    00124 #include <sys/time.h>
    00125 #include <unistd.h>
    00126 #else
    00127 #include <windows.h>
    00128 // Discard annoying macro definitions in windows.h
    00129 #ifdef min
    00130 #undef min
    00131 #undef max
    00132 #undef abs
    00133 #endif
    00134 #endif
    00135 #if cimg_display_type==1
    00136 #include <X11/Xlib.h>
    00137 #include <X11/Xutil.h>
    00138 #include <X11/keysym.h>
    00139 #include <pthread.h>
    00140 #endif
    00141
    00142 /*-----------------------------------------------------------------------------------
    00143
    00144
    00145
    00146    Define some macros. Macros of the CImg Library are prefixed by 'cimg_'
    00147    Documented macros below may be safely used in your own code.
    00148
    00149
    00150    ---------------------------------------------------------------------------------*/
    00151
    00152 // Macros used to describe the program usage, and retrieve command line arguments
    00153 // (See corresponding module 'Retrieving command line arguments' in the generated documentation).
    00154 #define cimg_usage(usage) cimg_library::cimg::option((char*)NULL,(unsigned int)argc,(char**)argv,(char*)NULL,(char*)usage)
    00155 #define cimg_option(name,defaut,usage) cimg_library::cimg::option((char*)name,(unsigned int)argc,(char**)argv,defaut,(char*)usage)
    00156
    00157 // Macros used for dynamic debug messages. Shouldn't be used in your own source code.
    00158 #define cimg_test(x,func)                                               \
    00159   if(!(x).width || !(x).height || !(x).depth || !(x).dim || !(x).data)  \
    00160     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is empty", \
    00161                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00162 #define cimgl_test(x,func) \
    00163   if(!(x).size || !(x).data) \
    00164     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImgl<%s> %s = (%d,%p) is empty", \
    00165                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).size,(x).data)
    00166 #define cimg_test_scalar(x,func) \
    00167   if(!(x).width || !(x).height || !(x).depth || (x).dim!=1 || !(x).data) \
    00168     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not scalar", \
    00169                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00170 #define cimg_test_matrix(x,func) \
    00171   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || !(x).data) \
    00172     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a matrix", \
    00173                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00174 #define cimg_test_square(x,func) \
    00175   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || (x).width!=(x).height || !(x).data) \
    00176     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a square matrix", \
    00177                                 func,__FILE__,__LINE__,(x).pixel_type,#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00178 #define cimg_test_display(x,func) \
    00179   if (!(x).width || !(x).height) \
    00180     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', l.%d), CImgDisplay %s = (%d,%d) is not a valid display", \
    00181                                 func,__FILE__,__LINE__,#x,(x).width,(x).height)
    00182
    00183 // Macros used for neighborhood definitions and manipulations (see module 'Using Image Loops' in the generated documentation).
    00184 #define CImg_2x2(I,T)     T I##cc,I##nc=0,I##cn,I##nn=0
    00185 #define CImg_3x3(I,T)     T I##pp,I##cp,I##np=0,I##pc,I##cc,I##nc=0,I##pn,I##cn,I##nn=0
    00186 #define CImg_4x4(I,T)     T I##pp,I##cp,I##np=0,I##ap=0, \
    00187                             I##pc,I##cc,I##nc=0,I##ac=0, \
    00188                             I##pn,I##cn,I##nn=0,I##an=0, \
    00189                             I##pa,I##ca,I##na=0,I##aa=0
    00190 #define CImg_5x5(I,T)     T I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \
    00191                             I##bp,I##pp,I##cp,I##np=0,I##ap=0, \
    00192                             I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \
    00193                             I##bn,I##pn,I##cn,I##nn=0,I##an=0, \
    00194                             I##ba,I##pa,I##ca,I##na=0,I##aa=0
    00195 #define CImg_2x2x2(I,T)   T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \
    00196                             I##ccn,I##ncn=0,I##cnn,I##nnn=0
    00197 #define CImg_3x3x3(I,T)   T I##ppp,I##cpp,I##npp=0,I##pcp,I##ccp,I##ncp=0,I##pnp,I##cnp,I##nnp=0, \
    00198                             I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \
    00199                             I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0
    00200
    00201 #define CImg_2x2_ref(I,T,tab)   T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3];
    00202 #define CImg_3x3_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \
    00203                                   &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \
    00204                                   &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8]
    00205 #define CImg_4x4_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2],&I##ap=(tab)[3], \
    00206                                   &I##pc=(tab)[4],&I##cc=(tab)[5],&I##nc=(tab)[6],&I##ap=(tab)[7], \
    00207                                   &I##pn=(tab)[8],&I##cn=(tab)[9],&I##nn=(tab)[10],&I##aa=(tab)[11], \
    00208                                   &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15]
    00209 #define CImg_5x5_ref(I,T,tab)   T &I##bb=(tab)[0],&I##pb=(tab)[1],&I##cb=(tab)[2],&I##nb=(tab)[3],&I##ab=(tab)[4], \
    00210                                   &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \
    00211                                   &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \
    00212                                   &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \
    00213                                   &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24]
    00214 #define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \
    00215                                   &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7]
    00216 #define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \
    00217                                   &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \
    00218                                   &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \
    00219                                   &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \
    00220                                   &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \
    00221                                   &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \
    00222                                   &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \
    00223                                   &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \
    00224                                   &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26]
    00225
    00226 #define cimg_squaresum2x2(I) ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn )
    00227 #define cimg_squaresum3x3(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \
    00228                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \
    00229                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn )
    00230 #define cimg_squaresum4x4(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
    00231                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
    00232                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
    00233                                I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
    00234 #define cimg_squaresum5x5(I) ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \
    00235                                I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
    00236                                I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
    00237                                I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
    00238                                I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
    00239 #define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \
    00240                                  I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn )
    00241 #define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \
    00242                                  I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \
    00243                                  I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \
    00244                                  I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \
    00245                                  I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \
    00246                                  I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \
    00247                                  I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \
    00248                                  I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \
    00249                                  I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn )
    00250
    00251 #define cimg_corr2x2(I,m) ( I##cc*(m)(0,0)+I##nc*(m)(1,0)+I##cn*(m)(0,1)+I##nn*(m)(1,1) )
    00252 #define cimg_corr3x3(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \
    00253                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \
    00254                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) )
    00255 #define cimg_corr4x4(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0)+I##ap*(m)(3,0) + \
    00256                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \
    00257                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \
    00258                             I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) )
    00259 #define cimg_corr5x5(I,m) ( I##bb*(m)(0,0)+I##pb*(m)(1,0)+I##cb*(m)(2,0)+I##nb*(m)(3,0)+I##ab*(m)(4,0) + \
    00260                             I##bp*(m)(0,1)+I##pp*(m)(1,1)+I##cp*(m)(2,1)+I##np*(m)(3,1)+I##ap*(m)(4,1) + \
    00261                             I##bc*(m)(0,2)+I##pc*(m)(1,2)+I##cc*(m)(2,2)+I##nc*(m)(3,2)+I##ac*(m)(4,2) + \
    00262                             I##bn*(m)(0,3)+I##pn*(m)(1,3)+I##cn*(m)(2,3)+I##nn*(m)(3,3)+I##an*(m)(4,3) + \
    00263                             I##ba*(m)(0,4)+I##pa*(m)(1,4)+I##ca*(m)(2,4)+I##na*(m)(3,4)+I##aa*(m)(4,4) )
    00264 #define cimg_corr2x2x2(I,m) ( I##ccc*(m)(0,0,0)+I##ncc*(m)(1,0,0)+I##cnc*(m)(0,1,0)+I##nnc*(m)(1,1,0) + \
    00265                               I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) )
    00266 #define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \
    00267                               I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \
    00268                               I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \
    00269                               I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \
    00270                               I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \
    00271                               I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \
    00272                               I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \
    00273                               I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \
    00274                               I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) )
    00275
    00276 #define cimg_conv2x2(I,m) ( I##cc*(m)(1,1)+I##nc*(m)(0,1)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
    00277 #define cimg_conv3x3(I,m) ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \
    00278                             I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \
    00279                             I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
    00280 #define cimg_conv4x4(I,m) ( I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \
    00281                             I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
    00282                             I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
    00283                             I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
    00284 #define cimg_conv5x5(I,m) ( I##bb*(m)(4,4)+I##pb*(m)(3,4)+I##cb*(m)(2,4)+I##nb*(m)(1,4)+I##ab*(m)(0,4) + \
    00285                             I##bp*(m)(4,3)+I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \
    00286                             I##bc*(m)(4,2)+I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
    00287                             I##bn*(m)(4,1)+I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
    00288                             I##ba*(m)(4,0)+I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
    00289 #define cimg_conv2x2x2(I,m) ( I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
    00290                               I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
    00291 #define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \
    00292                               I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \
    00293                               I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \
    00294                               I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \
    00295                               I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \
    00296                               I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
    00297                               I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \
    00298                               I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \
    00299                               I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
    00300
    00301 #define cimg_get2x2(img,x,y,z,v,I) I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
    00302     I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
    00303 #define cimg_get3x3(img,x,y,z,v,I) I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), \
    00304     I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
    00305     I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
    00306 #define cimg_get4x4(img,x,y,z,v,I)                                      \
    00307   I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \
    00308     I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), I##ac=(img)(_a##x,    y,z,v), \
    00309     I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \
    00310     I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v)
    00311 #define cimg_get5x5(img,x,y,z,v,I)                                      \
    00312   I##bb=(img)(_b##x,_b##y,z,v), I##pb=(img)(_p##x,_b##y,z,v), I##cb=(img)(x,_b##y,z,v), I##nb=(img)(_n##x,_b##y,z,v), I##ab=(img)(_a##x,_b##y,z,v), \
    00313     I##bp=(img)(_b##x,_p##y,z,v), I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \
    00314     I##bc=(img)(_b##x,    y,z,v), I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), I##ac=(img)(_a##x,    y,z,v), \
    00315     I##bn=(img)(_b##x,_n##y,z,v), I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \
    00316     I##ba=(img)(_b##x,_a##y,z,v), I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v)
    00317 #define cimg_get2x2x2(img,x,y,z,v,I)                                    \
    00318   I##ccc=(img)(x,y,    z,v), I##ncc=(img)(_n##x,y,    z,v), I##cnc=(img)(x,_n##y,    z,v), I##nnc=(img)(_n##x,_n##y,    z,v), \
    00319     I##ccc=(img)(x,y,_n##z,v), I##ncc=(img)(_n##x,y,_n##z,v), I##cnc=(img)(x,_n##y,_n##z,v), I##nnc=(img)(_n##x,_n##y,_n##z,v)
    00320 #define cimg_get3x3x3(img,x,y,z,v,I)                                    \
    00321   I##ppp=(img)(_p##x,_p##y,_p##z,v), I##cpp=(img)(x,_p##y,_p##z,v), I##npp=(img)(_n##x,_p##y,_p##z,v), \
    00322     I##pcp=(img)(_p##x,    y,_p##z,v), I##ccp=(img)(x,    y,_p##z,v), I##ncp=(img)(_n##x,    y,_p##z,v), \
    00323     I##pnp=(img)(_p##x,_n##y,_p##z,v), I##cnp=(img)(x,_n##y,_p##z,v), I##nnp=(img)(_n##x,_n##y,_p##z,v), \
    00324     I##ppc=(img)(_p##x,_p##y,    z,v), I##cpc=(img)(x,_p##y,    z,v), I##npc=(img)(_n##x,_p##y,    z,v), \
    00325     I##pcc=(img)(_p##x,    y,    z,v), I##ccc=(img)(x,    y,    z,v), I##ncc=(img)(_n##x,    y,    z,v), \
    00326     I##pnc=(img)(_p##x,_n##y,    z,v), I##cnc=(img)(x,_n##y,    z,v), I##nnc=(img)(_n##x,_n##y,    z,v), \
    00327     I##ppn=(img)(_p##x,_p##y,_n##z,v), I##cpn=(img)(x,_p##y,_n##z,v), I##npn=(img)(_n##x,_p##y,_n##z,v), \
    00328     I##pcn=(img)(_p##x,    y,_n##z,v), I##ccn=(img)(x,    y,_n##z,v), I##ncn=(img)(_n##x,    y,_n##z,v), \
    00329     I##pnn=(img)(_p##x,_n##y,_n##z,v), I##cnn=(img)(x,_n##y,_n##z,v), I##nnn=(img)(_n##x,_n##y,_n##z,v)
    00330
    00331 #define cimg_3x3to5x5(I,u) u##bb=I##pp,u##cb=I##cp,u##ab=I##np,u##bc=I##pc,u##cc=I##cc,u##ac=I##nc,u##ba=I##pn,u##ca=I##cn,u##aa=I##nn, \
    00332     u##pb=0.5*(u##bb+u##cb),u##nb=0.5*(u##cb+u##ab),u##pc=0.5*(u##bc+u##cc),u##nc=0.5*(u##cc+u##ac),u##pa=0.5*(u##ba+u##ca),u##na=0.5*(u##ca+u##aa), \
    00333     u##bp=0.5*(u##bb+u##bc),u##bn=0.5*(u##bc+u##ba),u##cp=0.5*(u##cb+u##cc),u##cn=0.5*(u##cc+u##ca),u##ap=0.5*(u##ab+u##ac),u##an=0.5*(u##ac+u##aa), \
    00334     u##pp=0.5*(u##bp+u##cp),u##np=0.5*(u##cp+u##ap),u##pn=0.5*(u##bn+u##cn),u##nn=0.5*(u##cn+u##an)
    00335
    00336 // Macros used to define special image loops (see module 'Using Image Loops' in the generated documentation).
    00337 #define cimg_map(img,ptr,T_ptr)   for (T_ptr *ptr=(img).data+(img).size()-1; ptr>=(img).data; ptr--)
    00338 #define cimgl_map(list,l)         for (unsigned int l=0; l<(list).size; l++)
    00339 #define cimg_mapoff(img,off)      for (unsigned int off=0; off<(img).size(); off++)
    00340 #define cimg_mapX(img,x)          for (int x=0; x<(int)((img).width); x++)
    00341 #define cimg_mapY(img,y)          for (int y=0; y<(int)((img).height);y++)
    00342 #define cimg_mapZ(img,z)          for (int z=0; z<(int)((img).depth); z++)
    00343 #define cimg_mapV(img,v)          for (int v=0; v<(int)((img).dim);   v++)
    00344 #define cimg_mapXY(img,x,y)       cimg_mapY(img,y) cimg_mapX(img,x)
    00345 #define cimg_mapXZ(img,x,z)       cimg_mapZ(img,z) cimg_mapX(img,x)
    00346 #define cimg_mapYZ(img,y,z)       cimg_mapZ(img,z) cimg_mapY(img,y)
    00347 #define cimg_mapXV(img,x,v)       cimg_mapV(img,v) cimg_mapX(img,x)
    00348 #define cimg_mapYV(img,y,v)       cimg_mapV(img,v) cimg_mapY(img,y)
    00349 #define cimg_mapZV(img,z,v)       cimg_mapV(img,v) cimg_mapZ(img,z)
    00350 #define cimg_mapXYZ(img,x,y,z)    cimg_mapZ(img,z) cimg_mapXY(img,x,y)
    00351 #define cimg_mapXYV(img,x,y,v)    cimg_mapV(img,v) cimg_mapXY(img,x,y)
    00352 #define cimg_mapXZV(img,x,z,v)    cimg_mapV(img,v) cimg_mapXZ(img,x,z)
    00353 #define cimg_mapYZV(img,y,z,v)    cimg_mapV(img,v) cimg_mapYZ(img,y,z)
    00354 #define cimg_mapXYZV(img,x,y,z,v) cimg_mapV(img,v) cimg_mapXYZ(img,x,y,z)
    00355 #define cimg_imapX(img,x,n)       for (int x=n; x<(int)((img).width-n); x++)
    00356 #define cimg_imapY(img,y,n)       for (int y=n; y<(int)((img).height-n); y++)
    00357 #define cimg_imapZ(img,z,n)       for (int z=n; z<(int)((img).depth-n); z++)
    00358 #define cimg_imapV(img,v,n)       for (int v=n; v<(int)((img).dim-n); v++)
    00359 #define cimg_imapXY(img,x,y,n)    cimg_imapY(img,y,n) cimg_imapX(img,x,n)
    00360 #define cimg_imapXYZ(img,x,y,z,n) cimg_imapZ(img,z,n) cimg_imapXY(img,x,y,n)
    00361 #define cimg_bmapX(img,x,n)       for (int x=0; x<(int)((img).width);  x==(n)-1?(x=(img).width-(n)): x++)
    00362 #define cimg_bmapY(img,y,n)       for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++)
    00363 #define cimg_bmapZ(img,z,n)       for (int z=0; z<(int)((img).depth);  z==(n)-1?(x=(img).depth-(n)): z++)
    00364 #define cimg_bmapV(img,v,n)       for (int v=0; v<(int)((img).dim);    v==(n)-1?(x=(img).dim-(n)):   v++)
    00365 #define cimg_bmapXY(img,x,y,n)    cimg_mapY(img,y) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n))?x++: \
    00366                                                           ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
    00367 #define cimg_bmapXYZ(img,x,y,z,n) cimg_mapYZ(img,y,z) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n) || z<(n) || z>=(int)((img).depth)-(n))?x++: \
    00368                                                              ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
    00369 #define cimg_2mapX(img,x)         for (int x=0,_n##x=1; _n##x<(int)((img).width)   || x==--_n##x; x++, _n##x++)
    00370 #define cimg_2mapY(img,y)         for (int y=0,_n##y=1; _n##y<(int)((img).height)  || y==--_n##y; y++, _n##y++)
    00371 #define cimg_2mapZ(img,z)         for (int z=0,_n##z=1; _n##z<(int)((img).depth)   || z==--_n##z; z++, _n##z++)
    00372 #define cimg_2mapXY(img,x,y)      cimg_2mapY(img,y) cimg_2mapX(img,x)
    00373 #define cimg_2mapXZ(img,x,z)      cimg_2mapZ(img,z) cimg_2mapX(img,x)
    00374 #define cimg_2mapYZ(img,y,z)      cimg_2mapZ(img,z) cimg_2mapY(img,y)
    00375 #define cimg_2mapXYZ(img,x,y,z)   cimg_2mapZ(img,z) cimg_2mapXY(img,x,y)
    00376 #define cimg_3mapX(img,x)         for (int x=0,_p##x=0,_n##x=1; _n##x<(int)((img).width)  || x==--_n##x;  _p##x=x++,_n##x++)
    00377 #define cimg_3mapY(img,y)         for (int y=0,_p##y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y;  _p##y=y++,_n##y++)
    00378 #define cimg_3mapZ(img,z)         for (int z=0,_p##z=0,_n##z=1; _n##z<(int)((img).depth)  || z==--_n##z;  _p##z=z++,_n##z++)
    00379 #define cimg_3mapXY(img,x,y)      cimg_3mapY(img,y) cimg_3mapX(img,x)
    00380 #define cimg_3mapXZ(img,x,z)      cimg_3mapZ(img,z) cimg_3mapX(img,x)
    00381 #define cimg_3mapYZ(img,y,z)      cimg_3mapZ(img,z) cimg_3mapY(img,y)
    00382 #define cimg_3mapXYZ(img,x,y,z)   cimg_3mapZ(img,z) cimg_3mapXY(img,x,y)
    00383 #define cimg_4mapX(img,x)         for (int _p##x=0,x=0,_n##x=1,_a##x=2; \
    00384                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00385                                        _p##x=x++,_n##x++,_a##x++)
    00386 #define cimg_4mapY(img,y)         for (int _p##y=0,y=0,_n##y=1,_a##y=2; \
    00387                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
    00388                                        _p##y=y++,_n##y++,_a##y++)
    00389 #define cimg_4mapZ(img,z)         for (int _p##z=0,z=0,_n##z=1,_a##z=2; \
    00390                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
    00391                                        _p##z=z++,_n##z++,_a##z++)
    00392 #define cimg_4mapXY(img,x,y)      cimg_4mapY(img,y) cimg_4mapX(img,x)
    00393 #define cimg_4mapXZ(img,x,z)      cimg_4mapZ(img,z) cimg_4mapX(img,x)
    00394 #define cimg_4mapYZ(img,y,z)      cimg_4mapZ(img,z) cimg_4mapY(img,y)
    00395 #define cimg_4mapXYZ(img,x,y,z)   cimg_4mapZ(img,z) cimg_4mapXY(img,x,y)
    00396 #define cimg_5mapX(img,x)         for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \
    00397                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00398                                        _b##x=_p##x,_p##x=x++,_n##x++,_a##x++)
    00399 #define cimg_5mapY(img,y)         for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \
    00400                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
    00401                                        _b##y=_p##y,_p##y=y++,_n##y++,_a##y++)
    00402 #define cimg_5mapZ(img,z)         for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \
    00403                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
    00404                                        _b##z=_p##z,_p##z=z++,_n##z++,_a##z++)
    00405 #define cimg_5mapXY(img,x,y)      cimg_5mapY(img,y) cimg_5mapX(img,x)
    00406 #define cimg_5mapXZ(img,x,z)      cimg_5mapZ(img,z) cimg_5mapX(img,x)
    00407 #define cimg_5mapYZ(img,y,z)      cimg_5mapZ(img,z) cimg_5mapY(img,y)
    00408 #define cimg_5mapXYZ(img,x,y,z)   cimg_5mapZ(img,z) cimg_5mapXY(img,x,y)
    00409
    00410 #define cimg_map2x2(img,x,y,z,v,I) cimg_2mapY(img,y)                    \
    00411        for (int _n##x=1, x=((int)(I##cc=(img)(0,  y,z,v),               \
    00412                                   I##cn=(img)(0,_n##y,z,v)),0);         \
    00413             (_n##x<(int)((img).width) && (                              \
    00414                                           I##nc=(img)(_n##x,    y,z,v), \
    00415                                           I##nn=(img)(_n##x,_n##y,z,v), \
    00416                                           1)) || x==--_n##x;            \
    00417             I##cc=I##nc, I##cn=I##nn,                                   \
    00418               x++,_n##x++ )
    00419
    00420 #define cimg_map3x3(img,x,y,z,v,I) cimg_3mapY(img,y)                    \
    00421        for (int _n##x=1, _p##x=(int)(I##cp=I##pp=(img)(0,_p##y,z,v),    \
    00422                                      I##cc=I##pc=(img)(0,  y,z,v),      \
    00423                                      I##cn=I##pn=(img)(0,_n##y,z,v)     \
    00424                                      ), x=_p##x=0;                      \
    00425             (_n##x<(int)((img).width) && (                              \
    00426                                           I##np=(img)(_n##x,_p##y,z,v), \
    00427                                           I##nc=(img)(_n##x,    y,z,v), \
    00428                                           I##nn=(img)(_n##x,_n##y,z,v), \
    00429                                           1)) || x==--_n##x;            \
    00430             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn,                      \
    00431               I##cp=I##np, I##cc=I##nc, I##cn=I##nn,                    \
    00432               _p##x=x++,_n##x++ )
    00433
    00434 #define cimg_map4x4(img,x,y,z,v,I) cimg_4mapY(img,y)                    \
    00435        for (int _a##x=2, _n##x=1, x=((int)(I##cp=I##pp=(img)(0,_p##y,z,v), \
    00436                                            I##cc=I##pc=(img)(0,    y,z,v), \
    00437                                            I##cn=I##pn=(img)(0,_n##y,z,v), \
    00438                                            I##ca=I##pa=(img)(0,_a##y,z,v), \
    00439                                            I##np=(img)(_n##x,_p##y,z,v), \
    00440                                            I##nc=(img)(_n##x,    y,z,v), \
    00441                                            I##nn=(img)(_n##x,_n##y,z,v), \
    00442                                            I##na=(img)(_n##x,_a##y,z,v)),0), \
    00443               _p##x=0;                                                  \
    00444             (_a##x<(int)((img).width) && (                              \
    00445                                           I##ap=(img)(_a##x,_p##y,z,v), \
    00446                                           I##ac=(img)(_a##x,    y,z,v), \
    00447                                           I##an=(img)(_a##x,_n##y,z,v), \
    00448                                           I##aa=(img)(_a##x,_a##y,z,v), \
    00449                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00450             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca,         \
    00451               I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na,       \
    00452               I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa,       \
    00453               _p##x=x++, _n##x++, _a##x++ )
    00454
    00455 #define cimg_map5x5(img,x,y,z,v,I) cimg_5mapY(img,y)                    \
    00456        for (int _a##x=2, _n##x=1, _b##x=(int)(I##cb=I##pb=I##bb=(img)(0,_b##y,z,v), \
    00457                                               I##cp=I##pp=I##bp=(img)(0,_p##y,z,v), \
    00458                                               I##cc=I##pc=I##bc=(img)(0,    y,z,v), \
    00459                                               I##cn=I##pn=I##bn=(img)(0,_n##y,z,v), \
    00460                                               I##ca=I##pa=I##ba=(img)(0,_a##y,z,v), \
    00461                                               I##nb=(img)(_n##x,_b##y,z,v), \
    00462                                               I##np=(img)(_n##x,_p##y,z,v), \
    00463                                               I##nc=(img)(_n##x,   y,z,v), \
    00464                                               I##nn=(img)(_n##x,_n##y,z,v), \
    00465                                               I##na=(img)(_n##x,_a##y,z,v)), \
    00466               x=0, _p##x=_b##x=0;                                       \
    00467             (_a##x<(int)((img).width) && (                              \
    00468                                           I##ab=(img)(_a##x,_b##y,z,v), \
    00469                                           I##ap=(img)(_a##x,_p##y,z,v), \
    00470                                           I##ac=(img)(_a##x,    y,z,v), \
    00471                                           I##an=(img)(_a##x,_n##y,z,v), \
    00472                                           I##aa=(img)(_a##x,_a##y,z,v), \
    00473                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00474             I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \
    00475               I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \
    00476               I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \
    00477               I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \
    00478               _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ )
    00479
    00480 #define cimg_map2x2x2(img,x,y,z,v,I) cimg_2mapYZ(img,y,z)               \
    00481        for (int _n##x=1, x=((int)(I##ccc=(img)(0,    y,    z,v),        \
    00482                                   I##cnc=(img)(0,_n##y,    z,v),        \
    00483                                   I##ccn=(img)(0,    y,_n##z,v),        \
    00484                                   I##cnn=(img)(0,_n##y,_n##z,v)),0);    \
    00485             (_n##x<(int)((img).width) && (                              \
    00486                                           I##ncc=(img)(_n##x,    y,    z,v), \
    00487                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
    00488                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
    00489                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
    00490                                           1)) || x==--_n##x;            \
    00491             I##ccc=I##ncc, I##cnc=I##nnc,                               \
    00492               I##ccn=I##ncn, I##cnn=I##nnn,                             \
    00493               x++, _n##x++ )
    00494
    00495 #define cimg_map3x3x3(img,x,y,z,v,I) cimg_3mapYZ(img,y,z)               \
    00496        for (int _n##x=1, _p##x=(int)(I##cpp=I##ppp=(img)(0,_p##y,_p##z,v), \
    00497                                      I##ccp=I##pcp=(img)(0,    y,_p##z,v), \
    00498                                      I##cnp=I##pnp=(img)(0,_n##y,_p##z,v), \
    00499                                      I##cpc=I##ppc=(img)(0,_p##y,    z,v), \
    00500                                      I##ccc=I##pcc=(img)(0,    y,    z,v), \
    00501                                      I##cnc=I##pnc=(img)(0,_n##y,    z,v), \
    00502                                      I##cpn=I##ppn=(img)(0,_p##y,_n##z,v), \
    00503                                      I##ccn=I##pcn=(img)(0,    y,_n##z,v), \
    00504                                      I##cnn=I##pnn=(img)(0,_n##y,_n##z,v)),\
    00505               x=_p##x=0;                                                \
    00506             (_n##x<(int)((img).width) && (                              \
    00507                                           I##npp=(img)(_n##x,_p##y,_p##z,v), \
    00508                                           I##ncp=(img)(_n##x,    y,_p##z,v), \
    00509                                           I##nnp=(img)(_n##x,_n##y,_p##z,v), \
    00510                                           I##npc=(img)(_n##x,_p##y,    z,v), \
    00511                                           I##ncc=(img)(_n##x,    y,    z,v), \
    00512                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
    00513                                           I##npn=(img)(_n##x,_p##y,_n##z,v), \
    00514                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
    00515                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
    00516                                           1)) || x==--_n##x;            \
    00517             I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp,                \
    00518               I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp,              \
    00519               I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc,              \
    00520               I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc,              \
    00521               I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn,              \
    00522               I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn,              \
    00523               _p##x=x++, _n##x++ )
    00524
    00525 // Macros used to create inline code in some special internal functions. Never use in your own code !
    00526 #define cimg_deriche_map(x0,y0,z0,k0,nb,offset,T) {                           \
    00527     ima = ptr(x0,y0,z0,k0);                                                   \
    00528     I2 = *ima; ima+=offset; I1 = *ima; ima+=offset;                           \
    00529     Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2;                   \
    00530     for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset;                          \
    00531         Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2;                          \
    00532         I2=I1; Y2=Y1; Y1=Y0; }                                                \
    00533     ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \
    00534     ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1);                            \
    00535     for (i=(nb)-3; i>=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset;      \
    00536       I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; }                    \
    00537   }
    00538 #define cimg_load_inr_case(Tf,sign,pixsize,Ts,Td)                       \
    00539   if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) {    \
    00540       Ts *xval, *val = new Ts[fopt[0]*fopt[3]];                         \
    00541       const int cimg_endian = cimg::CPU_endian();                       \
    00542       cimg_mapYZ(dest,y,z) {                                            \
    00543           cimg::fread(val,pixsize/8,fopt[0]*fopt[3],file);              \
    00544           if (fopt[7]!=cimg_endian) cimg::bswap(val,fopt[0]*fopt[3],pixsize/8); \
    00545           xval = val; cimg_mapX(dest,x) cimg_mapV(dest,k) dest(x,y,z,k) = (Td)*(xval++); \
    00546         }                                                               \
    00547       delete[] val;                                                     \
    00548       loaded = true;                                                    \
    00549     }
    00550
    00551 #define cimg_load_raw_case(Ts,Tss)                                               \
    00552   if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l<n; l++) {  \
    00553       Tss *buf;                                                         \
    00554       const bool cimg_endian = cimg::CPU_endian();                      \
    00555       j=0; while((i=fgetc(file))!='\n') tmp[j++]=(char)i; tmp[j]='\0';  \
    00556       std::sscanf(tmp,"%d %d %d %d",&w,&h,&z,&k);                       \
    00557       buf = new Tss[w*h*z*k]; cimg::fread(buf,sizeof(Tss),w*h*z*k,file);\
    00558       if (!cimg_endian) cimg::bswap(buf,w*h*z*k,sizeof(Tss));           \
    00559       CImg<T> idest(w,h,z,k); cimg_mapoff(idest,off)                    \
    00560                         idest[off] = (T)(buf[off]); idest.swap(res[l]); \
    00561       delete[] buf;                                                     \
    00562       loaded = true;                                                    \
    00563     }
    00564
    00565 #define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype)  \
    00566   case nid: {                                                         \
    00567     cimg::fread(dims,sizeof(unsigned int),nbdim,file);                \
    00568     if (endian) cimg::bswap(dims,nbdim,sizeof(unsigned int));         \
    00569     dest = CImg<T>(nwidth,nheight,ndepth,ndim);                       \
    00570     stype *buffer = new stype[dest.size()];                           \
    00571     cimg::fread(buffer,sizeof(stype),dest.size(),file);               \
    00572     if (endian) cimg::bswap(buffer,dest.size(),sizeof(T));            \
    00573     T *ptrd = dest.ptr();                                             \
    00574     cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));               \
    00575     buffer-=dest.size();                                              \
    00576     delete[] buffer;                                                  \
    00577    }                                                                  \
    00578    break;
    00579
    00580 #define cimg_save_pandore_case(sy,sz,sv,stype,id)                           \
    00581    if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
    00582       unsigned int *iheader = (unsigned int*)(header+12);                   \
    00583       nbdims = _save_pandore_header_length((*iheader=id),dims);             \
    00584       cimg::fwrite(header,sizeof(unsigned char),36,file);                   \
    00585       cimg::fwrite(dims,sizeof(unsigned int),nbdims,file);                  \
    00586       if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
    00587         unsigned char *buffer = new unsigned char[size()];                  \
    00588         T *ptrs = ptr();                                                    \
    00589         cimg_mapoff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++));      \
    00590         buffer-=size();                                                     \
    00591         cimg::fwrite(buffer,sizeof(unsigned char),size(),file);             \
    00592         delete[] buffer;                                                    \
    00593       }                                                                     \
    00594       if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
    00595         unsigned long *buffer = new unsigned long[size()];                  \
    00596         T *ptrs = ptr();                                                    \
    00597         cimg_mapoff(*this,off) *(buffer++)=(long)(*(ptrs++));               \
    00598         buffer-=size();                                                     \
    00599         cimg::fwrite(buffer,sizeof(long),size(),file);                      \
    00600         delete[] buffer;                                                    \
    00601       }                                                                     \
    00602       if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
    00603         float *buffer = new float[size()];                                  \
    00604         T *ptrs = ptr();                                                    \
    00605         cimg_mapoff(*this,off) *(buffer++)=(float)(*(ptrs++));              \
    00606         buffer-=size();                                                     \
    00607         cimg::fwrite(buffer,sizeof(float),size(),file);                     \
    00608         delete[] buffer;                                                    \
    00609       }                                                                     \
    00610       saved = true;                                                         \
    00611     }
    00612
    00613 /*-------------------------------------------------
    00614   -------------------------------------------------
    00615
    00616
    00617
    00618     Definition of the cimg_library:: namespace
    00619
    00620
    00621   -------------------------------------------------
    00622   -------------------------------------------------*/
    00623
    00625
    00635 namespace cimg_library {
    00636   struct CImgStats;
    00637   struct CImgDisplay;
    00638   struct CImgException;
    00639   template<typename T=float> struct CImg;
    00640   template<typename T=float> struct CImgl;
    00641   template<typename T=float> struct CImgROI;
    00642
    00643   /*----------------------------------------------------
    00644
    00645
    00646
    00647   Definition of the CImgException structures
    00648
    00649
    00650
    00651   -------------------------------------------------*/
    00652
    00653 #if cimg_debug>=1
    00654 #if cimg_display_type!=2
    00655 #define cimg_exception_print(str) std::fprintf(stderr,"<CImg Error> %s",str);
    00656 #else
    00657 #define cimg_exception_print(str) MessageBox(NULL,str,"<CImg Error>",MB_OK);
    00658 #endif
    00659 #else
    00660 #define cimg_exception_print(str)
    00661 #endif
    00662 #define cimg_exception_err(etype)                                       \
    00663   char tmp[1024];                                                       \
    00664   va_list ap;                                                           \
    00665   va_start(ap,format);                                                  \
    00666   std::vsprintf(message,format,ap);                                     \
    00667   va_end(ap);                                                           \
    00668   std::sprintf(tmp,"==> %s \n\nGeneral : %s\n\n", message,etype); \
    00669   cimg_exception_print(tmp)
    00670
    00672
    00707   struct CImgException {
    00708     char message[1024];
    00709     CImgException() { message[0]='\0'; }
    00710     CImgException(const char *format,...) {
    00711       cimg_exception_err("This error has been generated by a 'CImgException' throw, corresponding to a general exception problem.");
    00712     }
    00713   };
    00714
    00717
    00728   struct CImgInstanceException : CImgException {
    00729     CImgInstanceException(const char *format,...) {
    00730       cimg_exception_err("This error has been generated by a 'CImgInstanceException' throw.\n\
    00731 The instance passed through the function above has a bad structure (perhaps an empty image, list or display object ?)");
    00732     }};
    00733
    00736
    00747   struct CImgArgumentException : CImgException {
    00748     CImgArgumentException(const char *format,...) {
    00749       cimg_exception_err("This error has been generated by a 'CImgArgumentException' throw.\n\
    00750 At least one argument passed to the function above has been considered as not valid.");
    00751     }};
    00752
    00755
    00765   struct CImgIOException : CImgException {
    00766     CImgIOException(const char *format,...) {
    00767       cimg_exception_err("This error has been generated by a 'CImgIOException' throw.\n\
    00768 When trying to load or save a file, the function above has encountered a problem.");
    00769     }};
    00770
    00773
    00781   struct CImgDisplayException : CImgException {
    00782     CImgDisplayException(const char *format,...) {
    00783       cimg_exception_err("This error has been generated by a 'CImgDisplayException' throw.\n\
    00784 When trying to operate on a CImgDisplay instance, the function above encountered a problem.");
    00785     }};
    00786
    00787
    00788   /*-------------------------------------------------------------------------
    00789
    00790     Add LAPACK support to the library.
    00791
    00792     Define the macro 'cimg_lapack' before including 'CImg.h'
    00793     will activate the support of LAPACK. You'll have then to link
    00794     your code with the Lapack library to get it working.
    00795
    00796     -----------------------------------------------------------------------*/
    00797 #ifdef cimg_lapack
    00798   extern "C" {
    00799     extern void dgeev_(char*,char*, int*,double*,int*,double*,double*,double*,int*,double*,int*,double*,int*,int*);
    00800     extern void dsyev_(char*,char*,int*,double*,int*,double*,double*,int*,int*);
    00801     extern void dgetrf_(int*,int*,double*,int*,int*,int*);
    00802     extern void dgetri_(int*,double*,int*,int*,double*,int*,int*);
    00803   }
    00804 #else
    00805   inline void cimg_nolapack() {
    00806     throw CImgException("a LAPACK call : A LAPACK function has been required, but the LAPACK library\
    00807 hasn't been linked.\nPlease define the compilation flag '#define cimg_lapack' before including 'CImg.h' and link your code with LAPACK.");
    00808   }
    00809   inline void dgeev_ (char*,char*, int*,double*,int*,double*,double*,double*,int*,double*,int*,double*,int*,int*) { cimg_nolapack(); }
    00810   inline void dsyev_ (char*, char*, int*, double*, int*, double*, double*, int*, int*) { cimg_nolapack(); }
    00811   inline void dgetrf_(int*,int*,double*,int*,int*,int*) { cimg_nolapack(); }
    00812   inline void dgetri_(int*,double*,int*,int*,double*,int*,int*) { cimg_nolapack(); }
    00813 #endif
    00814
    00815
    00816   /*----------------------------------------
    00817
    00818
    00819
    00820     Definition of the namespace 'cimg'
    00821
    00822
    00823
    00824   --------------------------------------*/
    00825
    00827
    00835   namespace cimg {
    00836
    00837     // Define internal library variables.
    00838     const unsigned int lblock=1024;
    00839 #if cimg_display_type==1
    00840     static pthread_mutex_t*      X11_mutex = NULL;
    00841     static pthread_t*            X11_event_thread = NULL;
    00842     static CImgDisplay*          X11_wins[1024];
    00843     static Display*              X11_display = NULL;
    00844     static volatile unsigned int X11_nb_wins = 0;
    00845     static volatile bool         X11_thread_finished = false;
    00846     static unsigned int          X11_nb_bits = 0;
    00847     static GC*                   X11_gc = NULL;
    00848     static bool                  X11_colors_endian = false;
    00849 #endif
    00850 #ifdef cimg_color_terminal
    00851     const char t_normal[9]  = {0x1b,'[','0',';','0',';','0','m','\0'};
    00852     const char t_red[11]    = {0x1b,'[','4',';','3','1',';','5','9','m','\0'};
    00853     const char t_bold[5]    = {0x1b,'[','1','m','\0'};
    00854     const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'};
    00855 #else
    00856     const char t_normal[1]  = {'\0'};
    00857     static const char *t_red = t_normal, *t_bold = t_normal, *t_purple = t_normal;
    00858 #endif
    00859
    00860 #if cimg_OS==0 || cimg_OS==1 || cimg_OS==3
    00861     // Keycodes for X11-based graphical systems
    00862     const unsigned int keyESC        = XK_Escape;
    00863     const unsigned int keyF1         = XK_F1;
    00864     const unsigned int keyF2         = XK_F2;
    00865     const unsigned int keyF3         = XK_F3;
    00866     const unsigned int keyF4         = XK_F4;
    00867     const unsigned int keyF5         = XK_F5;
    00868     const unsigned int keyF6         = XK_F6;
    00869     const unsigned int keyF7         = XK_F7;
    00870     const unsigned int keyF8         = XK_F8;
    00871     const unsigned int keyF9         = XK_F9;
    00872     const unsigned int keyF10        = XK_F10;
    00873     const unsigned int keyF11        = XK_F11;
    00874     const unsigned int keyF12        = XK_F12;
    00875     const unsigned int keyPAUSE      = XK_Pause;
    00876     const unsigned int key1          = XK_1;
    00877     const unsigned int key2          = XK_2;
    00878     const unsigned int key3          = XK_3;
    00879     const unsigned int key4          = XK_4;
    00880     const unsigned int key5          = XK_5;
    00881     const unsigned int key6          = XK_6;
    00882     const unsigned int key7          = XK_7;
    00883     const unsigned int key8          = XK_8;
    00884     const unsigned int key9          = XK_9;
    00885     const unsigned int key0          = XK_0;
    00886     const unsigned int keyBACKSPACE  = XK_BackSpace;
    00887     const unsigned int keyINSERT     = XK_Insert;
    00888     const unsigned int keyHOME       = XK_Home;
    00889     const unsigned int keyPAGEUP     = XK_Page_Up;
    00890     const unsigned int keyTAB        = XK_Tab;
    00891     const unsigned int keyQ          = XK_q;
    00892     const unsigned int keyW          = XK_w;
    00893     const unsigned int keyE          = XK_e;
    00894     const unsigned int keyR          = XK_r;
    00895     const unsigned int keyT          = XK_t;
    00896     const unsigned int keyY          = XK_y;
    00897     const unsigned int keyU          = XK_u;
    00898     const unsigned int keyI          = XK_i;
    00899     const unsigned int keyO          = XK_o;
    00900     const unsigned int keyP          = XK_p;
    00901     const unsigned int keyDELETE     = XK_Delete;
    00902     const unsigned int keyEND        = XK_End;
    00903     const unsigned int keyPAGEDOWN   = XK_Page_Down;
    00904     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
    00905     const unsigned int keyA          = XK_a;
    00906     const unsigned int keyS          = XK_s;
    00907     const unsigned int keyD          = XK_d;
    00908     const unsigned int keyF          = XK_f;
    00909     const unsigned int keyG          = XK_g;
    00910     const unsigned int keyH          = XK_h;
    00911     const unsigned int keyJ          = XK_j;
    00912     const unsigned int keyK          = XK_k;
    00913     const unsigned int keyL          = XK_l;
    00914     const unsigned int keyENTER      = XK_Return;
    00915     const unsigned int keySHIFTLEFT  = XK_Shift_L;
    00916     const unsigned int keyZ          = XK_z;
    00917     const unsigned int keyX          = XK_x;
    00918     const unsigned int keyC          = XK_c;
    00919     const unsigned int keyV          = XK_v;
    00920     const unsigned int keyB          = XK_b;
    00921     const unsigned int keyN          = XK_n;
    00922     const unsigned int keyM          = XK_m;
    00923     const unsigned int keySHIFTRIGHT = XK_Shift_R;
    00924     const unsigned int keyARROWUP    = XK_Up;
    00925     const unsigned int keyCTRLLEFT   = XK_Control_L;
    00926     const unsigned int keyAPPLEFT    = XK_Super_L;
    00927     const unsigned int keySPACE      = XK_space;
    00928     const unsigned int keyALTGR      = XK_Alt_R;
    00929     const unsigned int keyAPPRIGHT   = XK_Super_R;
    00930     const unsigned int keyMENU       = XK_Menu;
    00931     const unsigned int keyCTRLRIGHT  = XK_Control_R;
    00932     const unsigned int keyARROWLEFT  = XK_Left;
    00933     const unsigned int keyARROWDOWN  = XK_Down;
    00934     const unsigned int keyARROWRIGHT = XK_Right;
    00935 #else
    00936     // Keycodes for Windows-OS
    00938
    00939
    00947     const unsigned int keyESC        = 27;
    00948     const unsigned int keyF1         = 112;
    00949     const unsigned int keyF2         = 113;
    00950     const unsigned int keyF3         = 114;
    00951     const unsigned int keyF4         = 115;
    00952     const unsigned int keyF5         = 116;
    00953     const unsigned int keyF6         = 117;
    00954     const unsigned int keyF7         = 118;
    00955     const unsigned int keyF8         = 119;
    00956     const unsigned int keyF9         = 120;
    00957     const unsigned int keyF10        = 121;
    00958     const unsigned int keyF11        = 122;
    00959     const unsigned int keyF12        = 123;
    00960     const unsigned int keyPAUSE      = 19;
    00961     const unsigned int key1          = 49;
    00962     const unsigned int key2          = 50;
    00963     const unsigned int key3          = 51;
    00964     const unsigned int key4          = 52;
    00965     const unsigned int key5          = 53;
    00966     const unsigned int key6          = 54;
    00967     const unsigned int key7          = 55;
    00968     const unsigned int key8          = 56;
    00969     const unsigned int key9          = 57;
    00970     const unsigned int key0          = 48;
    00971     const unsigned int keyBACKSPACE  = 8;
    00972     const unsigned int keyINSERT     = 45;
    00973     const unsigned int keyHOME       = 36;
    00974     const unsigned int keyPAGEUP     = 33;
    00975     const unsigned int keyTAB        = 9;
    00976     const unsigned int keyQ          = 81;
    00977     const unsigned int keyW          = 87;
    00978     const unsigned int keyE          = 69;
    00979     const unsigned int keyR          = 82;
    00980     const unsigned int keyT          = 84;
    00981     const unsigned int keyY          = 89;
    00982     const unsigned int keyU          = 85;
    00983     const unsigned int keyI          = 73;
    00984     const unsigned int keyO          = 79;
    00985     const unsigned int keyP          = 80;
    00986     const unsigned int keyDELETE     = 8;
    00987     const unsigned int keyEND        = 35;
    00988     const unsigned int keyPAGEDOWN   = 34;
    00989     const unsigned int keyCAPSLOCK   = 20;
    00990     const unsigned int keyA          = 65;
    00991     const unsigned int keyS          = 83;
    00992     const unsigned int keyD          = 68;
    00993     const unsigned int keyF          = 70;
    00994     const unsigned int keyG          = 71;
    00995     const unsigned int keyH          = 72;
    00996     const unsigned int keyJ          = 74;
    00997     const unsigned int keyK          = 75;
    00998     const unsigned int keyL          = 76;
    00999     const unsigned int keyENTER      = 13;
    01000     const unsigned int keySHIFTLEFT  = 16;
    01001     const unsigned int keyZ          = 90;
    01002     const unsigned int keyX          = 88;
    01003     const unsigned int keyC          = 67;
    01004     const unsigned int keyV          = 86;
    01005     const unsigned int keyB          = 66;
    01006     const unsigned int keyN          = 78;
    01007     const unsigned int keyM          = 77;
    01008     const unsigned int keySHIFTRIGHT = 16;
    01009     const unsigned int keyARROWUP    = 38;
    01010     const unsigned int keyCTRLLEFT   = 17;
    01011     const unsigned int keyAPPLEFT    = 91;
    01012     const unsigned int keySPACE      = 32;
    01013     const unsigned int keyALTGR      = 17;
    01014     const unsigned int keyAPPRIGHT   = 92;
    01015     const unsigned int keyMENU       = 93;
    01016     const unsigned int keyCTRLRIGHT  = 17;
    01017     const unsigned int keyARROWLEFT  = 37;
    01018     const unsigned int keyARROWDOWN  = 40;
    01019     const unsigned int keyARROWRIGHT = 39;
    01020 #endif
    01021
    01022     const double PI = 3.14159265358979323846;
    01023
    01024     // Definition of a 7x11x1x3 font, used to return a default font for drawing text.
    01025     const unsigned int font7x11[7*11*256/8] =
    01026       {0x00000000,
    01027        0x00000000,0x00000000,0x00000002,0x04081020,0x00800000,0x24489000,0x00000000,0x000000a1,
    01028        0x4f8a7e50,0xa0000002,0x0f287030,0x50a78200,0x00008695,0x454552c2,0x00000002,0x0a143193,
    01029        0x19f00000,0x04081000,0x00000000,0x00001841,0x02040810,0x20203006,0x02020408,0x1020410c,
    01030        0x000010d8,0xc1400000,0x00000000,0x01021f08,0x10200000,0x00000000,0x00018302,0x08000000,
    01031        0x0007c000,0x00000000,0x00000000,0x0060c000,0x0000820c,0x1040820c,0x10400000,0xe2244891,
    01032        0x22380000,0x00061408,0x102043e0,0x00000070,0x10208208,0x1e000000,0x03c0810c,0x0408e000,
    01033        0x0000020c,0x2891f040,0x80000000,0xf1020701,0x02380000,0x0001c410,0x2c6488e0,0x0000003e,
    01034        0x08104102,0x08000000,0x00e22487,0x11223800,0x00000711,0x223c0823,0x80000000,0x0060c000,
    01035        0x060c0000,0x00000306,0x00003060,0x41000000,0x0218c180,0xc0400000,0x000007f0,0x1fc00000,
    01036        0x00000010,0x180c18c2,0x00000000,0x3c440820,0x80020000,0x0000f229,0xd4afa038,0x00000002,
    01037        0x0a1444f9,0x14100000,0x00788913,0xc4489e00,0x000001e4,0x10204040,0x78000000,0x1e224489,
    01038        0x12278000,0x0000f902,0x0788103e,0x00000007,0xc8103c40,0x81000000,0x001e4102,0x34244780,
    01039        0x00000112,0x244f9122,0x44000000,0x0f840810,0x2043e000,0x00003810,0x2040811c,0x00000002,
    01040        0x248a1828,0x48880000,0x00102040,0x810207c0,0x0000019b,0x36ab56a9,0x42000000,0x044c9d2a,
    01041        0x4c991000,0x00003c85,0x0a14284f,0x00000001,0xe2244f10,0x20400000,0x000f2142,0x850a13c0,
    01042        0xc0c000f1,0x12278911,0x21000000,0x01e4080e,0x0204f000,0x00003f88,0x10204081,0x00000000,
    01043        0x89122448,0x911c0000,0x00082891,0x22285040,0x00000041,0x9325ab64,0xc8800000,0x020a2282,
    01044        0x0a228200,0x00001051,0x14102040,0x80000000,0xfc082082,0x083f0000,0x00e10204,0x08102040,
    01045        0x81c01010,0x20202040,0x40808080,0x70204081,0x02040810,0xe0008105,0x1b228200,0x00000000,
    01046        0x00000000,0x00003f80,0x20200000,0x00000000,0x00000000,0x0e023c89,0x11f00000,0x2040b192,
    01047        0x24489e00,0x00000003,0xc8102040,0x78000000,0x811e4489,0x1223c000,0x000000e2,0x27c8101e,
    01048        0x00000071,0x0fc40810,0x20400000,0x00003c89,0x12244781,0x1c008102,0xe6489122,0x44000001,
    01049        0x001c0810,0x20408000,0x00040070,0x20408102,0x04700102,0x04491c28,0x48880000,0x0e040810,
    01050        0x20408100,0x00000002,0xded93264,0xc9000000,0x000b9922,0x44891000,0x00000038,0x89122447,
    01051        0x00000000,0x02c64891,0x22788100,0x00000f22,0x448911e0,0x40800000,0xb9920408,0x10000000,
    01052        0x00078818,0x0c08e000,0x0000083e,0x20408101,0xc0000000,0x01122448,0x933a0000,0x00001051,
    01053        0x22285040,0x00000000,0x8326ad56,0xc8800000,0x00042486,0x0c248400,0x00000020,0xa24450a0,
    01054        0x831c0000,0x00f81041,0x041f0000,0x00308102,0x0c081020,0x40600204,0x08102040,0x81020400,
    01055        0x60204081,0x82040810,0xe0000000,0x00399c00,0x00000000,0x00000000,0x00000000,0x00000000,
    01056        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01057        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01058        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01059        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01060        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01061        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01062        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01063        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01064        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01065        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04001020,
    01066        0x40810000,0x00107142,0x85070400,0x000000c2,0x041c1020,0xf0000000,0x213c4891,0xe4200000,
    01067        0x00010511,0x47c21f08,0x00000081,0x02000000,0x00408100,0x001c40c1,0x62428302,0x38480000,
    01068        0x00000000,0x00000000,0x0f215aa5,0x6a13c000,0x00007871,0x23e00000,0x00000000,0x00028a28,
    01069        0x28280000,0x00000001,0xf8102000,0x00000000,0x0007c000,0x00000000,0x07113a44,0x70000000,
    01070        0x1fc00000,0x00000000,0x00000000,0x41410000,0x00000000,0x00000408,0x7c2043e0,0x0000003c,
    01071        0x30f00000,0x00000000,0x01c10700,0x00000000,0x00820000,0x00000000,0x00000000,0x01122448,
    01072        0x933a4080,0x0007ce9d,0x1a142850,0xa1400000,0x0000c180,0x00000000,0x00000000,0x00000010,
    01073        0x60000604,0x08000000,0x00000000,0x30912180,0x00000000,0x0000000a,0x0a0a28a0,0x00000032,
    01074        0x28505952,0xf8400000,0x01914282,0xe8514700,0x00000e38,0xba0e34be,0x10000000,0x00100040,
    01075        0x8208111e,0x40404142,0x889f2282,0x00004102,0x0a1444f9,0x1410000c,0x241050a2,0x27c8a080,
    01076        0x0028a082,0x85113e45,0x04000480,0x04142889,0xf2282000,0x082820a1,0x444f9141,0x00000001,
    01077        0xc60c2c50,0xe2700000,0x001e4102,0x04040782,0x0c2021f2,0x040f1020,0x7c000020,0x8f902078,
    01078        0x8103e000,0x0c247c81,0x03c4081f,0x00009003,0xe4081e20,0x40f80002,0x021f0810,0x204087c0,
    01079        0x000410f8,0x40810204,0x3e0000c2,0x47c20408,0x1021f000,0x09003e10,0x2040810f,0x80000001,
    01080        0xe2245c91,0x22780000,0xa288993a,0x54993220,0x00080879,0x0a142850,0x9e000010,0x43c850a1,
    01081        0x4284f000,0x03091e42,0x850a1427,0x80000a28,0xf2142850,0xa13c0001,0x200790a1,0x428509e0,
    01082        0x00000000,0x8490c184,0x90800000,0x01f66954,0xa966f800,0x01010891,0x22448911,0xc0000104,
    01083        0x44891224,0x488e0000,0x61222448,0x91224470,0x00048011,0x22448912,0x23800002,0x09051141,
    01084        0x02040800,0x0000040f,0x112244f1,0x0000000e,0x2448a142,0x444b8000,0x202001c0,0x4791223e,
    01085        0x00004100,0x0e023c89,0x11f0000c,0x24007011,0xe4488f80,0x0028a003,0x808f2244,0x7c000005,
    01086        0x001c0479,0x1223e000,0x082820e0,0x23c8911f,0x00000000,0x1d853e91,0x21b00000,0x00003c81,
    01087        0x02040782,0x0c202001,0xc44f9020,0x3c000041,0x000e227c,0x8101e000,0x0c240071,0x13e4080f,
    01088        0x000000a0,0x03889f20,0x40780002,0x02003810,0x20408100,0x00041001,0xc0810204,0x080000c2,
    01089        0x400e0408,0x10204000,0x000a0070,0x20408102,0x000000e1,0x21c44891,0x22380000,0xa2801732,
    01090        0x44891220,0x00080800,0x71122448,0x8e000020,0x80038891,0x22447000,0x0309001c,0x44891223,
    01091        0x80000a28,0x00e22448,0x911c0000,0x01400711,0x224488e0,0x00000000,0x2003f000,0x04000000,
    01092        0x0001e4ca,0x99327800,0x01010011,0x22448933,0xa0000410,0x00891224,0x499d0000,0x61200448,
    01093        0x91224ce8,0x00000500,0x22448912,0x67400004,0x10020a24,0x450a0831,0xc002040b,0x19224489,
    01094        0xe204000a,0x00828911,0x42820c70,0x00000000,0x00000000,0x00000002,0x04081020,0x00800000,
    01095        0x24489000,0x00000000,0x000000a1,0x4f8a7e50,0xa0000002,0x0f287030,0x50a78200,0x00008695,
    01096        0x454552c2,0x00000002,0x0a143193,0x19f00000,0x04081000,0x00000000,0x00001841,0x02040810,
    01097        0x20203006,0x02020408,0x1020410c,0x000010d8,0xc1400000,0x00000000,0x01021f08,0x10200000,
    01098        0x00000000,0x00018302,0x08000000,0x0007c000,0x00000000,0x00000000,0x0060c000,0x0000820c,
    01099        0x1040820c,0x10400000,0xe2244891,0x22380000,0x00061408,0x102043e0,0x00000070,0x10208208,
    01100        0x1e000000,0x03c0810c,0x0408e000,0x0000020c,0x2891f040,0x80000000,0xf1020701,0x02380000,
    01101        0x0001c410,0x2c6488e0,0x0000003e,0x08104102,0x08000000,0x00e22487,0x11223800,0x00000711,
    01102        0x223c0823,0x80000000,0x0060c000,0x060c0000,0x00000306,0x00003060,0x41000000,0x0218c180,
    01103        0xc0400000,0x000007f0,0x1fc00000,0x00000010,0x180c18c2,0x00000000,0x3c440820,0x80020000,
    01104        0x0000f229,0xd4afa038,0x00000002,0x0a1444f9,0x14100000,0x00788913,0xc4489e00,0x000001e4,
    01105        0x10204040,0x78000000,0x1e224489,0x12278000,0x0000f902,0x0788103e,0x00000007,0xc8103c40,
    01106        0x81000000,0x001e4102,0x34244780,0x00000112,0x244f9122,0x44000000,0x0f840810,0x2043e000,
    01107        0x00003810,0x2040811c,0x00000002,0x248a1828,0x48880000,0x00102040,0x810207c0,0x0000019b,
    01108        0x36ab56a9,0x42000000,0x044c9d2a,0x4c991000,0x00003c85,0x0a14284f,0x00000001,0xe2244f10,
    01109        0x20400000,0x000f2142,0x850a13c0,0xc0c000f1,0x12278911,0x21000000,0x01e4080e,0x0204f000,
    01110        0x00003f88,0x10204081,0x00000000,0x89122448,0x911c0000,0x00082891,0x22285040,0x00000041,
    01111        0x9325ab64,0xc8800000,0x020a2282,0x0a228200,0x00001051,0x14102040,0x80000000,0xfc082082,
    01112        0x083f0000,0x00e10204,0x08102040,0x81c01010,0x20202040,0x40808080,0x70204081,0x02040810,
    01113        0xe0008105,0x1b228200,0x00000000,0x00000000,0x00003f80,0x20200000,0x00000000,0x00000000,
    01114        0x0e023c89,0x11f00000,0x2040b192,0x24489e00,0x00000003,0xc8102040,0x78000000,0x811e4489,
    01115        0x1223c000,0x000000e2,0x27c8101e,0x00000071,0x0fc40810,0x20400000,0x00003c89,0x12244781,
    01116        0x1c008102,0xe6489122,0x44000001,0x001c0810,0x20408000,0x00040070,0x20408102,0x04700102,
    01117        0x04491c28,0x48880000,0x0e040810,0x20408100,0x00000002,0xded93264,0xc9000000,0x000b9922,
    01118        0x44891000,0x00000038,0x89122447,0x00000000,0x02c64891,0x22788100,0x00000f22,0x448911e0,
    01119        0x40800000,0xb9920408,0x10000000,0x00078818,0x0c08e000,0x0000083e,0x20408101,0xc0000000,
    01120        0x01122448,0x933a0000,0x00001051,0x22285040,0x00000000,0x8326ad56,0xc8800000,0x00042486,
    01121        0x0c248400,0x00000020,0xa24450a0,0x831c0000,0x00f81041,0x041f0000,0x00308102,0x0c081020,
    01122        0x40600204,0x08102040,0x81020400,0x60204081,0x82040810,0xe0000000,0x00399c00,0x00000000,
    01123        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01124        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01125        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01126        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01127        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01128        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01129        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01130        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01131        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01132        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01133        0x00000000,0x00000000,0x04001020,0x40810000,0x00107142,0x85070400,0x000000c2,0x041c1020,
    01134        0xf0000000,0x213c4891,0xe4200000,0x00010511,0x47c21f08,0x00000081,0x02000000,0x00408100,
    01135        0x001c40c1,0x62428302,0x38480000,0x00000000,0x00000000,0x0f215aa5,0x6a13c000,0x00007871,
    01136        0x23e00000,0x00000000,0x00028a28,0x28280000,0x00000001,0xf8102000,0x00000000,0x0007c000,
    01137        0x00000000,0x07113a44,0x70000000,0x1fc00000,0x00000000,0x00000000,0x41410000,0x00000000,
    01138        0x00000408,0x7c2043e0,0x0000003c,0x30f00000,0x00000000,0x01c10700,0x00000000,0x00820000,
    01139        0x00000000,0x00000000,0x01122448,0x933a4080,0x0007ce9d,0x1a142850,0xa1400000,0x0000c180,
    01140        0x00000000,0x00000000,0x00000010,0x60000604,0x08000000,0x00000000,0x30912180,0x00000000,
    01141        0x0000000a,0x0a0a28a0,0x00000032,0x28505952,0xf8400000,0x01914282,0xe8514700,0x00000e38,
    01142        0xba0e34be,0x10000000,0x00100040,0x8208111e,0x40404142,0x889f2282,0x00004102,0x0a1444f9,
    01143        0x1410000c,0x241050a2,0x27c8a080,0x0028a082,0x85113e45,0x04000480,0x04142889,0xf2282000,
    01144        0x082820a1,0x444f9141,0x00000001,0xc60c2c50,0xe2700000,0x001e4102,0x04040782,0x0c2021f2,
    01145        0x040f1020,0x7c000020,0x8f902078,0x8103e000,0x0c247c81,0x03c4081f,0x00009003,0xe4081e20,
    01146        0x40f80002,0x021f0810,0x204087c0,0x000410f8,0x40810204,0x3e0000c2,0x47c20408,0x1021f000,
    01147        0x09003e10,0x2040810f,0x80000001,0xe2245c91,0x22780000,0xa288993a,0x54993220,0x00080879,
    01148        0x0a142850,0x9e000010,0x43c850a1,0x4284f000,0x03091e42,0x850a1427,0x80000a28,0xf2142850,
    01149        0xa13c0001,0x200790a1,0x428509e0,0x00000000,0x8490c184,0x90800000,0x01f66954,0xa966f800,
    01150        0x01010891,0x22448911,0xc0000104,0x44891224,0x488e0000,0x61222448,0x91224470,0x00048011,
    01151        0x22448912,0x23800002,0x09051141,0x02040800,0x0000040f,0x112244f1,0x0000000e,0x2448a142,
    01152        0x444b8000,0x202001c0,0x4791223e,0x00004100,0x0e023c89,0x11f0000c,0x24007011,0xe4488f80,
    01153        0x0028a003,0x808f2244,0x7c000005,0x001c0479,0x1223e000,0x082820e0,0x23c8911f,0x00000000,
    01154        0x1d853e91,0x21b00000,0x00003c81,0x02040782,0x0c202001,0xc44f9020,0x3c000041,0x000e227c,
    01155        0x8101e000,0x0c240071,0x13e4080f,0x000000a0,0x03889f20,0x40780002,0x02003810,0x20408100,
    01156        0x00041001,0xc0810204,0x080000c2,0x400e0408,0x10204000,0x000a0070,0x20408102,0x000000e1,
    01157        0x21c44891,0x22380000,0xa2801732,0x44891220,0x00080800,0x71122448,0x8e000020,0x80038891,
    01158        0x22447000,0x0309001c,0x44891223,0x80000a28,0x00e22448,0x911c0000,0x01400711,0x224488e0,
    01159        0x00000000,0x2003f000,0x04000000,0x0001e4ca,0x99327800,0x01010011,0x22448933,0xa0000410,
    01160        0x00891224,0x499d0000,0x61200448,0x91224ce8,0x00000500,0x22448912,0x67400004,0x10020a24,
    01161        0x450a0831,0xc002040b,0x19224489,0xe204000a,0x00828911,0x42820c70,0x00000000,0x00000000,
    01162        0x00000002,0x04081020,0x00800000,0x24489000,0x00000000,0x000000a1,0x4f8a7e50,0xa0000002,
    01163        0x0f287030,0x50a78200,0x00008695,0x454552c2,0x00000002,0x0a143193,0x19f00000,0x04081000,
    01164        0x00000000,0x00001841,0x02040810,0x20203006,0x02020408,0x1020410c,0x000010d8,0xc1400000,
    01165        0x00000000,0x01021f08,0x10200000,0x00000000,0x00018302,0x08000000,0x0007c000,0x00000000,
    01166        0x00000000,0x0060c000,0x0000820c,0x1040820c,0x10400000,0xe2244891,0x22380000,0x00061408,
    01167        0x102043e0,0x00000070,0x10208208,0x1e000000,0x03c0810c,0x0408e000,0x0000020c,0x2891f040,
    01168        0x80000000,0xf1020701,0x02380000,0x0001c410,0x2c6488e0,0x0000003e,0x08104102,0x08000000,
    01169        0x00e22487,0x11223800,0x00000711,0x223c0823,0x80000000,0x0060c000,0x060c0000,0x00000306,
    01170        0x00003060,0x41000000,0x0218c180,0xc0400000,0x000007f0,0x1fc00000,0x00000010,0x180c18c2,
    01171        0x00000000,0x3c440820,0x80020000,0x0000f229,0xd4afa038,0x00000002,0x0a1444f9,0x14100000,
    01172        0x00788913,0xc4489e00,0x000001e4,0x10204040,0x78000000,0x1e224489,0x12278000,0x0000f902,
    01173        0x0788103e,0x00000007,0xc8103c40,0x81000000,0x001e4102,0x34244780,0x00000112,0x244f9122,
    01174        0x44000000,0x0f840810,0x2043e000,0x00003810,0x2040811c,0x00000002,0x248a1828,0x48880000,
    01175        0x00102040,0x810207c0,0x0000019b,0x36ab56a9,0x42000000,0x044c9d2a,0x4c991000,0x00003c85,
    01176        0x0a14284f,0x00000001,0xe2244f10,0x20400000,0x000f2142,0x850a13c0,0xc0c000f1,0x12278911,
    01177        0x21000000,0x01e4080e,0x0204f000,0x00003f88,0x10204081,0x00000000,0x89122448,0x911c0000,
    01178        0x00082891,0x22285040,0x00000041,0x9325ab64,0xc8800000,0x020a2282,0x0a228200,0x00001051,
    01179        0x14102040,0x80000000,0xfc082082,0x083f0000,0x00e10204,0x08102040,0x81c01010,0x20202040,
    01180        0x40808080,0x70204081,0x02040810,0xe0008105,0x1b228200,0x00000000,0x00000000,0x00003f80,
    01181        0x20200000,0x00000000,0x00000000,0x0e023c89,0x11f00000,0x2040b192,0x24489e00,0x00000003,
    01182        0xc8102040,0x78000000,0x811e4489,0x1223c000,0x000000e2,0x27c8101e,0x00000071,0x0fc40810,
    01183        0x20400000,0x00003c89,0x12244781,0x1c008102,0xe6489122,0x44000001,0x001c0810,0x20408000,
    01184        0x00040070,0x20408102,0x04700102,0x04491c28,0x48880000,0x0e040810,0x20408100,0x00000002,
    01185        0xded93264,0xc9000000,0x000b9922,0x44891000,0x00000038,0x89122447,0x00000000,0x02c64891,
    01186        0x22788100,0x00000f22,0x448911e0,0x40800000,0xb9920408,0x10000000,0x00078818,0x0c08e000,
    01187        0x0000083e,0x20408101,0xc0000000,0x01122448,0x933a0000,0x00001051,0x22285040,0x00000000,
    01188        0x8326ad56,0xc8800000,0x00042486,0x0c248400,0x00000020,0xa24450a0,0x831c0000,0x00f81041,
    01189        0x041f0000,0x00308102,0x0c081020,0x40600204,0x08102040,0x81020400,0x60204081,0x82040810,
    01190        0xe0000000,0x00399c00,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01191        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01192        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01193        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01194        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01195        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01196        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01197        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01198        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01199        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01200        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04001020,0x40810000,0x00107142,
    01201        0x85070400,0x000000c2,0x041c1020,0xf0000000,0x213c4891,0xe4200000,0x00010511,0x47c21f08,
    01202        0x00000081,0x02000000,0x00408100,0x001c40c1,0x62428302,0x38480000,0x00000000,0x00000000,
    01203        0x0f215aa5,0x6a13c000,0x00007871,0x23e00000,0x00000000,0x00028a28,0x28280000,0x00000001,
    01204        0xf8102000,0x00000000,0x0007c000,0x00000000,0x07113a44,0x70000000,0x1fc00000,0x00000000,
    01205        0x00000000,0x41410000,0x00000000,0x00000408,0x7c2043e0,0x0000003c,0x30f00000,0x00000000,
    01206        0x01c10700,0x00000000,0x00820000,0x00000000,0x00000000,0x01122448,0x933a4080,0x0007ce9d,
    01207        0x1a142850,0xa1400000,0x0000c180,0x00000000,0x00000000,0x00000010,0x60000604,0x08000000,
    01208        0x00000000,0x30912180,0x00000000,0x0000000a,0x0a0a28a0,0x00000032,0x28505952,0xf8400000,
    01209        0x01914282,0xe8514700,0x00000e38,0xba0e34be,0x10000000,0x00100040,0x8208111e,0x40404142,
    01210        0x889f2282,0x00004102,0x0a1444f9,0x1410000c,0x241050a2,0x27c8a080,0x0028a082,0x85113e45,
    01211        0x04000480,0x04142889,0xf2282000,0x082820a1,0x444f9141,0x00000001,0xc60c2c50,0xe2700000,
    01212        0x001e4102,0x04040782,0x0c2021f2,0x040f1020,0x7c000020,0x8f902078,0x8103e000,0x0c247c81,
    01213        0x03c4081f,0x00009003,0xe4081e20,0x40f80002,0x021f0810,0x204087c0,0x000410f8,0x40810204,
    01214        0x3e0000c2,0x47c20408,0x1021f000,0x09003e10,0x2040810f,0x80000001,0xe2245c91,0x22780000,
    01215        0xa288993a,0x54993220,0x00080879,0x0a142850,0x9e000010,0x43c850a1,0x4284f000,0x03091e42,
    01216        0x850a1427,0x80000a28,0xf2142850,0xa13c0001,0x200790a1,0x428509e0,0x00000000,0x8490c184,
    01217        0x90800000,0x01f66954,0xa966f800,0x01010891,0x22448911,0xc0000104,0x44891224,0x488e0000,
    01218        0x61222448,0x91224470,0x00048011,0x22448912,0x23800002,0x09051141,0x02040800,0x0000040f,
    01219        0x112244f1,0x0000000e,0x2448a142,0x444b8000,0x202001c0,0x4791223e,0x00004100,0x0e023c89,
    01220        0x11f0000c,0x24007011,0xe4488f80,0x0028a003,0x808f2244,0x7c000005,0x001c0479,0x1223e000,
    01221        0x082820e0,0x23c8911f,0x00000000,0x1d853e91,0x21b00000,0x00003c81,0x02040782,0x0c202001,
    01222        0xc44f9020,0x3c000041,0x000e227c,0x8101e000,0x0c240071,0x13e4080f,0x000000a0,0x03889f20,
    01223        0x40780002,0x02003810,0x20408100,0x00041001,0xc0810204,0x080000c2,0x400e0408,0x10204000,
    01224        0x000a0070,0x20408102,0x000000e1,0x21c44891,0x22380000,0xa2801732,0x44891220,0x00080800,
    01225        0x71122448,0x8e000020,0x80038891,0x22447000,0x0309001c,0x44891223,0x80000a28,0x00e22448,
    01226        0x911c0000,0x01400711,0x224488e0,0x00000000,0x2003f000,0x04000000,0x0001e4ca,0x99327800,
    01227        0x01010011,0x22448933,0xa0000410,0x00891224,0x499d0000,0x61200448,0x91224ce8,0x00000500,
    01228        0x22448912,0x67400004,0x10020a24,0x450a0831,0xc002040b,0x19224489,0xe204000a,0x00828911,
    01229        0x42820c70};
    01230
    01231     // Return a 'stringification' of standart integral types.
    01232     const char* const bool_st    = "bool";
    01233     const char* const uchar_st   = "unsigned char";
    01234     const char* const char_st    = "char";
    01235     const char* const ushort_st  = "unsigned short";
    01236     const char* const short_st   = "short";
    01237     const char* const uint_st    = "unsigned int";
    01238     const char* const int_st     = "int";
    01239     const char* const ulong_st   = "unsigned long";
    01240     const char* const long_st    = "long";
    01241     const char* const float_st   = "float";
    01242     const char* const double_st  = "double";
    01243     const char* const unknown_st = "unknown";
    01244     template<typename t> inline const char* get_type(const t&) { return unknown_st; }
    01245     inline const char* get_type(const bool&          ) { return bool_st;   }
    01246     inline const char* get_type(const unsigned char& ) { return uchar_st;  }
    01247     inline const char* get_type(const char&          ) { return char_st;   }
    01248     inline const char* get_type(const unsigned short&) { return ushort_st; }
    01249     inline const char* get_type(const short&         ) { return short_st;  }
    01250     inline const char* get_type(const unsigned int&  ) { return uint_st;   }
    01251     inline const char* get_type(const int&           ) { return int_st;    }
    01252     inline const char* get_type(const unsigned long& ) { return ulong_st;  }
    01253     inline const char* get_type(const long&          ) { return long_st;   }
    01254     inline const char* get_type(const float&         ) { return float_st;  }
    01255     inline const char* get_type(const double&        ) { return double_st; }
    01256
    01257 #if cimg_debug>=1
    01258     static void warn(const bool cond,const char *format,...) {
    01259       if (cond) {
    01260         va_list ap;
    01261         va_start(ap,format);
    01262         std::fprintf(stderr,"<CImg Warning> ");
    01263         std::vfprintf(stderr,format,ap);
    01264         std::fputc('\n',stderr);
    01265         va_end(ap);
    01266       }
    01267     }
    01268 #else
    01269     inline void warn(const bool cond,const char *format,...) {}
    01270 #endif
    01271
    01272     inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; }
    01273     inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); }
    01274     inline float atof(const char *str) {
    01275       float x=0,y=1;
    01276       if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
    01277     }
    01278     inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; }
    01279     inline int strncmp(const char *s1,const char *s2,const int l) {
    01280       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=abs(s1[k] - s2[k]); return n; }
    01281       return 0;
    01282     }
    01283     inline int strncasecmp(const char *s1,const char *s2,const int l) {
    01284       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=abs(uncase(s1[k])-uncase(s2[k])); return n; }
    01285       return 0;
    01286     }
    01287     inline int strcmp(const char *s1,const char *s2)     {
    01288       const int l1 = strlen(s1), l2 = strlen(s2);
    01289       return strncmp(s1,s2,1+(l1<l2?l1:l2));
    01290     }
    01291     inline int strcasecmp(const char *s1,const char *s2) {
    01292       const int l1 = strlen(s1), l2 = strlen(s2);
    01293       return strncasecmp(s1,s2,1+(l1<l2?l1:l2));
    01294     }
    01295     inline int strfind(const char *s,const char c) {
    01296       if (s) {
    01297         int l; for (l=strlen(s); l>=0 && s[l]!=c; l--) ;
    01298         return l;
    01299       }
    01300       return -1;
    01301     }
    01302     inline const char* basename(const char *s)  { return (cimg_OS!=2)?(s?s+1+strfind(s,'/'):NULL):(s?s+1+strfind(s,'\\'):NULL); }
    01303
    01304     inline void system(const char *command) {
    01305 #if cimg_OS==2
    01306       PROCESS_INFORMATION pi;
    01307       STARTUPINFO si;
    01308       GetStartupInfo(&si);
    01309       si.wShowWindow = SW_HIDE;
    01310       si.dwFlags |= SW_HIDE;
    01311       BOOL res = CreateProcess(NULL,(LPSTR)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
    01312       if (res) {
    01313         WaitForSingleObject(pi.hProcess, INFINITE);
    01314         CloseHandle(pi.hThread);
    01315         CloseHandle(pi.hProcess);
    01316       }
    01317 #else
    01318       ::system(command);
    01319 #endif
    01320     }
    01321
    01323
    01342     inline const char* convert_path() {
    01343       static char *convert_path = NULL;
    01344       if (!convert_path) {
    01345 #if cimg_OS==2 || defined(cimg_convert_path)
    01346         bool stopflag = false;
    01347         std::FILE *file;
    01348 #endif
    01349         convert_path = new char[1024];
    01350 #ifdef cimg_convert_path
    01351         std::strcpy(convert_path,cimg_convert_path);
    01352         if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
    01353 #endif
    01354 #if cimg_OS==2
    01355         for (int k=0; k<=9 && !stopflag; k++) {
    01356           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%d-Q\\convert.exe",k);
    01357           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
    01358         }
    01359         if (!stopflag) std::strcpy(convert_path,"convert.exe");
    01360 #else
    01361         std::strcpy(convert_path,"convert");
    01362 #endif
    01363       }
    01364       return convert_path;
    01365     }
    01366
    01368
    01385     inline const char* temporary_path() {
    01386       static char *temporary_path = NULL;
    01387       if (!temporary_path) {
    01388         temporary_path = new char[1024];
    01389 #ifdef cimg_temporary_path
    01390         std::strcpy(temporary_path,cimg_temporary_path);
    01391         const char* testing_path[7] = { temporary_path, "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
    01392 #else
    01393         const char* testing_path[6] = { "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
    01394 #endif
    01395         char filetmp[1024];
    01396         std::FILE *file=NULL;
    01397         int i=-1;
    01398         while (!file && testing_path[++i]) {
    01399           std::sprintf(filetmp,"%s/CImg%.4d.ppm",testing_path[i],std::rand()%10000);
    01400           if ((file=std::fopen(filetmp,"w"))!=NULL) { std::fclose(file); std::remove(filetmp); }
    01401         }
    01402         if (!file) throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n\
    01403 you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n \
    01404 #define cimg_temporary_path \"path\" (before including 'CImg.h')");
    01405         std::strcpy(temporary_path,testing_path[i]);
    01406       }
    01407       return temporary_path;
    01408     }
    01409
    01410     inline const char *filename_split(const char *const filename, char *const body=NULL) {
    01411       if (!filename) throw CImgArgumentException("cimg::filename_split() : Can't split the (null) filename");
    01412       int l=strfind(filename,'.');
    01413       if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }}
    01414       else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; }
    01415       return filename+l+1;
    01416     }
    01417
    01418     inline char* file_number(const char *filename,const int number,const unsigned int n,char *const string) {
    01419       char format[1024],body[1024];
    01420       const char *ext = filename_split(filename,body);
    01421       if (n>0) std::sprintf(format,"%s_%%.%dd.%s",body,n,ext);
    01422       else std::sprintf(format,"%s_%%d.%s",body,ext);
    01423       std::sprintf(string,format,number);
    01424       return string;
    01425     }
    01426     inline std::FILE *fopen(const char *const path,const char *const mode) {
    01427       if(!path || !mode) throw CImgArgumentException("cimg::fopen() : Can't open file '%s' with mode '%s'",path,mode);
    01428       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; else {
    01429         std::FILE *dest=std::fopen(path,mode);
    01430         if(!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened %s",
    01431                                         path,mode[0]=='r'?"for reading":(mode[0]=='w'?"for writing":""),path);
    01432         return dest;
    01433       }
    01434     }
    01435     inline int fclose(std::FILE *file) {
    01436       warn(!file,"cimg::fclose() : Can't close (null) file");
    01437       if (!file || file==stdin || file==stdout) return 0;
    01438       const int errn=std::fclose(file);
    01439       warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn);
    01440       return errn;
    01441     }
    01442     inline int fread(void *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
    01443       if (!ptr || size<=0 || nmemb<=0 || !stream)
    01444         throw CImgArgumentException("cimg::fread() : Can't read %dx%d bytes of file pointer '%p' in buffer '%p'",
    01445                                     nmemb,size,stream,ptr);
    01446       const unsigned int errn = (unsigned int)std::fread(ptr,size,nmemb,stream);
    01447       warn(errn!=nmemb,"cimg::fread() : File reading problems, only %d/%d elements read",errn,nmemb);
    01448       return errn;
    01449     }
    01450     inline int fwrite(const void *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
    01451       if (!ptr || size<=0 || nmemb<=0 || !stream)
    01452         throw CImgArgumentException("cimg::fwrite() : Can't write %dx%d bytes of file pointer '%p' from buffer '%p'",
    01453                                     nmemb,size,stream,ptr);
    01454       const unsigned int errn = (unsigned int)std::fwrite(ptr,size,nmemb,stream);
    01455       if(errn!=nmemb)
    01456         throw CImgIOException("cimg::fwrite() : File writing problems, only %d/%d elements written",errn,nmemb);
    01457       return errn;
    01458     }
    01459     inline void bswap(void *const xbuffer,const unsigned int size,const unsigned int n) {
    01460       char minibuf[32],*buffer=(char*)xbuffer;
    01461       if (!buffer || n>32)
    01462         throw CImgArgumentException("cimg::bswap() : Can't swap buffer %p with blocks of size %d",buffer,n);
    01463       for (unsigned int y=0; y<size; y++) {
    01464         { for (unsigned int x=0; x<n; x++) minibuf[x] = *(buffer++); }
    01465         { for (unsigned int x=0; x<n; x++) *(--buffer) = minibuf[x]; }
    01466         buffer+=n;
    01467       }
    01468     }
    01469     inline void inr_header_read(std::FILE *file,int out[8],float *voxsize=NULL) {
    01470       char item[1024],tmp1[64],tmp2[64];
    01471       out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1;
    01472       fscanf(file,"%63s",item);
    01473       if(strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
    01474         throw CImgIOException("cimg::inr_header_read() : INRIMAGE-4 Header not found");
    01475       while (fscanf(file," %63[^\n]%*c",item)!=EOF  && strncmp(item,"##}",3)) {
    01476         std::sscanf(item," XDIM%*[^0-9]%d",out);
    01477         std::sscanf(item," YDIM%*[^0-9]%d",out+1);
    01478         std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
    01479         std::sscanf(item," VDIM%*[^0-9]%d",out+3);
    01480         std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
    01481         if (voxsize) {
    01482           std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize);
    01483           std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1);
    01484           std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2);
    01485         }
    01486         if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=strncasecmp(tmp1,"sun",3)?1:0;
    01487         switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
    01488         case 0: break;
    01489         case 2: out[5] = strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
    01490         case 1:
    01491           if (!strncasecmp(tmp1,"int",3)   || !strncasecmp(tmp1,"fixed",5))  out[4]=0;
    01492           if (!strncasecmp(tmp1,"float",5) || !strncasecmp(tmp1,"double",6)) out[4]=1;
    01493           if (!strncasecmp(tmp1,"packed",6))                                       out[4]=2;
    01494           if (out[4]>=0) break;
    01495         default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
    01496         }
    01497       }
    01498       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
    01499         throw CImgIOException("cimg::inr_header_read() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
    01500                               out[0],out[1],out[2],out[3]);
    01501       if(out[4]<0 || out[5]<0) throw CImgIOException("cimg::inr_header_read() : TYPE is not fully defined");
    01502       if(out[6]<0) throw CImgIOException("cimg::inr_header_read() : PIXSIZE is not fully defined");
    01503       if(out[7]<0) throw CImgIOException("cimg::inr_header_read() : CPU type is not fully defined");
    01504     }
    01505
    01506     inline const char* option(const char *const name,const unsigned int argc,char **argv,const char *const defaut,
    01507                               const char *const usage=NULL) {
    01508       static bool first=true, visu=false;
    01509       const char *res = NULL;
    01510       if (first) { first=false; visu = option("-h",argc,argv,(const char*)NULL)!=NULL; }
    01511       if (!name && visu) {
    01512         std::fprintf(stderr,"\n %s%s%s",t_red,basename(argv[0]),t_normal);
    01513         if (usage) std::fprintf(stderr," : %s",usage);
    01514         std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__);
    01515       }
    01516       if (name) {
    01517         if (argc>0) {
    01518           unsigned int k=0,i;
    01519           while (k<argc && strcmp(argv[k],name)) k++;
    01520           i=k;
    01521           res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
    01522         } else res = defaut;
    01523         if (visu && usage) std::fprintf(stderr,"    %s%-8s%s = %-12s : %s%s%s\n",
    01524                                         t_bold,name,t_normal,res?res:"NULL",t_purple,usage,t_normal);
    01525       }
    01526       return res;
    01527     }
    01528     inline bool option(const char *const name,const unsigned int argc,char **argv,
    01529                        const bool defaut,const char *const usage=NULL) {
    01530       const char *s = option(name,argc,argv,(const char*)NULL);
    01531       const bool res = s?(strcasecmp(s,"false") && strcasecmp(s,"off") && strcasecmp(s,"0")):defaut;
    01532       option(name,0,NULL,res?"true":"false",usage);
    01533       return res;
    01534     }
    01535     inline int option(const char *const name,const unsigned int argc,char **argv,
    01536                       const int defaut,const char *const usage=NULL) {
    01537       const char *s = option(name,argc,argv,(const char*)NULL);
    01538       const int res = s?atoi(s):defaut;
    01539       char tmp[256];
    01540       std::sprintf(tmp,"%d",res);
    01541       option(name,0,NULL,tmp,usage);
    01542       return res;
    01543     }
    01544     inline char option(const char *const name,const unsigned int argc,char **argv,
    01545                        const char defaut,const char *const usage=NULL) {
    01546       const char *s = option(name,argc,argv,(const char*)NULL);
    01547       const char res = s?s[0]:defaut;
    01548       char tmp[8];
    01549       tmp[0] = res;
    01550       tmp[1] ='\0';
    01551       option(name,0,NULL,tmp,usage);
    01552       return res;
    01553     }
    01554     inline double option(const char *const name,const unsigned int argc,char **argv,
    01555                          const double defaut,const char *const usage=NULL) {
    01556       const char *s = option(name,argc,argv,(const char*)NULL);
    01557       const double res = s?atof(s):defaut;
    01558       char tmp[256];
    01559       std::sprintf(tmp,"%g",res);
    01560       option(name,0,NULL,tmp,usage);
    01561       return res;
    01562     }
    01563
    01564     inline const bool CPU_endian() { const int x=1; return ((unsigned char*)&x)[0]?true:false; }
    01565
    01567     inline void info() {
    01568       std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n",
    01569                    t_red,cimg_version,t_normal,__DATE__,__TIME__);
    01570       std::fprintf(stderr,"  > Architecture   : %s%-12s%s %s(cimg_OS=%d)\n%s",
    01571                    t_bold,
    01572                    cimg_OS==0?"Solaris":(cimg_OS==1?"Linux":(cimg_OS==2?"Windows":(cimg_OS==3?"Mac OS X":(cimg_OS==4?"FreeBSD":"Unknown")))),
    01573                    t_normal,t_purple,cimg_OS,t_normal);
    01574       std::fprintf(stderr,"  > Display type   : %s%-12s%s %s(cimg_display_type=%d)%s\n",
    01575                    t_bold,cimg_display_type==0?"No":(cimg_display_type==1?"X11":(cimg_display_type==2?"WindowsGDI":"Unknown")),t_normal,t_purple,cimg_display_type,t_normal);
    01576 #ifdef cimg_color_terminal
    01577       std::fprintf(stderr,"  > Color terminal : %s%-12s%s %s(cimg_color_terminal defined)%s\n",t_bold,"Yes",t_normal,t_purple,t_normal);
    01578 #else
    01579       std::fprintf(stderr,"  > Color terminal : %-12s (cimg_color_terminal undefined)\n","No");
    01580 #endif
    01581 #ifdef cimg_lapack
    01582       std::fprintf(stderr,"  > Using LAPACK   : %s%-12s%s %s(cimg_lapack defined)%s\n",t_bold,"Yes",t_normal,t_purple,t_normal);
    01583 #else
    01584       std::fprintf(stderr,"  > Using LAPACK   : %s%-12s%s %s(cimg_lapack undefined)%s\n",t_bold,"No",t_normal,t_purple,t_normal);
    01585 #endif
    01586       std::fprintf(stderr,"  > Debug messages : %s%-12s%s %s(cimg_debug=%d)%s\n",t_bold,cimg_debug==2?"High":(cimg_debug==1?"Yes":"No"),
    01587                    t_normal,t_purple,cimg_debug,t_normal);
    01588       std::fprintf(stderr,"\n");
    01589     }
    01590
    01592     inline long int time() {
    01593 #if cimg_OS==0 || cimg_OS==1 || cimg_OS==3 || cimg_OS==4
    01594       struct timeval st_time;
    01595       gettimeofday(&st_time,NULL);
    01596       return (long int)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
    01597 #elif cimg_OS==2
    01598       static SYSTEMTIME st_time;
    01599       GetSystemTime(&st_time);
    01600       return (long int)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
    01601 #else
    01602       return 0;
    01603 #endif
    01604     }
    01605
    01607
    01612     inline void sleep(const int milliseconds) {
    01613 #if cimg_OS==0 || cimg_OS==1 || cimg_OS==3 || cimg_OS==4
    01614       struct timespec tv;
    01615       tv.tv_sec = milliseconds/1000;
    01616       tv.tv_nsec = (milliseconds%1000)*1000000;
    01617       nanosleep(&tv,NULL);
    01618 #elif cimg_OS==2
    01619       Sleep(milliseconds);
    01620 #endif
    01621     }
    01623
    01628     inline long int wait(const int milliseconds=20,long int reference_time=-1) {
    01629       static long int latest_time = time();
    01630       if (reference_time>=0) latest_time = reference_time;
    01631       const long int current_time = time(), time_diff = milliseconds + latest_time - current_time;
    01632       if (time_diff>0) { sleep(time_diff); return (latest_time = current_time + time_diff); }
    01633       else return (latest_time = current_time);
    01634     }
    01636     template<typename T> inline const T rol(const T& a,const unsigned int n=1) { return (a<<n)|(a>>((sizeof(T)<<3)-n)); }
    01638     template<typename T> inline const T ror(const T& a,const unsigned int n=1) { return (a>>n)|(a<<((sizeof(T)<<3)-n)); }
    01639     // Exchange the values of variables \p a and \p b
    01640     template<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; }
    01641     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2) { swap(a1,b1); swap(a2,b2); }
    01642     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3) { swap(a1,b1,a2,b2); swap(a3,b3); }
    01643     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4) { swap(a1,b1,a2,b2,a3,b3); swap(a4,b4); }
    01644     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4,T& a5,T& b5) {
    01645       swap(a1,b1,a2,b2,a3,b3,a4,b4); swap(a5,b5);
    01646     }
    01647     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4,T& a5,T& b5,T& a6,T& b6) {
    01648       swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); swap(a6,b6);
    01649     }
    01650
    01651 #if ( !defined(_MSC_VER) || _MSC_VER>1200 )
    01652
    01653     template<typename T> inline const T abs(const T& a) { return a>=0?a:-a; }
    01655     template<typename T> inline const T& min(const T& a,const T& b) { return a<=b?a:b; }
    01657     template<typename T> inline const T& min(const T& a,const T& b,const T& c) { return min(min(a,b),c); }
    01659     template<typename T> inline const T& min(const T& a,const T& b,const T& c,const T& d) { return min(min(min(a,b),c),d); }
    01661     template<typename T> inline const T& max(const T& a,const T& b) { return a>=b?a:b; }
    01663     template<typename T> inline const T& max(const T& a,const T& b,const T& c) { return max(max(a,b),c); }
    01665     template<typename T> inline const T& max(const T& a,const T& b,const T& c,const T& d) { return max(max(a,b,c),d); }
    01667     template<typename T> inline char sign(const T& x) { return (x<0)?-1:(x==0?0:1); }
    01668 #else
    01669     // Special versions due to object reference bug in VisualC++ 6.0.
    01670     template<typename T> inline const T abs(const T a) { return a>=0?a:-a; }
    01671     template<typename T> inline const T min(const T a,const T b) { return a<=b?a:b; }
    01672     template<typename T> inline const T min(const T a,const T b,const T c) { return min(min(a,b),c); }
    01673     template<typename T> inline const T min(const T a,const T b,const T c,const T& d) { return min(min(min(a,b),c),d); }
    01674     template<typename T> inline const T max(const T a,const T b) { return a>=b?a:b; }
    01675     template<typename T> inline const T max(const T a,const T b,const T c) { return max(max(a,b),c); }
    01676     template<typename T> inline const T max(const T a,const T b,const T c,const T& d) { return max(max(max(a,b),c),d); }
    01677     template<typename T> inline char sign(const T x) { return (x<0)?-1:(x==0?0:1); }
    01678 #endif
    01679
    01681
    01684     template<typename T> inline T mod(const T& x,const T& m) { return x-m*(T)std::floor((double)x/m); }
    01686
    01689     inline int modi(const int x,const int m) { return x>=0?x%m:(x%m?m+x%m:0); }
    01691
    01696     template<typename T> inline T minmod(const T& a,const T& b) { return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a)); }
    01698     inline double rand() { return (double)std::rand()/RAND_MAX; }
    01700     inline double crand() { return 1-2*rand(); }
    01702     inline double grand() { return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*rand())))*std::cos((double)(2*PI*rand())); }
    01703   };
    01704
    01705   /*-------------------------------------------------------
    01706
    01707
    01708
    01709
    01710     Definition of the CImgStats structure
    01711
    01712
    01713
    01714
    01715     ------------------------------------------------------*/
    01717
    01731   struct CImgStats {
    01732     double min;
    01733     double max;
    01734     double mean;
    01735     double variance;
    01736
    01738     CImgStats():min(0),max(0),mean(0),variance(0) {}
    01740     CImgStats(const CImgStats& stats):min(stats.min),max(stats.max),mean(stats.mean),variance(stats.variance) {};
    01741
    01743
    01746     template<typename T> CImgStats(const CImg<T>& img,const bool compute_variance=true):mean(0),variance(0) {
    01747       cimg_test(img,"CImgStats::CImgStats");
    01748       T pmin=img[0], pmax=pmin;
    01749       cimg_map(img,ptr,T) { const T& a=*ptr; mean+=(double)a; if (a<pmin) pmin=a; if (a>pmax) pmax=a; }
    01750       mean/=img.size();
    01751       min=(double)pmin;
    01752       max=(double)pmax;
    01753       if (compute_variance) {
    01754         cimg_map(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
    01755         variance = std::sqrt(variance/img.size());
    01756       }
    01757     }
    01759
    01763     template<typename T> CImgStats(const CImgl<T>& list,const bool compute_variance=true):mean(0),variance(0) {
    01764       cimgl_test(list,"CImgStats::CImgStats");
    01765       T pmin=list[0][0], pmax=pmin;
    01766       int psize=0;
    01767       cimgl_map(list,l) {
    01768         cimg_map(list[l],ptr,T) {
    01769           const T& a=*ptr;
    01770           mean+=(double)a;
    01771           if (a<pmin) pmin=a;
    01772           if (a>pmax) pmax=a;
    01773         }
    01774         psize+=list[l].size();
    01775       }
    01776       mean/=psize;
    01777       min=(double)pmin;
    01778       max=(double)pmax;
    01779       if (compute_variance) {
    01780         cimgl_map(list,l) cimg_map(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
    01781         variance = std::sqrt(variance/psize);
    01782       }
    01783     }
    01785     CImgStats& operator=(const CImgStats stats) {
    01786       min = stats.min;
    01787       max = stats.max;
    01788       mean = stats.mean;
    01789       variance = stats.variance;
    01790       return *this;
    01791     }
    01793     const CImgStats& print(const char* title=NULL) const {
    01794       std::fprintf(stderr,"%-8s = { %g, %g [%g], %g }\n",title?title:"CImgStats",min,mean,variance,max);
    01795       return *this;
    01796     }
    01797   };
    01798
    01799   /*-------------------------------------------------------
    01800
    01801
    01802
    01803
    01804     Definition of the CImgDisplay structure
    01805
    01806
    01807
    01808
    01809   ------------------------------------------------------*/
    01811
    01819   struct CImgDisplay {
    01820
    01821     //------------------------
    01822     //
    01823     // CImgDisplay variables
    01824     //
    01825     //------------------------
    01826
    01828
    01841     unsigned int width;
    01842
    01844
    01857     unsigned int height;
    01858
    01861
    01867     volatile unsigned int window_width;
    01868
    01871
    01877     volatile unsigned int window_height;
    01878
    01880
    01890     unsigned int normalization;
    01891
    01893
    01904     unsigned int events;
    01905
    01907
    01912     const bool fullscreen;
    01913
    01916
    01924     volatile int mousex;
    01925
    01928
    01936     volatile int mousey;
    01937
    01940
    01955     volatile unsigned int button;
    01956
    01958
    01983     volatile unsigned int key;
    01984
    01986
    02009     volatile bool closed;
    02010
    02012     volatile bool resized;
    02013
    02014     // Not documented, internal use only.
    02015     double min,max;
    02016
    02017     //------------------------
    02018     //
    02019     // CImgDisplay functions
    02020     //
    02021     //------------------------
    02022
    02024
    02030     const int dimx() const { return (int)width; }
    02031
    02033
    02039     const int dimy() const { return (int)height; }
    02040
    02041     // operator=(). It is actually defined to avoid its use, and throw a CImgDisplay exception.
    02042     CImgDisplay& operator=(const CImgDisplay&) {
    02043       throw CImgDisplayException("CImgDisplay()::operator=() : Assignement of CImgDisplay is not allowed. Use pointers instead !");
    02044       return *this;
    02045     }
    02046
    02048
    02050       const CImgDisplay& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; }
    02051
    02053
    02062     template<typename T> CImgDisplay& display(const CImgl<T>& list,const char axe='x',const char align='c') {
    02063       return display(list.get_append(axe,align));
    02064     }
    02065
    02067
    02075     template<typename T> CImgDisplay& resize(const CImg<T>& img,const bool redraw=false,const bool force=true) {
    02076       return resize(img.width,img.height,redraw,force);
    02077     }
    02078
    02079     CImgDisplay& resize(const CImgDisplay& disp,const bool redraw=false,const bool force=true) {
    02080       return resize(disp.width,disp.height,redraw,force);
    02081     }
    02082
    02083     CImgDisplay& resize(const bool redraw=false,const bool force=false) {
    02084       resize(window_width,window_height,redraw,force);
    02085       return *this;
    02086     }
    02087
    02088     // When no display available
    02089     //---------------------------
    02090 #if cimg_display_type==0
    02091     void nodisplay_available() {
    02092       static bool first = true;
    02093       if (first) {
    02094         cimg::warn(true,"CImgDisplay() : Display has been required but is not available (cimg_display_type=0)");
    02095         first = false;
    02096       }
    02097     }
    02099
    02107     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02108                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02109                 const bool resizing_flag=false,const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02110       nodisplay_available();
    02111     }
    02112
    02114
    02119     template<typename T>
    02120     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02121                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02122                 const bool resizing_flag=false,const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02123       nodisplay_available();
    02124     }
    02125
    02127
    02132     template<typename T>
    02133     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02134                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02135                 const bool resizing_flag=false,const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02136       nodisplay_available();
    02137     }
    02138
    02140
    02143     CImgDisplay(const CImgDisplay& win, char *title=NULL) { nodisplay_available(); }
    02144
    02146     CImgDisplay& resize(const int width, const int height,const bool redraw=false,const bool force=true) {
    02147       return *this;
    02148     }
    02150     ~CImgDisplay() {}
    02152     template<typename T> void render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {}
    02154     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=-1) { return *this; }
    02156     CImgDisplay& wait()  { return *this; }
    02158     CImgDisplay& show()  { return *this; }
    02160     CImgDisplay& close() { return *this; }
    02161
    02162     // X11-based display
    02163     //------------------
    02164 #elif cimg_display_type==1
    02165     unsigned long *data;
    02166     XImage *image;
    02167     Window window;
    02168
    02169     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02170                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02171                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02172       width(dimw),height(dimh),window_width(dimw),window_height(dimh),
    02173       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02174       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02175       new_lowlevel(title);
    02176       std::memset(data,0,sizeof(unsigned long)*width*height);
    02177       pthread_mutex_lock(cimg::X11_mutex);
    02178       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02179       XFlush(cimg::X11_display);
    02180       pthread_mutex_unlock(cimg::X11_mutex);
    02181     }
    02182
    02183     template<typename T>
    02184     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02185                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02186                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02187       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02188       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02189       cimg_test(img,"CImgDisplay::CImgDisplay");
    02190       CImg<T> tmp;
    02191       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
    02192       window_width  = width  = nimg.width;
    02193       window_height = height = nimg.height;
    02194       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02195       new_lowlevel(title);
    02196       display(nimg);
    02197     }
    02198
    02199     template<typename T>
    02200     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02201                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02202                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02203       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02204       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02205       cimgl_test(list,"CImgDisplay::CImgDisplay");
    02206       CImg<T> tmp;
    02207       const CImg<T> img0 = list.get_append('x'),
    02208         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
    02209       window_width  = width  = img.width;
    02210       window_height = height = img.height;
    02211       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02212       new_lowlevel(title);
    02213       display(img);
    02214     }
    02215
    02216     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
    02217       width(win.width),height(win.height),window_width(width),window_height(height),
    02218       normalization(win.normalization),events(win.events),fullscreen(win.fullscreen),
    02219       mousex(-1),mousey(-1),button(0),key(0),closed(win.closed),resized(false),min(win.min),max(win.max) {
    02220       new_lowlevel(title);
    02221       std::memcpy(data,win.data,sizeof(unsigned long)*width*height);
    02222       pthread_mutex_lock(cimg::X11_mutex);
    02223       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02224       XFlush(cimg::X11_display);
    02225       pthread_mutex_unlock(cimg::X11_mutex);
    02226     }
    02227
    02228     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
    02229       const unsigned int
    02230         dimx=nwidth>0?nwidth:-width*nwidth/100,
    02231         dimy=nheight>0?nheight:-height*nheight/100;
    02232       if (!dimx || !dimy) return *this;
    02233       pthread_mutex_lock(cimg::X11_mutex);
    02234       if (dimx!=width || dimy!=height) {
    02235         unsigned long *ndata = new unsigned long[dimx*dimy];
    02236         if (redraw)
    02237           for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++) ndata[x+y*dimx] = data[x*width/dimx + width*(y*height/dimy)];
    02238         else std::memset(ndata,0,sizeof(unsigned long)*dimx*dimy);
    02239         data = ndata;
    02240         XDestroyImage(image);
    02241         image = XCreateImage(cimg::X11_display,DefaultVisual(cimg::X11_display,DefaultScreen(cimg::X11_display)),
    02242                              cimg::X11_nb_bits,ZPixmap,0,(char*)data,dimx,dimy,8,0);
    02243       }
    02244       width  = dimx;
    02245       height = dimy;
    02246       if (force && (window_width!=width || window_height!=height)) {
    02247         XResizeWindow(cimg::X11_display,window,width,height);
    02248         window_width  = width;
    02249         window_height = height;
    02250       }
    02251       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02252       XFlush(cimg::X11_display);
    02253       resized = false;
    02254       pthread_mutex_unlock(cimg::X11_mutex);
    02255       return *this;
    02256     }
    02257
    02258     ~CImgDisplay() {
    02259       unsigned int i;
    02260       pthread_mutex_lock(cimg::X11_mutex);
    02261       for (i=0; i<cimg::X11_nb_wins && cimg::X11_wins[i]!=this; i++) i++;
    02262       for (; i<cimg::X11_nb_wins-1; i++) cimg::X11_wins[i]=cimg::X11_wins[i+1];
    02263       cimg::X11_nb_wins--;
    02264       XDestroyWindow(cimg::X11_display,window);
    02265       XDestroyImage(image);
    02266       if (!cimg::X11_nb_wins) {
    02267         pthread_cancel(*cimg::X11_event_thread);
    02268         pthread_join(*cimg::X11_event_thread,NULL);
    02269         XCloseDisplay(cimg::X11_display);
    02270         cimg::X11_display=NULL;
    02271         pthread_mutex_unlock(cimg::X11_mutex);
    02272         pthread_mutex_destroy(cimg::X11_mutex);
    02273         delete cimg::X11_event_thread;
    02274         delete cimg::X11_mutex;
    02275         delete cimg::X11_gc;
    02276       } else pthread_mutex_unlock(cimg::X11_mutex);
    02277     }
    02278
    02279     void new_lowlevel(const char *title=NULL) {
    02280       cimg::warn(fullscreen,"CImgDisplay::new_lowlevel() : Fullscreen mode requested, but not supported on X11 Displays");
    02281       if (!cimg::X11_display) {
    02282         cimg::X11_nb_wins = 0;
    02283         cimg::X11_thread_finished = false;
    02284         cimg::X11_mutex = new pthread_mutex_t;
    02285         pthread_mutex_init(cimg::X11_mutex,NULL);
    02286         pthread_mutex_lock(cimg::X11_mutex);
    02287         cimg::X11_display = XOpenDisplay((getenv("DISPLAY") ? getenv("DISPLAY") : ":0.0"));
    02288         if (!cimg::X11_display) throw CImgDisplayException("CImgDisplay::new_lowlevel() : Can't open X11 display");
    02289         cimg::X11_nb_bits = DefaultDepth(cimg::X11_display, DefaultScreen(cimg::X11_display));
    02290         if (cimg::X11_nb_bits!=16 && cimg::X11_nb_bits!=24)
    02291           throw CImgDisplayException("CImgDisplay::new_lowlevel() : %d bits mode is not supported (only 16 and 24 bits are supported)",
    02292                                      cimg::X11_nb_bits);
    02293         cimg::X11_gc = new GC;
    02294         *cimg::X11_gc = DefaultGC(cimg::X11_display,DefaultScreen(cimg::X11_display));
    02295         Visual *visual = DefaultVisual(cimg::X11_display,0);
    02296         XVisualInfo vtemplate;
    02297         vtemplate.visualid = XVisualIDFromVisual(visual);
    02298         int nb_visuals;
    02299         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11_display,VisualIDMask,&vtemplate,&nb_visuals);
    02300         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_colors_endian = true;
    02301         cimg::X11_event_thread = new pthread_t;
    02302         pthread_create(cimg::X11_event_thread,NULL,thread_lowlevel,NULL);
    02303       } else pthread_mutex_lock(cimg::X11_mutex);
    02304       window = XCreateSimpleWindow(cimg::X11_display,RootWindow(cimg::X11_display,DefaultScreen(cimg::X11_display)),0,0,width,height,2,0,0x0L);
    02305       data   = new unsigned long[width*height];
    02306       image  = XCreateImage(cimg::X11_display,DefaultVisual(cimg::X11_display,DefaultScreen(cimg::X11_display)),cimg::X11_nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
    02307       XStoreName(cimg::X11_display,window,title?title:"");
    02308       if (!closed) {
    02309         XEvent event;
    02310         XSelectInput(cimg::X11_display,window,StructureNotifyMask);
    02311         XMapWindow(cimg::X11_display,window);
    02312         do XWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event); while (event.type!=MapNotify);
    02313       }
    02314       if (events) {
    02315         Atom atom = XInternAtom(cimg::X11_display, "WM_DELETE_WINDOW", False);
    02316         XSetWMProtocols(cimg::X11_display, window, &atom, 1);
    02317       }
    02318       cimg::X11_wins[cimg::X11_nb_wins++]=this;
    02319       pthread_mutex_unlock(cimg::X11_mutex);
    02320     }
    02321
    02322     void proc_lowlevel(XEvent *pevent) {
    02323       const unsigned int buttoncode[3] = { 1,4,2 };
    02324       XEvent event=*pevent;
    02325       switch (event.type) {
    02326       case ClientMessage:
    02327         XUnmapWindow(cimg::X11_display,window);
    02328         mousex=mousey=-1;
    02329         button=key=0;
    02330         closed=true;
    02331         break;
    02332      case ConfigureNotify: {
    02333         while (XCheckWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event));
    02334         const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height;
    02335         if (nw && nh && (nw!=width || nh!=height)) {
    02336           window_width = nw;
    02337           window_height = nh;
    02338           mousex = mousey = -1;
    02339           button = key=0;
    02340           XResizeWindow(cimg::X11_display,window,window_width,window_height);
    02341           resized = true;
    02342         }
    02343       } break;
    02344       case Expose:
    02345         while (XCheckWindowEvent(cimg::X11_display,window,ExposureMask,&event));
    02346         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02347         break;
    02348       case ButtonPress:
    02349         while (XCheckWindowEvent(cimg::X11_display,window,ButtonPressMask,&event));
    02350         button |= buttoncode[event.xbutton.button-1];
    02351         break;
    02352       case ButtonRelease:
    02353         while (XCheckWindowEvent(cimg::X11_display,window,ButtonReleaseMask,&event));
    02354         button &= ~buttoncode[event.xbutton.button-1];
    02355         break;
    02356       case KeyPress: {
    02357         while (XCheckWindowEvent(cimg::X11_display,window,KeyPressMask,&event));
    02358         char tmp;
    02359         KeySym ksym;
    02360         XLookupString(&event.xkey,&tmp,1,&ksym,NULL);
    02361         key = (unsigned int)ksym;
    02362       }
    02363         break;
    02364       case KeyRelease:
    02365         while (XCheckWindowEvent(cimg::X11_display,window,KeyReleaseMask,&event));
    02366         key = 0;
    02367         break;
    02368       case LeaveNotify:
    02369         while (XCheckWindowEvent(cimg::X11_display,window,LeaveWindowMask,&event));
    02370         mousex = mousey =-1;
    02371         key = button = 0;
    02372         break;
    02373       case MotionNotify:
    02374         while (XCheckWindowEvent(cimg::X11_display,window,PointerMotionMask,&event));
    02375         mousex = event.xmotion.x;
    02376         mousey = event.xmotion.y;
    02377         if (mousex<0 || mousey<0 || mousex>=dimx() || mousey>=dimy()) {
    02378           mousex=mousey=-1;
    02379           key=button=0;
    02380         }
    02381         break;
    02382       }
    02383     }
    02384
    02385     static void* thread_lowlevel(void *arg) {
    02386       XEvent event;
    02387       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    02388       for (;;) {
    02389         pthread_mutex_lock(cimg::X11_mutex);
    02390         for (unsigned int i=0; i<cimg::X11_nb_wins; i++) {
    02391           const unsigned int xevent_type = (cimg::X11_wins[i]->events)&3;
    02392           const unsigned int emask =
    02393             ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
    02394             ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
    02395             ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
    02396           XSelectInput(cimg::X11_display,cimg::X11_wins[i]->window,emask);
    02397         }
    02398         bool event_flag = XCheckTypedEvent(cimg::X11_display, ClientMessage, &event);
    02399         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11_display,
    02400                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
    02401                                                       KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
    02402                                                       KeyReleaseMask,&event);
    02403         if (event_flag) {
    02404           for (unsigned int i=0; i<cimg::X11_nb_wins; i++)
    02405             if (!cimg::X11_wins[i]->closed && event.xany.window==cimg::X11_wins[i]->window) cimg::X11_wins[i]->proc_lowlevel(&event);
    02406           cimg::X11_thread_finished = true;
    02407         }
    02408         pthread_mutex_unlock(cimg::X11_mutex);
    02409         cimg::wait(25);
    02410       }
    02411       return NULL;
    02412     }
    02413
    02414     template<typename T> XImage* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
    02415       cimg_test(img,"CImgDisplay::render");
    02416       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),0,~0);
    02417       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),0,~0);
    02418       const bool by=(ymin<=ymax);
    02419       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin), w=width;
    02420       const T
    02421         *data1 = img.ptr(0,nymin,0,0),
    02422         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
    02423         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
    02424       if (cimg::X11_colors_endian) cimg::swap(data1,data3);
    02425       pthread_mutex_lock(cimg::X11_mutex);
    02426       XImage *ximg = image;
    02427       if (!normalization) {
    02428         switch (cimg::X11_nb_bits) {
    02429         case 16:
    02430           for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++) {
    02431             XPutPixel(ximg,x,y,(((unsigned char)*(data1++)>>3)<<11) | (((unsigned char)*(data2++)>>2)<<5) | ((unsigned char)*(data3++)>>3));
    02432           }
    02433           break;
    02434         case 24:
    02435           for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++) {
    02436             XPutPixel(ximg,x,y,((unsigned char)*(data1++)<<16)      | ((unsigned char)*(data2++)<<8)      | (unsigned char)*(data3++)     );
    02437           }
    02438           break;
    02439         };
    02440       } else {
    02441         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
    02442         const T nmin = (T)min, delta = (T)max-nmin, mm=delta?delta:(T)1;
    02443         switch (cimg::X11_nb_bits) {
    02444         case 16: for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++) {
    02445             const unsigned char
    02446               val1 = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02447               val2 = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02448               val3 = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02449             XPutPixel(ximg,x,y,((val1>>3)<<11) | ((val2>>2)<<5) | (val3>>3));
    02450           }
    02451           break;
    02452         case 24: for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++) {
    02453             const unsigned char
    02454               val1 = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02455               val2 = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02456               val3 = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02457             XPutPixel(ximg,x,y,(val1<<16) | (val2<<8) | val3);
    02458           }
    02459           break;
    02460         }
    02461       }
    02462       pthread_mutex_unlock(cimg::X11_mutex);
    02463       return image;
    02464     }
    02465
    02466     template<typename T> CImgDisplay& display(const CImg<T>& pimg,const unsigned int pymin=0,const unsigned int pymax=~0) {
    02467       const unsigned int
    02468         ymin = pymin<pymax?pymin:pymax,
    02469         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
    02470       render(pimg,ymin,ymax);
    02471       if (!closed) {
    02472         pthread_mutex_lock(cimg::X11_mutex);
    02473         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,ymin,0,ymin,width,ymax-ymin+1);
    02474         XFlush(cimg::X11_display);
    02475         pthread_mutex_unlock(cimg::X11_mutex);
    02476       }
    02477       return *this;
    02478     }
    02479
    02480     CImgDisplay& wait() {
    02481       if (!closed && events) {
    02482         XEvent event;
    02483         do {
    02484           pthread_mutex_lock(cimg::X11_mutex);
    02485           const unsigned int
    02486             emask = ExposureMask|StructureNotifyMask|
    02487             ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
    02488             ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0);
    02489           XSelectInput(cimg::X11_display,window,emask);
    02490           XPeekEvent(cimg::X11_display,&event);
    02491           cimg::X11_thread_finished = false;
    02492           pthread_mutex_unlock(cimg::X11_mutex);
    02493         } while (event.xany.window!=window);
    02494         while (!cimg::X11_thread_finished) cimg::wait(25);
    02495       }
    02496       return *this;
    02497     }
    02498
    02499     CImgDisplay& show() {
    02500       if (closed) {
    02501         pthread_mutex_lock(cimg::X11_mutex);
    02502         XEvent event;
    02503         XSelectInput(cimg::X11_display,window,StructureNotifyMask);
    02504         XMapWindow(cimg::X11_display,window);
    02505         do XWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event);
    02506         while (event.type!=MapNotify);
    02507         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02508         XFlush(cimg::X11_display);
    02509         closed = false;
    02510         pthread_mutex_unlock(cimg::X11_mutex);
    02511       }
    02512       return *this;
    02513     }
    02514     CImgDisplay& close() {
    02515       if (!closed) {
    02516         pthread_mutex_lock(cimg::X11_mutex);
    02517         XUnmapWindow(cimg::X11_display,window);
    02518         XFlush(cimg::X11_display);
    02519         closed = true;
    02520         pthread_mutex_unlock(cimg::X11_mutex);
    02521       }
    02522       return *this;
    02523     }
    02524
    02525     // Windows-based display
    02526     //-----------------------
    02527 #elif cimg_display_type==2
    02528     CLIENTCREATESTRUCT ccs;
    02529     BITMAPINFO bmi;
    02530     unsigned int *data;
    02531     DEVMODE curr_mode;
    02532     HWND window;
    02533     HDC hdc;
    02534     HANDLE thread;
    02535     HANDLE wait_disp;
    02536     HANDLE created;
    02537     HANDLE mutex;
    02538
    02539     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02540                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02541                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02542       width(dimw),height(dimh),window_width(dimw),window_height(dimh),
    02543       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02544       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02545       new_lowlevel(title);
    02546       std::memset(data,0,sizeof(unsigned int)*width*height);
    02547       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02548     }
    02549
    02550     template<typename T>
    02551     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02552                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02553                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02554       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02555       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02556       cimg_test(img,"CImgDisplay::CImgDisplay");
    02557       CImg<T> tmp;
    02558       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
    02559       window_width  = width  = nimg.width;
    02560       window_height = height = nimg.height;
    02561       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02562       new_lowlevel(title);
    02563       display(nimg);
    02564     }
    02565
    02566     template<typename T>
    02567     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02568                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02569                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02570       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02571       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02572       cimgl_test(list,"CImgDisplay::CImgDisplay");
    02573       CImg<T> tmp;
    02574       const CImg<T> img0 = list.get_append('x'),
    02575         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
    02576       window_width  = width  = img.width;
    02577       window_height = height = img.height;
    02578       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02579       new_lowlevel(title);
    02580       display(img);
    02581     }
    02582
    02583     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
    02584       width(win.width),height(win.height),window_width(win.width),window_height(win.height),
    02585       normalization(win.normalization),events(win.events),fullscreen(win.fullscreen),
    02586       mousex(-1),mousey(-1),button(0),key(0),closed(win.closed),resized(false),min(win.min),max(win.max) {
    02587       new_lowlevel(title);
    02588       std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
    02589       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02590     }
    02591
    02592     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
    02593       const unsigned int
    02594         dimx=nwidth>0?nwidth:(-nwidth)*width/100,
    02595         dimy=nheight>0?nheight:(-nheight)*height/100;
    02596       if (!dimx || !dimy) return *this;
    02597       if (dimx!=width || dimy!=height) {
    02598         unsigned int *ndata = new unsigned int[dimx*dimy];
    02599         if (redraw)
    02600           for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++) ndata[x+y*dimx] = data[x*width/dimx + width*(y*height/dimy)];
    02601         else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
    02602         delete[] data;
    02603         data = ndata;
    02604         bmi.bmiHeader.biWidth=dimx;
    02605         bmi.bmiHeader.biHeight=-(int)dimy;
    02606       }
    02607       width  = dimx;
    02608       height = dimy;
    02609       if (force && (window_width!=width || window_height!=height)) {
    02610         int cwidth,cheight;
    02611         RECT rect;
    02612         rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
    02613         if (AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false)) {
    02614           cwidth = rect.right-rect.left+1; cheight = rect.bottom-rect.top+1;
    02615         } else { cwidth = width+9; cheight = height+28; }
    02616         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
    02617         window_width  = dimx;
    02618         window_height = dimy;
    02619       }
    02620       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02621       resized = false;
    02622       return *this;
    02623     }
    02624
    02625     ~CImgDisplay() {
    02626       DestroyWindow(window);
    02627       if (events) TerminateThread(thread,0);
    02628       delete[] data;
    02629       if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
    02630     }
    02631
    02632     void new_lowlevel(const char *title=NULL) {
    02633       unsigned long ThreadID;
    02634       DEVMODE mode;
    02635       unsigned int imode=0,ibest=0,bestbpp=0;
    02636       void *arg = (void*)(new void*[2]);
    02637       ((void**)arg)[0]=(void*)this;
    02638       ((void**)arg)[1]=(void*)title;
    02639       if (fullscreen) {
    02640         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(NULL,imode,&mode); imode++)
    02641           if (mode.dmPelsWidth==width && mode.dmPelsHeight==height && mode.dmBitsPerPel>bestbpp) {
    02642             bestbpp = mode.dmBitsPerPel;
    02643             ibest=imode;
    02644           }
    02645         cimg::warn(!bestbpp,"CImgDisplay::new_lowlevel() : Could not initialize fullscreen mode %dx%d\n",width,height);
    02646         if (bestbpp) {
    02647           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
    02648           EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&curr_mode);
    02649           EnumDisplaySettings(NULL,ibest,&mode);
    02650           ChangeDisplaySettings(&mode,0);
    02651         }
    02652         else curr_mode.dmSize = 0;
    02653       }
    02654       else curr_mode.dmSize = 0;
    02655       if (events) {
    02656         mutex     = CreateMutex(NULL,FALSE,NULL);
    02657         created   = CreateEvent(NULL,FALSE,FALSE,NULL);
    02658         wait_disp = CreateEvent(NULL,FALSE,FALSE,NULL);
    02659         thread    = CreateThread(NULL,0,thread_lowlevel,arg,0,&ThreadID);
    02660         WaitForSingleObject(created,INFINITE);
    02661       } else thread_lowlevel(arg);
    02662     }
    02663
    02664     static LRESULT APIENTRY proc_lowlevel(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
    02665       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
    02666       MSG st_msg;
    02667
    02668       switch(msg) {
    02669       case WM_CLOSE:
    02670         disp->mousex=disp->mousey=-1;
    02671         disp->key=disp->button=0;
    02672         disp->closed=true;
    02673         ReleaseMutex(disp->mutex);
    02674         ShowWindow(disp->window,SW_HIDE);
    02675         return 0;
    02676       case WM_SIZE: {
    02677         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
    02678         WaitForSingleObject(disp->mutex,INFINITE);
    02679         const unsigned int nw = LOWORD(lParam), nh = HIWORD(lParam);
    02680         if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
    02681           disp->window_width  = nw;
    02682           disp->window_height = nh;
    02683           disp->mousex = disp->mousey = -1;
    02684           disp->button = disp->key = 0;
    02685           disp->resized = true;
    02686         }
    02687         ReleaseMutex(disp->mutex);
    02688       }
    02689         break;
    02690       case WM_PAINT:
    02691         WaitForSingleObject(disp->mutex,INFINITE);
    02692         SetDIBitsToDevice(disp->hdc,0,0,disp->width,disp->height,0,0,0,disp->height,disp->data,&(disp->bmi),DIB_RGB_COLORS);
    02693         ReleaseMutex(disp->mutex);
    02694         break;
    02695       }
    02696       if (disp->events>=2) switch(msg) {
    02697       case WM_KEYDOWN:
    02698         while (PeekMessage(&st_msg,window,WM_KEYDOWN,WM_KEYDOWN,PM_REMOVE));
    02699         disp->key=(int)wParam;
    02700         break;
    02701       case WM_MOUSEMOVE: {
    02702         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE));
    02703         disp->mousex = LOWORD(lParam);
    02704         disp->mousey = HIWORD(lParam);
    02705         if (disp->mousex<0 || disp->mousey<0 || disp->mousex>=disp->dimx() || disp->mousey>=disp->dimy()) {
    02706           disp->mousex=disp->mousey=-1;
    02707           disp->button=disp->key=0;
    02708         }
    02709       }
    02710         break;
    02711       case WM_LBUTTONDOWN:
    02712         while (PeekMessage(&st_msg,window,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE));
    02713         disp->button |= 1;
    02714         break;
    02715       case WM_RBUTTONDOWN:
    02716         while (PeekMessage(&st_msg,window,WM_RBUTTONDOWN,WM_RBUTTONDOWN,PM_REMOVE));
    02717         disp->button |= 2;
    02718         break;
    02719       case WM_MBUTTONDOWN:
    02720         while (PeekMessage(&st_msg,window,WM_MBUTTONDOWN,WM_MBUTTONDOWN,PM_REMOVE));
    02721         disp->button |= 4;
    02722         break;
    02723       }
    02724       if (disp->events>=3) switch(msg) {
    02725       case WM_KEYUP:
    02726         while (PeekMessage(&st_msg,window,WM_KEYUP,WM_KEYUP,PM_REMOVE));
    02727         disp->key=0;
    02728         break;
    02729       case WM_LBUTTONUP:
    02730         while (PeekMessage(&st_msg,window,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE));
    02731         disp->button &= ~1;
    02732         break;
    02733       case WM_RBUTTONUP:
    02734         while (PeekMessage(&st_msg,window,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE));
    02735         disp->button &= ~2;
    02736         break;
    02737       case WM_MBUTTONUP:
    02738         while (PeekMessage(&st_msg,window,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE));
    02739         disp->button &= ~4;
    02740         break;
    02741       }
    02742       return DefWindowProc(window,msg,wParam,lParam);
    02743     }
    02744
    02745     static DWORD WINAPI thread_lowlevel(void* arg) {
    02746       CImgDisplay *disp  = (CImgDisplay*)(((void**)arg)[0]);
    02747       const char *title = (const char*)(((void**)arg)[1]);
    02748       MSG msg;
    02749       delete[] (void**)arg;
    02750       disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    02751       disp->bmi.bmiHeader.biWidth=disp->width;
    02752       disp->bmi.bmiHeader.biHeight=-(int)disp->height;
    02753       disp->bmi.bmiHeader.biPlanes=1;
    02754       disp->bmi.bmiHeader.biBitCount=32;
    02755       disp->bmi.bmiHeader.biCompression=BI_RGB;
    02756       disp->bmi.bmiHeader.biSizeImage=0;
    02757       disp->bmi.bmiHeader.biXPelsPerMeter=1;
    02758       disp->bmi.bmiHeader.biYPelsPerMeter=1;
    02759       disp->bmi.bmiHeader.biClrUsed=0;
    02760       disp->bmi.bmiHeader.biClrImportant=0;
    02761       disp->data = new unsigned int[disp->width*disp->height];
    02762       if (!disp->curr_mode.dmSize) {
    02763         int cwidth,cheight;
    02764         RECT rect;
    02765         rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1;
    02766         if (AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false)) {
    02767           cwidth = rect.right-rect.left+1; cheight = rect.bottom-rect.top+1;
    02768         } else { cwidth = disp->width+9; cheight = disp->height+28; }
    02769         disp->window = CreateWindow("MDICLIENT",title?title:"",
    02770                                     WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,CW_USEDEFAULT,
    02771                                     cwidth,cheight,NULL,NULL,NULL,&(disp->ccs));
    02772       }
    02773       else disp->window = CreateWindow("MDICLIENT",title?title:"",
    02774                                        WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,CW_USEDEFAULT,
    02775                                        disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs));
    02776       SetForegroundWindow(disp->window);
    02777       disp->hdc = GetDC(disp->window);
    02778       if (disp->events) {
    02779         SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
    02780         SetWindowLong(disp->window,GWL_WNDPROC,(LONG)proc_lowlevel);
    02781         SetEvent(disp->created);
    02782         while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); SetEvent(disp->wait_disp); }
    02783       }
    02784       return 0;
    02785     }
    02786
    02787     template<typename T> BITMAPINFO* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
    02788       cimg_test(img,"CImgDisplay::render");
    02789       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),(unsigned int)0,~(unsigned int)0);
    02790       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),(unsigned int)0,~(unsigned int)0);
    02791       const bool by=(ymin<=ymax);
    02792       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin), w=width;
    02793       const T
    02794         *data1 = img.ptr(0,nymin,0,0),
    02795         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
    02796         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
    02797       unsigned int *ximg = data + nymin*width;
    02798       WaitForSingleObject(mutex,INFINITE);
    02799       if (!normalization)
    02800         for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++)
    02801           *(ximg++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
    02802       else {
    02803         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
    02804         const T nmin = (T)min, delta = (T)(max-nmin), mm = delta?delta:(T)1;
    02805         for (unsigned int y=nymin; y<=nymax; y++) for (unsigned int x=0; x<w; x++) {
    02806           const unsigned char
    02807             val1 = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02808             val2 = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02809             val3 = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02810           *(ximg++) = (val1<<16) | (val2<<8) | (val3);
    02811         }
    02812       }
    02813       ReleaseMutex(mutex);
    02814       return &bmi;
    02815     }
    02816
    02817     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int pymin=0,const unsigned int pymax=~0) {
    02818       cimg_test(img,"CImgDisplay::display");
    02819       const unsigned int
    02820         ymin = pymin<pymax?pymin:pymax,
    02821         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
    02822       render(img,ymin,ymax);
    02823       if (!closed) {
    02824         WaitForSingleObject(mutex,INFINITE);
    02825         SetDIBitsToDevice(hdc,0,ymin,width,ymax-ymin+1,0,0,0,ymax-ymin+1,data+ymin*width,&bmi,DIB_RGB_COLORS);
    02826         ReleaseMutex(mutex);
    02827       }
    02828       return *this;
    02829     }
    02830
    02831     CImgDisplay& wait() {
    02832       if (!closed && events) WaitForSingleObject(wait_disp,INFINITE);
    02833       return *this;
    02834     }
    02835
    02836     CImgDisplay& show() {
    02837       if (closed) {
    02838         ShowWindow(window,SW_SHOW);
    02839         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02840         closed = false;
    02841       }
    02842       return *this;
    02843     }
    02844
    02845     CImgDisplay& close() {
    02846       if (!closed) {
    02847         ShowWindow(window,SW_HIDE);
    02848         closed = true;
    02849       }
    02850       return *this;
    02851     }
    02852 #endif
    02853
    02854   };
    02855
    02856
    02857   /*-------------------------------------------------------
    02858
    02859
    02860
    02861
    02862     Definition of the CImg<T> structure
    02863
    02864
    02865
    02866
    02867   ------------------------------------------------------*/
    02868
    02870
    02941   template<typename T> struct CImg {
    02942
    02944
    02952     unsigned int width;
    02953
    02955
    02963     unsigned int height;
    02964
    02966
    02974     unsigned int depth;
    02975
    02977
    02985     unsigned int dim;
    02986
    02988
    02996     T *data;
    02997
    02998     //------------------------------------------
    02999     //------------------------------------------
    03000     //
    03002
    03003     //------------------------------------------
    03004     //------------------------------------------
    03005
    03007
    03016     explicit CImg(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1):
    03017       width(dx),height(dy),depth(dz),dim(dv) {
    03018       const unsigned int siz = size();
    03019       if (siz) data = new T[siz]; else { data=NULL; width=height=depth=dim=0; }
    03020     }
    03021
    03024
    03030     explicit CImg(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val):
    03031       width(dx),height(dy),depth(dz),dim(dv) {
    03032       const unsigned int siz = size();
    03033       if (siz) { data = new T[siz]; fill(val); } else { data=NULL; width=height=depth=dim=0; }
    03034     }
    03035
    03037
    03040     template<typename t> CImg(const CImg<t>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
    03041       const unsigned int siz = size();
    03042       if (siz) {
    03043         data = new T[siz];
    03044         const t *ptrs = img.data + siz;
    03045         cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs);
    03046       } else data = NULL;
    03047     }
    03048     CImg(const CImg<T>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
    03049       const unsigned siz = size();
    03050       if (siz) {
    03051         data = new T[width*height*depth*dim];
    03052         std::memcpy(data,img.data,siz*sizeof(T));
    03053       } else data = NULL;
    03054     }
    03055
    03056
    03058
    03072     template<typename t> CImg(const CImg<t>& img,const bool pixel_copy):width(0),height(0),depth(0),dim(0),data(NULL) {
    03073       if (pixel_copy) CImg<T>(img).swap(*this);
    03074       CImg<T>(img.width,img.height,img.depth,img.dim).swap(*this);
    03075     }
    03076
    03078
    03082     CImg(const char *filename):width(0),height(0),depth(0),dim(0),data(NULL) { load(filename).swap(*this); }
    03083
    03085
    03093     CImg(const T *const data_buffer,unsigned int dx,unsigned int dy=1,unsigned int dz=1,unsigned int dv=1):
    03094       width(dx),height(dy),depth(dz),dim(dv) {
    03095       const unsigned int siz = size();
    03096       if (data_buffer && siz) {
    03097         data = new T[siz];
    03098         std::memcpy(data,data_buffer,siz*sizeof(T));
    03099       } else { width=height=depth=dim=0; data = NULL; }
    03100     }
    03101
    03103
    03106     ~CImg() { if (data) delete[] data; }
    03107
    03109     CImg& empty() { return CImg<T>().swap(*this); }
    03110
    03112     //-----------------------------------------------------
    03113     //-----------------------------------------------------
    03114     //
    03116
    03117     //-----------------------------------------------------
    03118     //-----------------------------------------------------
    03119
    03121
    03124     static const char* pixel_type() { T val; return cimg::get_type(val); }
    03125
    03127
    03131     const unsigned int size() const { return width*height*depth*dim; }
    03132
    03134
    03138     const int dimx() const { return (int)width; }
    03139
    03141
    03145     const int dimy() const { return (int)height; }
    03146
    03148
    03152     const int dimz() const { return (int)depth; }
    03153
    03155
    03159     const int dimv() const { return (int)dim; }
    03160
    03162     // with respect to the pixel data pointer \ref data.
    03169     const int offset(const int x=0, const int y=0, const int z=0, const int v=0) const { return x+width*(y+height*(z+depth*v)); }
    03170
    03172
    03178     T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
    03179 #if cimg_debug>1
    03180       const int off = offset(x,y,z,v);
    03181       if (off<0 || off>=(int)size()) {
    03182         cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%d,%d,%d,%d) (offset=%d) which is outside the data of the image (%d,%d,%d,%d) (size=%d)",
    03183                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
    03184         return data;
    03185       }
    03186 #endif
    03187       return data+offset(x,y,z,v);
    03188     }
    03189
    03191
    03198     T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const {
    03199       const int off = offset(x,y,z,v);
    03200 #if cimg_debug>1
    03201       if (!data || off>=(int)size()) {
    03202         cimg::warn(true,
    03203                    "CImg<%s>::operator() : Pixel access requested at (%d,%d,%d,%d) (offset=%d) outside the image range (%d,%d,%d,%d,%d) (size=%d)",
    03204                    pixel_type(),x,y,z,v,offset(x,y,z,v),width,height,depth,dim,data,size());
    03205         return *data;
    03206       }
    03207 #endif
    03208       return data[off];
    03209     }
    03210
    03212
    03216     T& operator[](const unsigned int off) const {
    03217 #if cimg_debug>1
    03218       if (!data || off>=(int)size()) {
    03219         cimg::warn(true,
    03220                    "CImg<%s>::operator[] : Trying to get a pixel at offset=%d, outside the range of the image (%d,%d,%d,%d,%d) (size=%d)",
    03221                    pixel_type(),off,width,height,depth,dim,data,size());
    03222         return *data;
    03223       }
    03224 #endif
    03225       return data[off];
    03226     }
    03227
    03229
    03236     T dirichlet_pix4d(const int x,const int y=0,const int z=0,const int v=0,const T out_val=(T)0) const {
    03237       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
    03238     }
    03239
    03241
    03248     T dirichlet_pix3d(const int x,const int y=0,const int z=0,const int v=0,const T out_val=(T)0) const {
    03249       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
    03250     }
    03252
    03259     T dirichlet_pix2d(const int x,const int y=0,const int z=0,const int v=0,const T out_val=(T)0) const {
    03260       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
    03261     }
    03262
    03264
    03271     T dirichlet_pix1d(const int x,const int y=0,const int z=0,const int v=0,const T out_val=(T)0) const {
    03272       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
    03273     }
    03274
    03276
    03282     const T& neumann_pix4d(const int x,const int y=0,const int z=0,const int v=0) const {
    03283       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03284                      y<0?0:(y>=dimy()?dimy()-1:y),
    03285                      z<0?0:(z>=dimz()?dimz()-1:z),
    03286                      v<0?0:(v>=dimv()?dimv()-1:v));
    03287     }
    03289
    03295     const T& neumann_pix3d(const int x,const int y=0,const int z=0,const int v=0) const {
    03296       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03297                      y<0?0:(y>=dimy()?dimy()-1:y),
    03298                      z<0?0:(z>=dimz()?dimz()-1:z),v);
    03299     }
    03300
    03302
    03308     const T& neumann_pix2d(const int x,const int y=0,const int z=0,const int v=0) const {
    03309       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03310                      y<0?0:(y>=dimy()?dimy()-1:y),z,v);
    03311     }
    03313
    03319     const T& neumann_pix1d(const int x,const int y=0,const int z=0,const int v=0) const {
    03320       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
    03321     }
    03322
    03324
    03330     double linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const {
    03331       double valx0,valx1,valy0,valy1,valz0,valz1;
    03332       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy),
    03333         fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv);
    03334       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy,  z = (unsigned int)fz, v = (unsigned int)fv;
    03335       const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
    03336       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y,  nz = dz>0?z+1:z, nv = dv>0?v+1:v;
    03337       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03338       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03339       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03340       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
    03341       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
    03342       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03343       valz0 = (1-dz)*valy0 + (dz)*valy1;
    03344       valx0 = (1-dx)*(*this)(x,y,z,nv)  + (dx)*(*this)(nx,y,z,nv);
    03345       valx1 = (1-dx)*(*this)(x,ny,z,nv) + (dx)*(*this)(nx,ny,z,nv);
    03346       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03347       valx0 = (1-dx)*(*this)(x,y,nz,nv)  + (dx)*(*this)(nx,y,nz,nv);
    03348       valx1 = (1-dx)*(*this)(x,ny,nz,nv) + (dx)*(*this)(nx,ny,nz,nv);
    03349       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03350       valz1 = (1-dz)*valy0 + (dz)*valy1;
    03351       return (1-dv)*valz0 + (dv)*valz1;
    03352     }
    03353
    03355
    03361     double linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const {
    03362       double valx0,valx1,valy0,valy1;
    03363       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), fz = ffz<0?0:(ffz>depth-1?depth-1:ffz);
    03364       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz;
    03365       const float dx = fx-x, dy = fy-y, dz = fz-z;
    03366       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z;
    03367       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03368       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03369       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03370       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
    03371       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
    03372       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03373       return (1-dz)*valy0 + (dz)*valy1;
    03374     }
    03375
    03377
    03383     double linear_pix2d(const float ffx,const float ffy=0,const int z=0,int v=0) const {
    03384       double valx0,valx1;
    03385       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy);
    03386       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy;
    03387       const float dx = fx-x, dy = fy-y;
    03388       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y;
    03389       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03390       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03391       return (1-dy)*valx0 + (dy)*valx1;
    03392     }
    03393
    03395
    03401     double linear_pix1d(const float ffx,const int y=0,const int z=0,int v=0) const {
    03402       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx);
    03403       const unsigned int x = (unsigned int)fx;
    03404       const float dx = fx-x;
    03405       const unsigned int nx = dx>0?x+1:x;
    03406       return (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03407     }
    03408
    03410
    03416     double cubic_pix2d(const float pfx,const float pfy=0,const int z=0,int v=0) const {
    03417       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy);
    03418       const unsigned int
    03419         x = (unsigned int)fx,  px = (int)x-1>=0?x-1:0, nx = x+1<width?x+1:width-1, ax = nx+1<width?nx+1:width-1,
    03420         y = (unsigned int)fy,  py = (int)y-1>=0?y-1:0, ny = y+1<height?y+1:height-1, ay = ny+1<height?ny+1:height-1;
    03421       const float dx = fx-x, dy = fy-y;
    03422       const T&
    03423         a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v),
    03424         e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v),
    03425         i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v),
    03426         m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v);
    03427       const double
    03428         A = dx*dx*dx*(2*(b-c)+0.5*(c-a+d-b)) + dx*dx*(2*c-2.5*b+a-0.5*d) + dx*0.5*(c-a) + b,
    03429         B = dx*dx*dx*(2*(f-g)+0.5*(g-e+h-f)) + dx*dx*(2*g-2.5*f+e-0.5*h) + dx*0.5*(g-e) + f,
    03430         C = dx*dx*dx*(2*(j-k)+0.5*(k-i+l-j)) + dx*dx*(2*k-2.5*j+i-0.5*l) + dx*0.5*(k-i) + j,
    03431         D = dx*dx*dx*(2*(n-o)+0.5*(o-m+p-n)) + dx*dx*(2*o-2.5*n+m-0.5*p) + dx*0.5*(o-m) + n;
    03432       return dy*dy*dy*(2*(B-C)+0.5*(C-A+D-B)) + dy*dy*(2*C-2.5*B+A-0.5*D) + dy*0.5*(C-A) + B;
    03433     }
    03434
    03436
    03442     double cubic_pix1d(const float pfx,const int y=0,const int z=0,int v=0) const {
    03443       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx);
    03444       const unsigned int x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1<width?x+1:width-1, ax = nx+1<width?nx+1:width-1;
    03445       const float dx = fx-x;
    03446       const T& a = (*this)(px,y,z,v), b = (*this)(x,y,z,v), c = (*this)(nx,y,z,v), d = (*this)(ax,y,z,v);
    03447       return dx*dx*dx*(2*(b-c)+0.5*(c-a+d-b)) + dx*dx*(2*c-2.5*b+a-0.5*d) + dx*0.5*(c-a) + b;
    03448     }
    03449
    03451
    03456     CImgStats get_stats(const bool compute_variance=true) const { return CImgStats(*this,compute_variance); }
    03457
    03459
    03465     const CImg& print(const char *title=NULL,const unsigned int print_flag=1) const {
    03466       std::fprintf(stderr,"%-8s(%p) : '%s'(%d,%d,%d,%d,%p) : ",title?title:"CImg",this,
    03467                    pixel_type(),width,height,depth,dim,data);
    03468       if (size()==0 || !data) { std::fprintf(stderr,"Undefined pixel data\n"); return *this; }
    03469       if (print_flag>=1) {
    03470         CImgStats st(*this);
    03471         std::fprintf(stderr,"stats = { %g, %g [%g], %g } : ",st.min,st.mean,st.variance,st.max);
    03472       }
    03473       if (print_flag>=2 || size()<=16) {
    03474         std::fprintf(stderr,"%s = [ ",title?title:"data");
    03475         cimg_mapXYZV(*this,x,y,z,k) std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k),((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]":(((x+1)%width==0)?" ; ":" ")));
    03476       }
    03477       std::fputc('\n',stderr);
    03478       return *this;
    03479     }
    03481
    03486     const CImg& print(const unsigned int print_flag) const { return print(NULL,print_flag); }
    03487
    03489     //--------------------------------------------------
    03490     //--------------------------------------------------
    03491     //
    03493
    03494     //--------------------------------------------------
    03495     //--------------------------------------------------
    03496
    03498
    03502     template<typename t> CImg<T>& operator=(const CImg<t>& img) { return CImg<T>(img).swap(*this); }
    03503     CImg& operator=(const CImg& img) { if (&img==this) return *this; return CImg<T>(img).swap(*this); }
    03504
    03506
    03509     CImg& operator=(const T& val) { return fill(val); }
    03510
    03512
    03515     CImg& operator=(const T *buf) {
    03516       if (buf) std::memcpy(data,buf,size()*sizeof(T));
    03517       else throw CImgArgumentException("CImg<T>::operator=() : Given array pointer 'ptr' is NULL");
    03518       return *this;
    03519     }
    03520
    03522
    03525     CImg& operator+=(const T& val) { cimg_map(*this,ptr,T) (*ptr)+=val; return *this; }
    03526
    03528
    03531     CImg& operator-=(const T& val) { cimg_map(*this,ptr,T) (*ptr)-=val; return *this; }
    03532
    03534
    03537     CImg& operator%=(const T& val) { cimg_map(*this,ptr,T) (*ptr)%=val; return *this; }
    03538
    03540
    03543     CImg& operator&=(const T& val) { cimg_map(*this,ptr,T) (*ptr)&=val; return *this; }
    03544
    03546
    03549     CImg& operator|=(const T& val) { cimg_map(*this,ptr,T) (*ptr)|=val; return *this; }
    03550
    03552     CImg& operator^=(const T& val) { cimg_map(*this,ptr,T) (*ptr)^=val; return *this; }
    03553
    03555     CImg operator+(const T& val) const { return CImg<T>(*this)+=val; }
    03556
    03558     CImg operator-(const T& val) const { return CImg<T>(*this)-=val; }
    03559
    03561     CImg operator%(const T& val) const { return CImg<T>(*this)%=val; }
    03562
    03564     CImg operator&(const T& val) const { return CImg<T>(*this)&=val; }
    03565
    03567     CImg operator|(const T& val) const { return CImg<T>(*this)|=val; }
    03568
    03570     CImg operator^(const T& val) const { return CImg<T>(*this)^=val; }
    03571
    03573     CImg operator!() const {
    03574       CImg<T> res(*this,false);
    03575       const T *ptrs = ptr() + size();
    03576       cimg_map(res,ptrd,T) *ptrd=!(*(--ptrs));
    03577       return res;
    03578     }
    03579
    03581     CImg operator~() const {
    03582       CImg<T> res(*this,false);
    03583       const T *ptrs = ptr() + size();
    03584       cimg_map(res,ptrd,T) *ptrd=~(*(--ptrs));
    03585       return res;
    03586     }
    03587
    03589     template<typename t> CImg& operator+=(const CImg<t>& img) {
    03590       const unsigned int smin = cimg::min(size(),img.size());
    03591       t *ptrs = img.data+smin;
    03592       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs))));
    03593       return *this;
    03594     }
    03596     template<typename t> CImg& operator-=(const CImg<t>& img) {
    03597       const unsigned int smin = cimg::min(size(),img.size());
    03598       t *ptrs = img.data+smin;
    03599       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs))));
    03600       return *this;
    03601     }
    03603     CImg& operator%=(const CImg& img) {
    03604       const unsigned int smin = cimg::min(size(),img.size());
    03605       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)%=*(--ptrs));
    03606       return *this;
    03607     }
    03609     CImg& operator&=(const CImg& img) {
    03610       const unsigned int smin = cimg::min(size(),img.size());
    03611       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)&=*(--ptrs));
    03612       return *this;
    03613     }
    03615     CImg& operator|=(const CImg& img) {
    03616       const unsigned int smin = cimg::min(size(),img.size());
    03617       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)|=*(--ptrs));
    03618       return *this;
    03619     }
    03621     CImg& operator^=(const CImg& img) {
    03622       const unsigned int smin = cimg::min(size(),img.size());
    03623       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)^=*(--ptrs));
    03624       return *this;
    03625     }
    03626
    03628     template<typename t> CImg operator+(const CImg<t>& img)  const { return CImg<T>(*this)+=img; }
    03629
    03631     template<typename t> CImg operator-(const CImg<t>& img)  const { return CImg<T>(*this)-=img; }
    03632
    03634     CImg operator%(const CImg& img) const { return CImg<T>(*this)%=img; }
    03635
    03637     CImg operator&(const CImg& img) const { return CImg<T>(*this)&=img; }
    03638
    03640     CImg operator|(const CImg& img) const { return CImg<T>(*this)|=img; }
    03641
    03643     CImg operator^(const CImg& img) const { return CImg<T>(*this)^=img; }
    03644
    03646     CImg& operator*=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)*val); return *this; }
    03647
    03649     CImg& operator/=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)/val); return *this; }
    03650
    03652     CImg operator*(const double val) const { return CImg<T>(*this)*=val; }
    03653
    03655     CImg operator/(const double val) const { return CImg<T>(*this)/=val; }
    03656
    03658     friend CImg operator+(const T& val, const CImg& img) { return CImg<T>(img)+=val; }
    03659
    03661     friend CImg operator*(const double val,const CImg &img) { return CImg<T>(img)*=val; }
    03662
    03664     friend CImg operator-(const T& val, const CImg& img) { return CImg<T>(img.width,img.height,img.depth,img.dim,val)-=img; }
    03665
    03667     template<typename t> const bool operator==(const CImg<t>& img) const {
    03668       const unsigned int siz = size();
    03669       bool vequal = true;
    03670       if (siz!=img.size()) return false;
    03671       t *ptrs=img.data+siz;
    03672       for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs))));
    03673       return vequal;
    03674     }
    03676     template<typename t> const bool operator!=(const CImg<t>& img) const { return !((*this)==img); }
    03677
    03679     //--------------------------------------------------
    03680     //--------------------------------------------------
    03681     //
    03683
    03684     //--------------------------------------------------
    03685     //--------------------------------------------------
    03686
    03688
    03694     template<typename t> CImg& mul(const CImg<t>& img) {
    03695       t *ptrs = img.data;
    03696       T *ptrf = data + cimg::min(size(),img.size());
    03697       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd*(*(ptrs++)));
    03698       return *this;
    03699     }
    03700
    03702
    03708     template<typename t> CImg get_mul(const CImg<t>& img) const { return CImg<T>(*this).mul(img); }
    03709
    03711
    03717     template<typename t> CImg& div(const CImg<t>& img) {
    03718       t *ptrs = img.data;
    03719       T *ptrf = data + cimg::min(size(),img.size());
    03720       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd/(*(ptrs++)));
    03721       return *this;
    03722     }
    03723
    03725
    03731     template<typename t> CImg get_div(const CImg<t>& img) const { return CImg<T>(*this).div(img); }
    03732
    03734
    03738     template<typename t> CImg& max(const CImg<t>& img) {
    03739       t *ptrs = img.data;
    03740       T *ptrf = data + cimg::min(size(),img.size());
    03741       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::max((T)(*(ptrs++)),*ptrd);
    03742       return *this;
    03743     }
    03745
    03749     template<typename t> CImg get_max(const CImg<t>& img) const { return CImg<T>(*this).max(img); }
    03750
    03752
    03756     template<typename t> CImg& min(const CImg<t>& img) {
    03757       t *ptrs = img.data;
    03758       T *ptrf = data + cimg::min(size(),img.size());
    03759       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::min((T)(*(ptrs++)),*ptrd);
    03760       return *this;
    03761     }
    03763
    03767     template<typename t> CImg get_min(const CImg<t>& img) const { return CImg<T>(*this).min(img); }
    03768
    03770
    03773     CImg& sqrt() {
    03774       cimg_map(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr));
    03775       return *this;
    03776     }
    03777
    03779
    03782     CImg get_sqrt() const { return CImg<T>(*this).sqrt(); }
    03783
    03785
    03788     CImg& log() {
    03789       cimg_map(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr));
    03790       return *this;
    03791     }
    03792
    03794
    03797     CImg get_log() const { return CImg<T>(*this).log(); }
    03798
    03800
    03803     CImg& log10() {
    03804       cimg_map(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr));
    03805       return *this;
    03806     }
    03807
    03809
    03812     CImg get_log10() const { return CImg<T>(*this).log10(); }
    03813
    03815
    03819     CImg& pow(const double p) {
    03820       cimg_map(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p);
    03821       return *this;
    03822     }
    03823
    03825
    03829     CImg get_pow(const double p) const { return CImg<T>(*this).pow(p); }
    03830
    03832
    03835     CImg& abs() {
    03836       cimg_map(*this,ptr,T) (*ptr)=cimg::abs(*ptr);
    03837       return *this;
    03838     }
    03839
    03841
    03844     CImg get_abs() const { return CImg<T>(*this).abs(); }
    03845
    03847
    03850     CImg& cos() {
    03851       cimg_map(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr));
    03852       return *this;
    03853     }
    03854
    03856
    03859     CImg get_cos() const { return CImg<T>(*this).cos(); }
    03860
    03862
    03865     CImg& sin() {
    03866       cimg_map(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr));
    03867       return *this;
    03868     }
    03869
    03871
    03874     CImg get_sin() const { return CImg<T>(*this).sin(); }
    03875
    03877
    03880     CImg& tan() {
    03881       cimg_map(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr));
    03882       return *this;
    03883     }
    03884
    03886
    03889     CImg get_tan() const { return CImg<T>(*this).tan(); }
    03890
    03891
    03893     //------------------------------------------
    03894     //------------------------------------------
    03895     //
    03897
    03898     //------------------------------------------
    03899     //------------------------------------------
    03900
    03902
    03906     CImg& fill(const T& val) {
    03907       cimg_test(*this,"CImg<T>::fill");
    03908       if (val!=0 && sizeof(T)!=1) cimg_map(*this,ptr,T) *ptr=val;
    03909       else std::memset(data,(int)val,size()*sizeof(T));
    03910       return *this;
    03911     }
    03912
    03914
    03918     CImg& fill(const T& val0,const T& val1) {
    03919       T *ptr, *ptr_end = data+size();
    03920       for (ptr=data;   ptr<ptr_end; ptr+=2) *ptr=val0;
    03921       for (ptr=data+1; ptr<ptr_end; ptr+=2) *ptr=val1;
    03922       return *this;
    03923     }
    03924
    03926
    03931     CImg& fill(const T& val0,const T& val1,const T& val2) {
    03932       T *ptr, *ptr_end = data+size();
    03933       for (ptr=data;   ptr<ptr_end; ptr+=3) *ptr=val0;
    03934       for (ptr=data+1; ptr<ptr_end; ptr+=3) *ptr=val1;
    03935       for (ptr=data+2; ptr<ptr_end; ptr+=3) *ptr=val2;
    03936       return *this;
    03937     }
    03938
    03940
    03946     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3) {
    03947       T *ptr, *ptr_end = data+size();
    03948       for (ptr=data;   ptr<ptr_end; ptr+=4) *ptr=val0;
    03949       for (ptr=data+1; ptr<ptr_end; ptr+=4) *ptr=val1;
    03950       for (ptr=data+2; ptr<ptr_end; ptr+=4) *ptr=val2;
    03951       for (ptr=data+3; ptr<ptr_end; ptr+=4) *ptr=val3;
    03952       return *this;
    03953     }
    03954
    03956
    03963     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4) {
    03964       T *ptr, *ptr_end = data+size();
    03965       for (ptr=data;   ptr<ptr_end; ptr+=5) *ptr=val0;
    03966       for (ptr=data+1; ptr<ptr_end; ptr+=5) *ptr=val1;
    03967       for (ptr=data+2; ptr<ptr_end; ptr+=5) *ptr=val2;
    03968       for (ptr=data+3; ptr<ptr_end; ptr+=5) *ptr=val3;
    03969       for (ptr=data+4; ptr<ptr_end; ptr+=5) *ptr=val4;
    03970       return *this;
    03971     }
    03972
    03974
    03982     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5) {
    03983       T *ptr, *ptr_end = data+size();
    03984       for (ptr=data;   ptr<ptr_end; ptr+=6) *ptr=val0;
    03985       for (ptr=data+1; ptr<ptr_end; ptr+=6) *ptr=val1;
    03986       for (ptr=data+2; ptr<ptr_end; ptr+=6) *ptr=val2;
    03987       for (ptr=data+3; ptr<ptr_end; ptr+=6) *ptr=val3;
    03988       for (ptr=data+4; ptr<ptr_end; ptr+=6) *ptr=val4;
    03989       for (ptr=data+5; ptr<ptr_end; ptr+=6) *ptr=val5;
    03990       return *this;
    03991     }
    03992
    03994
    04003     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5,const T& val6,const T& val7) {
    04004       T *ptr, *ptr_end = data+size();
    04005       for (ptr=data;   ptr<ptr_end; ptr+=8) *ptr=val0;
    04006       for (ptr=data+1; ptr<ptr_end; ptr+=8) *ptr=val1;
    04007       for (ptr=data+2; ptr<ptr_end; ptr+=8) *ptr=val2;
    04008       for (ptr=data+3; ptr<ptr_end; ptr+=8) *ptr=val3;
    04009       for (ptr=data+4; ptr<ptr_end; ptr+=8) *ptr=val4;
    04010       for (ptr=data+5; ptr<ptr_end; ptr+=8) *ptr=val5;
    04011       for (ptr=data+6; ptr<ptr_end; ptr+=8) *ptr=val6;
    04012       for (ptr=data+7; ptr<ptr_end; ptr+=8) *ptr=val7;
    04013       return *this;
    04014     }
    04015
    04017
    04027     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5,const T& val6,const T& val7,const T& val8) {
    04028       T *ptr, *ptr_end = data+size();
    04029       for (ptr=data;   ptr<ptr_end; ptr+=9) *ptr=val0;
    04030       for (ptr=data+1; ptr<ptr_end; ptr+=9) *ptr=val1;
    04031       for (ptr=data+2; ptr<ptr_end; ptr+=9) *ptr=val2;
    04032       for (ptr=data+3; ptr<ptr_end; ptr+=9) *ptr=val3;
    04033       for (ptr=data+4; ptr<ptr_end; ptr+=9) *ptr=val4;
    04034       for (ptr=data+5; ptr<ptr_end; ptr+=9) *ptr=val5;
    04035       for (ptr=data+6; ptr<ptr_end; ptr+=9) *ptr=val6;
    04036       for (ptr=data+7; ptr<ptr_end; ptr+=9) *ptr=val7;
    04037       for (ptr=data+8; ptr<ptr_end; ptr+=9) *ptr=val8;
    04038       return *this;
    04039     }
    04040
    04042
    04054     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,
    04055                const T& val5,const T& val6,const T& val7,const T& val8,const T& val9) {
    04056       T *ptr, *ptr_end = data+size();
    04057       for (ptr=data;   ptr<ptr_end; ptr+=10) *ptr=val0;
    04058       for (ptr=data+1; ptr<ptr_end; ptr+=10) *ptr=val1;
    04059       for (ptr=data+2; ptr<ptr_end; ptr+=10) *ptr=val2;
    04060       for (ptr=data+3; ptr<ptr_end; ptr+=10) *ptr=val3;
    04061       for (ptr=data+4; ptr<ptr_end; ptr+=10) *ptr=val4;
    04062       for (ptr=data+5; ptr<ptr_end; ptr+=10) *ptr=val5;
    04063       for (ptr=data+6; ptr<ptr_end; ptr+=10) *ptr=val6;
    04064       for (ptr=data+7; ptr<ptr_end; ptr+=10) *ptr=val7;
    04065       for (ptr=data+8; ptr<ptr_end; ptr+=10) *ptr=val8;
    04066       for (ptr=data+9; ptr<ptr_end; ptr+=10) *ptr=val9;
    04067       return *this;
    04068     }
    04069
    04071
    04085     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5,const T& val6,
    04086                const T& val7,const T& val8,const T& val9,const T& val10,const T& val11) {
    04087       T *ptr, *ptr_end = data+size();
    04088       for (ptr=data;   ptr<ptr_end; ptr+=12) *ptr=val0;
    04089       for (ptr=data+1; ptr<ptr_end; ptr+=12) *ptr=val1;
    04090       for (ptr=data+2; ptr<ptr_end; ptr+=12) *ptr=val2;
    04091       for (ptr=data+3; ptr<ptr_end; ptr+=12) *ptr=val3;
    04092       for (ptr=data+4; ptr<ptr_end; ptr+=12) *ptr=val4;
    04093       for (ptr=data+5; ptr<ptr_end; ptr+=12) *ptr=val5;
    04094       for (ptr=data+6; ptr<ptr_end; ptr+=12) *ptr=val6;
    04095       for (ptr=data+7; ptr<ptr_end; ptr+=12) *ptr=val7;
    04096       for (ptr=data+8; ptr<ptr_end; ptr+=12) *ptr=val8;
    04097       for (ptr=data+9; ptr<ptr_end; ptr+=12) *ptr=val9;
    04098       for (ptr=data+10; ptr<ptr_end; ptr+=12) *ptr=val10;
    04099       for (ptr=data+11; ptr<ptr_end; ptr+=12) *ptr=val11;
    04100       return *this;
    04101     }
    04103
    04121     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
    04122                const T& val4,const T& val5,const T& val6,const T& val7,
    04123                const T& val8,const T& val9,const T& val10,const T& val11,
    04124                const T& val12,const T& val13,const T& val14,const T& val15) {
    04125       T *ptr,*ptr_end = data+size();
    04126       for (ptr=data;   ptr<ptr_end; ptr+=16) *ptr=val0;
    04127       for (ptr=data+1; ptr<ptr_end; ptr+=16) *ptr=val1;
    04128       for (ptr=data+2; ptr<ptr_end; ptr+=16) *ptr=val2;
    04129       for (ptr=data+3; ptr<ptr_end; ptr+=16) *ptr=val3;
    04130       for (ptr=data+4; ptr<ptr_end; ptr+=16) *ptr=val4;
    04131       for (ptr=data+5; ptr<ptr_end; ptr+=16) *ptr=val5;
    04132       for (ptr=data+6; ptr<ptr_end; ptr+=16) *ptr=val6;
    04133       for (ptr=data+7; ptr<ptr_end; ptr+=16) *ptr=val7;
    04134       for (ptr=data+8; ptr<ptr_end; ptr+=16) *ptr=val8;
    04135       for (ptr=data+9; ptr<ptr_end; ptr+=16) *ptr=val9;
    04136       for (ptr=data+10; ptr<ptr_end; ptr+=16) *ptr=val10;
    04137       for (ptr=data+11; ptr<ptr_end; ptr+=16) *ptr=val11;
    04138       for (ptr=data+12; ptr<ptr_end; ptr+=16) *ptr=val12;
    04139       for (ptr=data+13; ptr<ptr_end; ptr+=16) *ptr=val13;
    04140       for (ptr=data+14; ptr<ptr_end; ptr+=16) *ptr=val14;
    04141       for (ptr=data+15; ptr<ptr_end; ptr+=16) *ptr=val15;
    04142       return *this;
    04143     }
    04144
    04146
    04151     CImg& normalize(const T& a,const T& b) {
    04152       cimg_test(*this,"CImg<T>::normalize");
    04153       const CImgStats st(*this,false);
    04154       if (st.min==st.max) fill(0);
    04155       else cimg_map(*this,ptr,T) *ptr=(T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a);
    04156       return *this;
    04157     }
    04158
    04160
    04165     CImg get_normalize(const T& a,const T& b) const { return CImg<T>(*this).normalize(a,b); }
    04166
    04168
    04173     CImg& cut(const T& a, const T& b) {
    04174       cimg_test(*this,"CImg<T>::cut");
    04175       cimg_map(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
    04176       return *this;
    04177     }
    04178
    04180
    04185     CImg get_cut(const T& a, const T& b) const { return CImg<T>(*this).cut(a,b); }
    04186
    04188
    04192     CImg& quantify(const unsigned int n=256) {
    04193       cimg_test(*this,"CImg<T>::quantify");
    04194       const CImgStats st(*this,false);
    04195       const double range = st.max-st.min;
    04196       cimg_map(*this,ptr,T) *ptr = (T)(st.min + range*(int)((*ptr-st.min)*(int)n/range)/n);
    04197       return *this;
    04198     }
    04199
    04201
    04205     CImg get_quantify(const unsigned int n=256) const { return CImg<T>(*this).quantify(n); }
    04206
    04208
    04212     CImg& threshold(const T& thres) {
    04213       cimg_test(*this,"CImg<T>::threshold");
    04214       cimg_map(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1;
    04215       return *this;
    04216     }
    04217
    04219
    04223     CImg get_threshold(const T& thres) const { return CImg<T>(*this).threshold(thres); }
    04224
    04226
    04235     CImg get_rotate(const float angle,const unsigned int cond=2) const {
    04236       cimg_test(*this,"CImg<T>::get_rotate");
    04237       CImg dest;
    04238       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
    04239         ca=(float)std::cos(rad), sa=(float)std::sin(rad);
    04240
    04241       if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
    04242         const int iangle = (int)nangle/90;
    04243         switch (iangle) {
    04244         case 1: {
    04245           dest = CImg<T>(height,width,depth,dim);
    04246           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,height-1-x,z,v);
    04247         } break;
    04248         case 2: {
    04249           dest = CImg<T>(width,height,depth,dim);
    04250           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
    04251         } break;
    04252         case 3: {
    04253           dest = CImg<T>(height,width,depth,dim);
    04254           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-y,x,z,v);
    04255         } break;
    04256         default:
    04257           return *this;
    04258         }
    04259       } else { // generic version
    04260         const float
    04261           ux  = (float)(std::fabs(width*ca)),  uy  = (float)(std::fabs(width*sa)),
    04262           vx  = (float)(std::fabs(height*sa)), vy  = (float)(std::fabs(height*ca)),
    04263           w2  = 0.5f*width,           h2  = 0.5f*height,
    04264           dw2 = 0.5f*(ux+vx),         dh2 = 0.5f*(uy+vy);
    04265         dest = CImg<T>((int)(ux+vx), (int)(uy+vy),depth,dim);
    04266
    04267         switch (cond) {
    04268         case 0: {
    04269           cimg_mapXY(dest,x,y)
    04270             cimg_mapZV(*this,z,v)
    04271             dest(x,y,z,v) = dirichlet_pix2d((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
    04272         } break;
    04273         case 1: {
    04274           cimg_mapXY(dest,x,y)
    04275             cimg_mapZV(*this,z,v)
    04276             dest(x,y,z,v) = (*this)(cimg::modi((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width),
    04277                                     cimg::modi((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height),z,v);
    04278         } break;
    04279         default: {
    04280           cimg_mapXY(dest,x,y) {
    04281             const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
    04282             const int ix = (int)X, iy = (int)Y;
    04283             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
    04284             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
    04285           }
    04286         } break;
    04287         }
    04288       }
    04289       return dest;
    04290     }
    04291
    04293
    04301     CImg& rotate(const float angle,const unsigned int cond=2) { return get_rotate(angle,cond).swap(*this); }
    04302
    04304
    04314     CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) const {
    04315       cimg_test(*this,"CImg<T>::get_rotate");
    04316       CImg dest(*this,false);
    04317       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
    04318         ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom;
    04319
    04320       if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
    04321         const int iangle = (int)nangle/90;
    04322         switch (iangle) {
    04323         case 1: {
    04324           dest.fill(0);
    04325           const unsigned int
    04326             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
    04327             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
    04328             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
    04329             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
    04330           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
    04331             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
    04332         } break;
    04333         case 2: {
    04334           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
    04335         } break;
    04336         case 3: {
    04337           dest.fill(0);
    04338           const unsigned int
    04339             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
    04340             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
    04341             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
    04342             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
    04343           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
    04344             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
    04345         } break;
    04346         default:
    04347           return *this;
    04348         }
    04349       } else
    04350         switch (cond) { // generic version
    04351         case 0: {
    04352           cimg_mapXY(dest,x,y)
    04353             cimg_mapZV(*this,z,v)
    04354             dest(x,y,z,v) = dirichlet_pix2d((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
    04355         } break;
    04356         case 1: {
    04357           cimg_mapXY(dest,x,y)
    04358             cimg_mapZV(*this,z,v)
    04359             dest(x,y,z,v) = (*this)(cimg::modi((int)(cx + (x-cx)*ca + (y-cy)*sa),width),
    04360                                     cimg::modi((int)(cy - (x-cx)*sa + (y-cy)*ca),height),z,v);
    04361         } break;
    04362         default: {
    04363           cimg_mapXY(dest,x,y) {
    04364             const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
    04365             const int ix = (int)X, iy = (int)Y;
    04366             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
    04367             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
    04368           }
    04369         } break;
    04370         }
    04371       return dest;
    04372     }
    04373
    04375
    04386     CImg& rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) {
    04387       return get_rotate(angle,cx,cy,zoom,cond).swap(*this);
    04388     }
    04389
    04391
    04405     CImg get_resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) const {
    04406       cimg_test(*this,"CImg<T>::get_resize");
    04407       const unsigned int
    04408         dx = pdx<0?-pdx*width/100:pdx,
    04409         dy = pdy<0?-pdy*height/100:pdy,
    04410         dz = pdz<0?-pdz*depth/100:pdz,
    04411         dv = pdv<0?-pdv*dim/100:pdv;
    04412       CImg res(dx?dx:1,dy?dy:1,dz?dz:1,dv?dv:1);
    04413       if (width==res.width && height==res.height && depth==res.depth && dim==res.dim) return *this;
    04414       switch (interp) {
    04415       case 0:                 // 0 filling
    04416         {
    04417           unsigned int w = cimg::min(dx,width), h = cimg::min(dy,height), d = cimg::min(dz,depth), v = cimg::min(dv,dim);
    04418           T *ptr = data;
    04419           w*=sizeof(T);
    04420           res.fill(0);
    04421           for (unsigned int k=0; k<v; k++) for (unsigned int z=0; z<d; z++) for (unsigned int y=0; y<h; y++) {
    04422             std::memcpy(res.ptr(0,y,z,k),ptr,w); ptr+=width;
    04423           }
    04424         }
    04425         break;
    04426       case 1:               // bloc interpolation
    04427         {
    04428           const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
    04429           float cx,cy,cz,ck=0;
    04430           cimg_mapV(res,k) { cz = 0;
    04431             cimg_mapZ(res,z) { cy = 0;
    04432               cimg_mapY(res,y) { cx = 0;
    04433                 cimg_mapX(res,x) { res(x,y,z,k) = (*this)((unsigned int)cx,(unsigned int)cy,(unsigned int)cz,(unsigned int)ck); cx+=sx;
    04434                 } cy+=sy;
    04435               } cz+=sz;
    04436             } ck+=sk;
    04437           }
    04438         }
    04439         break;
    04440       case 2:               // mosaic filling
    04441         {
    04442           cimg_mapXYZV(res,x,y,z,k) res(x,y,z,k) = (*this)(x%width,y%height,z%depth,k%dim);
    04443         }
    04444         break;
    04445       case 3:               // linear interpolation
    04446         {
    04447           const float
    04448             sx = res.width>1?(float)(width-1)/(res.width-1):0,
    04449             sy = res.height>1?(float)(height-1)/(res.height-1):0,
    04450             sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
    04451             sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
    04452           float cx,cy,cz,ck = 0;
    04453           cimg_mapV(res,k) { cz = 0;
    04454             cimg_mapZ(res,z) { cy = 0;
    04455               cimg_mapY(res,y) { cx = 0;
    04456                 cimg_mapX(res,x) { res(x,y,z,k) = (T)linear_pix4d(cx,cy,cz,ck); cx+=sx;
    04457                 } cy+=sy;
    04458               } cz+=sz;
    04459             } ck+=sk;
    04460           }
    04461         }
    04462         break;
    04463       case 4:              // grid filling
    04464         {
    04465           const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
    04466           res.fill(0);
    04467           cimg_mapXYZV(*this,x,y,z,k) res((int)(x/sx),(int)(y/sy),(int)(z/sz),(int)(k/sk)) = (*this)(x,y,z,k);
    04468         }
    04469         break;
    04470       case 5:             // cubic interpolation
    04471         {
    04472           const float
    04473             sx = res.width>1?(float)(width-1)/(res.width-1):0,
    04474             sy = res.height>1?(float)(height-1)/(res.height-1):0,
    04475             sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
    04476             sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
    04477           float cx,cy,cz,ck = 0;
    04478           cimg_mapV(res,k) { cz = 0;
    04479             cimg_mapZ(res,z) { cy = 0;
    04480               cimg_mapY(res,y) { cx = 0;
    04481                 cimg_mapX(res,x) { res(x,y,z,k) = (T)cubic_pix2d(cx,cy,(int)cz,(int)ck); cx+=sx;
    04482                 } cy+=sy;
    04483               } cz+=sz;
    04484             } ck+=sk;
    04485           }
    04486         }
    04487         break;
    04488       }
    04489       return res;
    04490     }
    04492
    04503     template<typename t> CImg get_resize(const CImg<t>& src,const unsigned int interp=1) const {
    04504       return get_resize(src.width,src.height,src.depth,src.dim,interp);
    04505     }
    04506
    04508
    04519     CImg get_resize(const CImgDisplay& disp,const unsigned int interp=1) const {
    04520       return get_resize(disp.width,disp.height,depth,dim,interp);
    04521     }
    04522
    04524
    04538     CImg& resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) {
    04539       const unsigned int
    04540         dx = pdx<0?-pdx*width/100 :(pdx==0?1:pdx),
    04541         dy = pdy<0?-pdy*height/100:(pdy==0?1:pdy),
    04542         dz = pdz<0?-pdz*depth/100 :(pdz==0?1:pdz),
    04543         dv = pdv<0?-pdv*dim/100   :(pdv==0?1:pdv);
    04544       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
    04545       else return get_resize(dx,dy,dz,dv,interp).swap(*this);
    04546     }
    04547
    04549
    04560     template<typename t> CImg& resize(const CImg<t>& src,const unsigned int interp=1) {
    04561       return resize(src.width,src.height,src.depth,src.dim,interp);
    04562     }
    04563
    04565
    04576     CImg& resize(const CImgDisplay& disp,const unsigned int interp=1) {
    04577       return resize(disp.width,disp.height,depth,dim,interp);
    04578     }
    04579
    04581
    04584     CImg get_resize_halfXY() const {
    04585       cimg_test(*this,"CImg<T>::get_resize_halfXY");
    04586       const CImg<float> mask(3,3);
    04587       mask.fill(0.07842776544f, 0.1231940459f, 0.07842776544f,
    04588                 0.1231940459f,  0.1935127547f, 0.1231940459f,
    04589                 0.07842776544f, 0.1231940459f, 0.07842776544f);
    04590       CImg_3x3(I,float);
    04591       CImg dest(width/2,height/2,depth,dim);
    04592       cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) dest(x/2,y/2,z,k) = (T)cimg_conv3x3(I,mask);
    04593       return dest;
    04594     }
    04595
    04597
    04600     CImg& resize_halfXY() {     return get_resize_halfXY().swap(*this); }
    04601
    04603
    04614     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
    04615                   const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1) const {
    04616       cimg_test(*this,"CImg<T>::get_crop");
    04617       if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth || v0>=dim || v1>=dim || x1<x0 || y1<y0 || z1<z0 || v1<v0)
    04618         throw CImgArgumentException("CImg<%s>::get_crop() : Bad crop coordinates (%d,%d,%d,%d)-(%d,%d,%d,%d) in image (%d,%d,%d,%d)",
    04619                                     pixel_type(),x0,y0,z0,v0,x1,y1,z1,v1,width,height,depth,dim);
    04620       const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1;
    04621       CImg dest(dx,dy,dz,dv);
    04622       T *psrc = ptr(x0,y0,z0,v0), *pdest = dest.ptr(0,0,0,0);
    04623       if (dx!=width)
    04624         for (unsigned int k=0; k<dv; k++) {
    04625           for (unsigned int z=0; z<dz; z++) {
    04626             for (unsigned int y=0; y<dy; y++) {
    04627               std::memcpy(pdest,psrc,dx*sizeof(T));
    04628               pdest+=dx;
    04629               psrc+=width;
    04630             }
    04631             psrc+=width*(height-dy);
    04632           }
    04633           psrc+=width*height*(depth-dz);
    04634         }
    04635       else {
    04636         if (dy!=height)
    04637           for (unsigned int k=0; k<dv; k++) {
    04638             for (unsigned int z=0; z<dz; z++) {
    04639               std::memcpy(pdest,psrc,dx*dy*sizeof(T));
    04640               pdest+=dx*dy;
    04641               psrc+=width*height;
    04642             }
    04643             psrc+=width*height*(depth-dz);
    04644           }
    04645         else {
    04646           if (dz!=depth)
    04647             for (unsigned int k=0; k<dv; k++) {
    04648               std::memcpy(pdest,psrc,dx*dy*dz*sizeof(T));
    04649               pdest+=dx*dy*dz;
    04650               psrc+=width*height*depth;
    04651             }
    04652           else std::memcpy(pdest,psrc,dx*dy*dz*dv*sizeof(T));
    04653         }
    04654       }
    04655       return dest;
    04656     }
    04657
    04659
    04668     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
    04669                   const unsigned int x1,const unsigned int y1,const unsigned int z1) const {
    04670       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1);
    04671     }
    04672
    04674
    04681     CImg get_crop(const unsigned int x0,const unsigned int y0,
    04682                   const unsigned int x1,const unsigned int y1) const {
    04683       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1);
    04684     }
    04685
    04687
    04692     CImg get_crop(const unsigned int x0,const unsigned int x1) const { return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1); }
    04693
    04695
    04706     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
    04707                const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1) {
    04708       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1).swap(*this);
    04709     }
    04710
    04712
    04721     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
    04722                const unsigned int x1,const unsigned int y1,const unsigned int z1) {
    04723       return crop(x0,y0,z0,0,x1,y1,z1,dim-1);
    04724     }
    04725
    04727
    04734     CImg& crop(const unsigned int x0,const unsigned int y0,
    04735                const unsigned int x1,const unsigned int y1) { return crop(x0,y0,0,0,x1,y1,depth-1,dim-1); }
    04736
    04738
    04743     CImg& crop(const unsigned int x0,const unsigned int x1) { return crop(x0,0,0,0,x1,height-1,depth-1,dim-1); }
    04744
    04746
    04750     CImg get_channel(const unsigned int v0=0) const { return get_crop(0,0,0,v0,width-1,height-1,depth-1,v0); }
    04751
    04753
    04757     CImg get_slice(const unsigned int z0=0) const { return get_crop(0,0,z0,0,width-1,height-1,z0,dim-1); }
    04758
    04760
    04765     CImg get_plane(const unsigned int z0=0,const unsigned int v0=0) const { return get_crop(0,0,z0,v0,width-1,height-1,z0,v0); }
    04766
    04768     CImgROI<T> ref_pointset(const unsigned int xmin,const unsigned int xmax,const unsigned int y0=0,const unsigned int z0=0,const unsigned int v0=0) const {
    04769       cimg_test(*this,"CImg<T>::ref_pointset");
    04770       if (xmax<xmin || xmax>=width || y0>=height || z0>=depth || v0>=dim)
    04771         throw CImgArgumentException("CImg<%s>::ref_pointset() : Cannot return a reference (%d->%d,%d,%d,%d) from a (%d,%d,%d,%d) image",
    04772                                     pixel_type(),xmin,xmax,y0,z0,v0,width,height,depth,dim);
    04773       return CImgROI<T>(1+xmax-xmin,1,1,1,ptr(xmin,y0,z0,v0));
    04774     }
    04775
    04777     CImgROI<T> ref_lineset(const unsigned int ymin,const unsigned int ymax,const unsigned int z0=0,const unsigned int v0=0) const {
    04778       cimg_test(*this,"CImg<T>::ref_lineset");
    04779       if (ymax<ymin || ymax>=height || z0>=depth || v0>=dim)
    04780         throw CImgArgumentException("CImg<%s>::ref_lineset() : Cannot return a reference (0->%d,%d->%d,%d,%d) from a (%d,%d,%d,%d) image",
    04781                                     pixel_type(),width-1,ymin,ymax,z0,v0,width,height,depth,dim);
    04782       return CImgROI<T>(width,1+ymax-ymin,1,1,ptr(0,ymin,z0,v0));
    04783     }
    04784
    04786     CImgROI<T> ref_planeset(const unsigned int zmin,const unsigned int zmax,const unsigned int v0=0) const {
    04787       cimg_test(*this,"CImg<T>::ref_planeset");
    04788       if(zmax<zmin || zmax>=depth || v0>=dim)
    04789         throw CImgArgumentException("CImg<%s>::ref_planeset() : Cannot return a reference (0->%d,0->%d,%d->%d,%d) from a (%d,%d,%d,%d) image",
    04790                                     pixel_type(),width-1,height-1,zmin,zmax,v0,width,height,depth,dim);
    04791       return CImgROI<T>(width,height,1+zmax-zmin,1,ptr(0,0,zmin,v0));
    04792     }
    04793
    04795     CImgROI<T> ref_channelset(const unsigned int vmin,const unsigned int vmax) const {
    04796       cimg_test(*this,"CImg<T>::ref_channelset");
    04797       if (vmax<vmin || vmax>=dim)
    04798         throw CImgArgumentException("CImg<%s>::ref_channelset() : Cannot return a reference (0->%d,0->%d,0->%d,%d->%d) from a (%d,%d,%d,%d) image",
    04799                                     pixel_type(),width-1,height-1,depth-1,vmin,vmax,width,height,depth,dim);
    04800       return CImgROI<T>(width,height,depth,1+vmax-vmin,ptr(0,0,0,vmin));
    04801     }
    04802
    04804     CImgROI<T> ref_line(const unsigned int y0,const unsigned int z0=0,const unsigned int v0=0) const { return ref_pointset(0,width-1,y0,z0,v0); }
    04805
    04807     CImgROI<T> ref_plane(const unsigned int z0,const unsigned int v0=0) const { return ref_lineset(0,height-1,z0,v0); }
    04808
    04810     CImgROI<T> ref_channel(const unsigned int v0) const { return ref_planeset(0,depth-1,v0); }
    04811
    04813     CImg& channel(const unsigned int v0=0) { return get_channel(v0).swap(*this); }
    04814
    04816     CImg& slice(const unsigned int z0=0) { return get_slice(z0).swap(*this); }
    04817
    04819     CImg& plane(const unsigned int z0=0, const unsigned int v0=0) { return get_plane(z0,v0).swap(*this); }
    04820
    04822     CImg& flip(const char axe='x') {
    04823       cimg_test(*this,"CImg<T>::flip");
    04824       T *pf,*pb,*buf=NULL;
    04825       switch (axe) {
    04826       case 'x':
    04827         {
    04828           pf = ptr(); pb = ptr(width-1);
    04829           for (unsigned int yzv=0; yzv<height*depth*dim; yzv++) {
    04830             for (unsigned int x=0; x<width/2; x++) { const T val = *pf; *(pf++)=*pb; *(pb--)=val; }
    04831             pf+=width-width/2;
    04832             pb+=width+width/2;
    04833           }
    04834         }
    04835         break;
    04836       case 'y':
    04837         {
    04838           buf = new T[width];
    04839           pf = ptr(); pb = ptr(0,height-1);
    04840           for (unsigned int zv=0; zv<depth*dim; zv++) {
    04841             for (unsigned int y=0; y<height/2; y++) {
    04842               std::memcpy(buf,pf,width*sizeof(T));
    04843               std::memcpy(pf,pb,width*sizeof(T));
    04844               std::memcpy(pb,buf,width*sizeof(T));
    04845               pf+=width;
    04846               pb-=width;
    04847             }
    04848             pf+=width*(height-height/2);
    04849             pb+=width*(height+height/2);
    04850           }
    04851         }
    04852         break;
    04853       case 'z':
    04854         {
    04855           buf = new T[width*height];
    04856           pf = ptr(); pb = ptr(0,0,depth-1);
    04857           cimg_mapV(*this,v) {
    04858             for (unsigned int z=0; z<depth/2; z++) {
    04859               std::memcpy(buf,pf,width*height*sizeof(T));
    04860               std::memcpy(pf,pb,width*height*sizeof(T));
    04861               std::memcpy(pb,buf,width*height*sizeof(T));
    04862               pf+=width*height;
    04863               pb-=width*height;
    04864             }
    04865             pf+=width*height*(depth-depth/2);
    04866             pb+=width*height*(depth+depth/2);
    04867           }
    04868         }
    04869         break;
    04870       case 'v':
    04871         {
    04872           buf = new T[width*height*depth];
    04873           pf = ptr(); pb = ptr(0,0,0,dim-1);
    04874           for (unsigned int v=0; v<dim/2; v++) {
    04875             std::memcpy(buf,pf,width*height*depth*sizeof(T));
    04876             std::memcpy(pf,pb,width*height*depth*sizeof(T));
    04877             std::memcpy(pb,buf,width*height*depth*sizeof(T));
    04878             pf+=width*height*depth;
    04879             pb-=width*height*depth;
    04880           }
    04881         }
    04882         break;
    04883       default: cimg::warn(true,"CImg<%s>::flip() : unknow axe '%c', should be 'x','y','z' or 'v'",pixel_type(),axe);
    04884       }
    04885       if (buf) delete[] buf;
    04886       return *this;
    04887     }
    04889     CImg get_flip(const char axe='x') { return CImg<T>(*this).flip(axe); }
    04890
    04892     CImg get_3dplanes(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const {
    04893       cimg_test(*this,"CImg<T>::get_3dplanes");
    04894       const unsigned int
    04895         x0=(px0>=width)?width-1:px0,
    04896         y0=(py0>=height)?height-1:py0,
    04897         z0=(pz0>=depth)?depth-1:pz0;
    04898       CImg res(width+depth,height+depth,1,dim);
    04899       res.fill((*this)[0]);
    04900       { cimg_mapXYV(*this,x,y,k) res(x,y,0,k)        = (*this)(x,y,z0,k); }
    04901       { cimg_mapYZV(*this,y,z,k) res(width+z,y,0,k)  = (*this)(x0,y,z,k); }
    04902       { cimg_mapXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); }
    04903       return res;
    04904     }
    04905
    04907     CImg<float> get_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const {
    04908       cimg_test(*this,"CImg<T>::get_histogram");
    04909       if (nblevels<1) {
    04910         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %d levels",
    04911                                     pixel_type(),nblevels);
    04912       }
    04913       T vmin=val_min,vmax=val_max;
    04914       CImg<float> res(nblevels);
    04915       if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
    04916       res.fill(0);
    04917       cimg_map(*this,ptr,T) { const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); if (pos>=0 && pos<(int)nblevels) res[pos]++; }
    04918       return res;
    04919     }
    04920
    04922     CImg& equalize_histogram(const unsigned int nblevels=256) {
    04923       cimg_test(*this,"CImg<T>::equalize_histogram");
    04924       CImgStats st(*this,false);
    04925       CImg<float> hist = get_histogram(nblevels,(T)st.min,(T)st.max);
    04926       float cumul=0;
    04927       cimg_mapX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
    04928       cimg_map(*this,ptr,T) {
    04929         unsigned int pos = (unsigned int)((*ptr-st.min)*nblevels/(1+st.max-st.min));
    04930         *ptr = (T)(st.min + (st.max-st.min)*hist[pos]/size());
    04931       }
    04932       return *this;
    04933     }
    04935     CImg get_equalize_histogram(const unsigned int nblevels=256) const { return CImg<T>(*this).equalize_histogram(nblevels); }
    04936
    04938     CImg<float> get_norm_pointwise(int ntype=2) const {
    04939       cimg_test(*this,"CImg<T>::get_norm_pointwise");
    04940       CImg<float> res(width,height,depth);
    04941       switch(ntype) {
    04942       case -1:                // Linf norm
    04943         {
    04944           cimg_mapXYZ(*this,x,y,z) {
    04945             float n=0; cimg_mapV(*this,v) if (std::fabs((double)((*this)(x,y,z,v)))>n) n=(float)(*this)(x,y,z,v); res(x,y,z) = n;
    04946           }
    04947         } break;
    04948       case 1:               // L1 norm
    04949         {
    04950           cimg_mapXYZ(*this,x,y,z) {
    04951             float n=0; cimg_mapV(*this,v) n+=(float)std::fabs((double)((*this)(x,y,z,v))); res(x,y,z) = n;
    04952           }
    04953         } break;
    04954       default:              // L2 norm
    04955         {
    04956           cimg_mapXYZ(*this,x,y,z) {
    04957             float n=0; cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v)); res(x,y,z) = (float)std::sqrt((double)n);
    04958           }
    04959         } break;
    04960       }
    04961       return res;
    04962     }
    04963
    04965     CImg& norm_pointwise() { return CImg<T>(get_norm_pointwise()).swap(*this); }
    04966
    04968     CImg get_orientation_pointwise() const {
    04969       cimg_test(*this,"CImg<T>::get_orientation_pointwise");
    04970       CImg dest(width,height,depth,dim);
    04971       cimg_mapXYZ(dest,x,y,z) {
    04972         float n = 0;
    04973         cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
    04974         n = (float)std::sqrt((double)n);
    04975         if (n>0) cimg_mapV(dest,v) dest(x,y,z,v)=(T)((*this)(x,y,z,v)/n); else cimg_mapV(dest,v) dest(x,y,z,v)=0;
    04976       }
    04977       return dest;
    04978     }
    04979
    04981     CImg& orientation_pointwise() { return get_orientation_pointwise().swap(*this); }
    04982
    04984     CImgl<T> get_split(const char Axe='v') const {
    04985       cimg_test(*this,"CImg<T>::get_split");
    04986       const char axe = cimg::uncase(Axe);
    04987       const unsigned int n = (axe=='x'?width:(axe=='y'?height:(axe=='z'?depth:(axe=='v'?dim:0))));
    04988       if (n==0) throw CImgArgumentException("CImg<%s>::get_split() : Unknow axe '%c', use rather 'x','y','z' or 'v'",pixel_type(),Axe);
    04989       CImgl<T> res(n);
    04990       cimgl_map(res,l) switch(axe) {
    04991       case 'x': res[l] = get_crop(l,0,0,0,l,height-1,depth-1,dim-1);   break;
    04992       case 'y': res[l] = get_crop(0,l,0,0,width-1,l,depth-1,dim-1);    break;
    04993       case 'z': res[l] = get_crop(0,0,l,0,width-1,height-1,l,dim-1);   break;
    04994       case 'v': res[l] = get_crop(0,0,0,l,width-1,height-1,depth-1,l); break;
    04995       }
    04996       return res;
    04997     }
    04998
    05000     CImgl<T> get_gradientXY(const int scheme=0) const {
    05001       cimg_test(*this,"CImg<T>::get_gradientXY");
    05002       CImgl<T> res(2,width,height,depth,dim);
    05003       CImg_3x3(I,T);
    05004       switch(scheme) {
    05005       case -1: { // backward finite differences
    05006         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = Icc-Ipc; res[1](x,y,z,k) = Icc-Icp; }
    05007       } break;
    05008       case 1: { // forward finite differences
    05009         cimg_mapZV(*this,z,k) cimg_map2x2(*this,x,y,z,k,I) { res[0](x,y,0,k) = Inc-Icc; res[1](x,y,z,k) = Icn-Icc; }
    05010       } break;
    05011       case 2: { // using Sobel mask
    05012         const float a = 1, b = 2;
    05013         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05014           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
    05015           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
    05016         }
    05017       } break;
    05018       case 3: { // using rotation invariant mask
    05019         const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1));
    05020         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05021           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
    05022           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
    05023         }
    05024       } break;
    05025       case 0:
    05026       default: { // central finite differences
    05027         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05028           res[0](x,y,z,k) = (T)(0.5*(Inc-Ipc));
    05029           res[1](x,y,z,k) = (T)(0.5*(Icn-Icp));
    05030         }
    05031       } break;
    05032       }
    05033       return res;
    05034     }
    05035
    05037     CImgl<T> get_gradientXYZ(const int scheme=0) const {
    05038       cimg_test(*this,"CImg<T>::get_gradientXYZ");
    05039       CImgl<T> res(3,width,height,depth,dim);
    05040       CImg_3x3x3(I,T);
    05041       switch(scheme) {
    05042       case -1: { // backward finite differences
    05043         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05044           res[0](x,y,z,k) = Iccc-Ipcc;
    05045           res[1](x,y,z,k) = Iccc-Icpc;
    05046           res[2](x,y,z,k) = Iccc-Iccp;
    05047         }
    05048       } break;
    05049       case 1: { // forward finite differences
    05050         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05051           res[0](x,y,z,k) = Incc-Iccc;
    05052           res[1](x,y,z,k) = Icnc-Iccc;
    05053           res[2](x,y,z,k) = Iccn-Iccc;
    05054         }
    05055       } break;
    05056       case 0:
    05057       default: { // central finite differences
    05058         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05059           res[0](x,y,z,k) = (T)(0.5*(Incc-Ipcc));
    05060           res[1](x,y,z,k) = (T)(0.5*(Icnc-Icpc));
    05061           res[2](x,y,z,k) = (T)(0.5*(Iccn-Iccp));
    05062         }
    05063       } break;
    05064       }
    05065       return res;
    05066     }
    05067
    05069     //--------------------------------------
    05070     //--------------------------------------
    05071     //
    05073
    05074     //--------------------------------------
    05075     //--------------------------------------
    05076
    05078     CImg& RGBtoXYZ() {
    05079       cimg_test(*this,"CImg<T>::RGBtoXYZ");
    05080       if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%d, should be a (R,G,B) image (dim=3)",
    05081                                               pixel_type(),dim);
    05082       cimg_mapXYZ(*this,x,y,z) {
    05083         const T R = (*this)(x,y,z,0), G = (*this)(x,y,z,1), B = (*this)(x,y,z,2);
    05084         (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B);
    05085         (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B);
    05086         (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B);
    05087       }
    05088       return *this;
    05089     }
    05091     CImg get_RGBtoXYZ() const { return CImg<T>(*this).RGBtoXYZ(); }
    05092
    05094     CImg& XYZtoRGB() {
    05095       cimg_test(*this,"CImg<T>::XYZtoRGB");
    05096       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%d, should be a (X,Y,Z) image (dim=3)",
    05097                                               pixel_type(),dim);
    05098       cimg_mapXYZ(*this,x,y,z) {
    05099         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
    05100         (*this)(x,y,z,0) = (T)(3.240479*X  - 1.537150*Y - 0.498535*Z);
    05101         (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z);
    05102         (*this)(x,y,z,2) = (T)(0.055648*X  - 0.204043*Y + 1.057311*Z);
    05103       }
    05104       return *this;
    05105     }
    05107     CImg get_XYZtoRGB() const { return CImg<T>(*this).XYZtoRGB(); }
    05108
    05110     CImg& XYZtoLab() {
    05111       cimg_test(*this,"CImg<T>::XYZtoLab");
    05112       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%d, should be a (X,Y,Z) image (dim=3)",
    05113                                               pixel_type(),dim);
    05114       CImg<double> white = CImg<double>(1,1,1,3).fill(1,1,1).RGBtoXYZ();
    05115       const double Xn = white(0), Yn = white(1), Zn = white(2);
    05116
    05117       cimg_mapXYZ(*this,x,y,z) {
    05118         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
    05119         const double L = (T)(116*std::pow(Y/Yn,1/3.0)-16);
    05120         (*this)(x,y,z,0) = (T)(L>=0?L:0);
    05121         (*this)(x,y,z,1) = (T)(500*(std::pow(X/Xn,1/3.0)-std::pow(Y/Yn,1/3.0)));
    05122         (*this)(x,y,z,2) = (T)(200*(std::pow(Y/Yn,1/3.0)-std::pow(Z/Zn,1/3.0)));
    05123       }
    05124       return *this;
    05125     }
    05127     CImg get_XYZtoLab() const { return CImg<T>(*this).XYZtoLab(); }
    05128
    05130     //--------------------------------------
    05131     //--------------------------------------
    05132     //
    05134
    05135     //--------------------------------------
    05136     //--------------------------------------
    05137
    05139
    05147     CImg& draw_point(const int x0,const int y0,const int z0,
    05148                      const T *const color,const float opacity=1) {
    05149       cimg_test(*this,"CImg<T>::draw_point");
    05150       if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : specified color is (null)",pixel_type());
    05151       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
    05152         const T *col=color;
    05153         const unsigned int whz = width*height*depth;
    05154         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05155         T *ptrd = ptr(x0,y0,z0,0);
    05156         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
    05157         else cimg_mapV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
    05158       }
    05159       return *this;
    05160     }
    05161
    05163
    05170     CImg& draw_point(const int x0,const int y0,const T *const color,const float opacity=1) {
    05171       return draw_point(x0,y0,0,color,opacity);
    05172     }
    05173
    05175
    05185     CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
    05186                     const T *const color,const unsigned long pattern=~0L,const float opacity=1) {
    05187       cimg_test(*this,"CImg<T>::draw_line");
    05188       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
    05189       const T* col=color;
    05190       unsigned long hatch=1;
    05191       int nx0=x0, nx1=x1, ny0=y0, ny1=y1;
    05192       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1);
    05193       if (nx1<0 || nx0>=dimx()) return *this;
    05194       if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; }
    05195       if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;}
    05196       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
    05197       if (ny1<0 || ny0>=dimy()) return *this;
    05198       if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; }
    05199       if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;}
    05200       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),ny1-ny0), whz = width*height*depth;
    05201       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0;
    05202       float x = (float)nx0, y = (float)ny0;
    05203       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
    05204         if (!(~pattern) || (~pattern && pattern&hatch)) {
    05205           T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05206           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
    05207           col-=dim;
    05208         }
    05209         x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05210       } else {
    05211         const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f);
    05212         for (unsigned int t=0; t<=dmax; t++) {
    05213           if (!(~pattern) || (~pattern && pattern&hatch)) {
    05214             T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05215             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
    05216             col-=dim;
    05217           }
    05218           x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05219         }
    05220       }
    05221       return *this;
    05222     }
    05223
    05225
    05237     CImg& draw_line(const int x0,const int y0,const int z0,const int x1,const int y1,const int z1,
    05238                     const T *const color,const unsigned long pattern=~0L,const float opacity=1) {
    05239       cimg_test(*this,"CImg<T>::draw_line");
    05240       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
    05241       const T* col=color;
    05242       unsigned long hatch=1;
    05243       int nx0=x0, ny0=y0, nz0=z0, nx1=x1, ny1=y1, nz1=z1;
    05244       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05245       if (nx1<0 || nx0>=dimx()) return *this;
    05246       if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; nz0-=nx0*(nz1-nz0)/D; nx0=0; }
    05247       if (nx1>=dimx()) { const int d=nx1-dimx(), D=nx1-nx0; ny1+=d*(ny0-ny1)/D; nz1+=d*(nz0-nz1)/D; nx1=dimx()-1;}
    05248       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05249       if (ny1<0 || ny0>=dimy()) return *this;
    05250       if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; nz0-=ny0*(nz1-nz0)/D; ny0=0; }
    05251       if (ny1>=dimy()) { const int d=ny1-dimy(), D=ny1-ny0; nx1+=d*(nx0-nx1)/D; nz1+=d*(nz0-nz1)/D; ny1=dimy()-1;}
    05252       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05253       if (nz1<0 || nz0>=dimz()) return *this;
    05254       if (nz0<0) { const int D=nz1-nz0; nx0-=nz0*(nx1-nx0)/D; ny0-=nz0*(ny1-ny0)/D; nz0=0; }
    05255       if (nz1>=dimz()) { const int d=nz1-dimz(), D=nz1-nz0; nx1+=d*(nx0-nx1)/D; ny1+=d*(ny0-ny1)/D; nz1=dimz()-1;}
    05256       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),std::abs(ny1-ny0),nz1-nz0), whz = width*height*depth;
    05257       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, pz = dmax?(nz1-nz0)/(float)dmax:0;
    05258       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
    05259       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
    05260         if (!(~pattern) || (~pattern && pattern&hatch)) {
    05261           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
    05262           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
    05263           col-=dim;
    05264         }
    05265         x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05266       } else {
    05267         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05268         for (unsigned int t=0; t<=dmax; t++) {
    05269           if (!(~pattern) || (~pattern && pattern&hatch)) {
    05270             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
    05271             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
    05272             col-=dim;
    05273           }
    05274           x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05275         }
    05276       }
    05277       return *this;
    05278     }
    05279
    05281
    05296     template<typename t> CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
    05297                                          const CImg<t>& texture,
    05298                                          const int tx0,const int ty0,const int tx1,const int ty1,
    05299                                          const float opacity=1) {
    05300       cimg_test(*this,"CImg<T>::draw_line"); cimg_test(texture,"CImg<T>::draw_line");
    05301       if (texture.dim<dim)
    05302         throw CImgArgumentException("CImg<%s>::draw_line() : texture has %d channel while image has %d channels",texture.dim,dim);
    05303       int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1;
    05304       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    05305       if (nx1<0 || nx0>=dimx()) return *this;
    05306       if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; ntx0-=nx0*(ntx1-ntx0)/D; nty0-=nx0*(nty1-nty0)/D; nx0=0; }
    05307       if (nx1>=dimx()) { const int d=nx1-dimx(),D=nx1-nx0; ny1+=d*(ny0-ny1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; nx1=dimx()-1; }
    05308       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    05309       if (ny1<0 || ny0>=dimy()) return *this;
    05310       if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; ntx0-=ny0*(ntx1-ntx0)/D; nty0-=ny0*(nty1-nty0)/D; ny0=0; }
    05311       if (ny1>=dimy()) { const int d=ny1-dimy(),D=ny1-ny0; nx1+=d*(nx0-nx1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; ny1=dimy()-1; }
    05312       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),ny1-ny0),
    05313         whz = width*height*depth, twhz = texture.width*texture.height*texture.depth;
    05314       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0,
    05315         tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0;
    05316       float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0;
    05317       if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) {
    05318         T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05319         t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
    05320         cimg_mapV(*this,k) { *ptrd = (T)(*ptrs); ptrd+=whz; ptrs+=twhz; }
    05321         x+=px; y+=py; tx+=tpx; ty+=tpy;
    05322       } else {
    05323         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05324         for (unsigned int tt=0; tt<=dmax; tt++) {
    05325           T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05326           t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
    05327           cimg_mapV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; }
    05328           x+=px; y+=py; tx+=tpx; ty+=tpy;
    05329         }
    05330       }
    05331       return *this;
    05332     }
    05333
    05335
    05347     CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1,
    05348                      const T *const color,
    05349                      const float angle=30,const float length=-10,const unsigned long pattern=~0L,const float opacity=1) {
    05350       cimg_test(*this,"CImg<T>::draw_arrow");
    05351       const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v,
    05352         deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
    05353         l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
    05354       if (sq>0) {
    05355         const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg);
    05356         const int
    05357           xl = x1+(int)(l*cl), yl = y1+(int)(l*sl),
    05358           xr = x1+(int)(l*cr), yr = y1+(int)(l*sr),
    05359           xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2;
    05360         draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
    05361       } else draw_point(x0,y0,color,opacity);
    05362       return *this;
    05363     }
    05364
    05366
    05375     template<typename t> CImg& draw_image(const CImg<t>& sprite,
    05376                                           const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) {
    05377       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image");
    05378       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05379       const int
    05380         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05381         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05382         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05383         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05384       const t *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
    05385         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
    05386       const unsigned int
    05387         offX = width-lX, soffX = sprite.width-lX,
    05388         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05389         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
    05390       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05391       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05392       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05393         for (int v=0; v<lV; v++) {
    05394           for (int z=0; z<lZ; z++) {
    05395             for (int y=0; y<lY; y++) {
    05396               if (opacity>=1) for (int x=0; x<lX; x++) *(ptrd++) = (T)(*(ptrs++));
    05397               else for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
    05398               ptrd+=offX; ptrs+=soffX;
    05399             }
    05400             ptrd+=offY; ptrs+=soffY;
    05401           }
    05402           ptrd+=offZ; ptrs+=soffZ;
    05403         }
    05404       return *this;
    05405     }
    05406
    05407 #if ( !defined(_MSC_VER) || _MSC_VER>1200 )
    05408     CImg& draw_image(const CImg<T>& sprite,const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) {
    05409       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image");
    05410       if (this==&sprite) return draw_image(CImg<T>(sprite),x0,y0,z0,v0,opacity);
    05411       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05412       const int
    05413         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05414         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05415         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05416         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05417       const T *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
    05418         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
    05419       const unsigned int
    05420         offX = width-lX, soffX = sprite.width-lX,
    05421         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05422         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ),
    05423         slX = lX*sizeof(T);
    05424       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05425       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05426       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05427         for (int v=0; v<lV; v++) {
    05428           for (int z=0; z<lZ; z++) {
    05429             if (opacity>=1) for (int y=0; y<lY; y++) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
    05430             else for (int y=0; y<lY; y++) {
    05431               for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
    05432               ptrd+=offX; ptrs+=soffX;
    05433             }
    05434             ptrd+=offY; ptrs+=soffY;
    05435           }
    05436           ptrd+=offZ; ptrs+=soffZ;
    05437         }
    05438       return *this;
    05439     }
    05440 #endif
    05441
    05443
    05456     template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite,const CImg<tm>& mask,
    05457                                                        const int x0=0,const int y0=0,const int z0=0,const int v0=0,
    05458                                                        const tm mask_valmax=1,const float opacity=1) {
    05459       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image"); cimg_test(mask,"CImg<T>::draw_image");
    05460       if ((void*)this==(void*)&sprite) return draw_image(CImg<T>(sprite),mask,x0,y0,z0,v0);
    05461       if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
    05462         throw CImgArgumentException("CImg<%s>::draw_image() : mask dimension is (%d,%d,%d,%d), while sprite is (%d,%d,%d,%d)",
    05463                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
    05464       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05465       const int
    05466         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05467         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05468         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05469         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05470       const int coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-
    05471         (bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
    05472         ssize = mask.dimx()*mask.dimy()*mask.dimz();
    05473       const ti *ptrs = sprite.ptr() + coff;
    05474       const tm *ptrm = mask.ptr() + coff;
    05475       const unsigned int
    05476         offX = width-lX, soffX = sprite.width-lX,
    05477         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05478         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
    05479       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05480       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05481         for (int v=0; v<lV; v++) {
    05482           ptrm = mask.data + (ptrm - mask.data)%ssize;
    05483           for (int z=0; z<lZ; z++) {
    05484             for (int y=0; y<lY; y++) {
    05485               for (int x=0; x<lX; x++) {
    05486                 const float mopacity = *(ptrm++)*opacity,
    05487                   nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f);
    05488                 *(ptrd++) = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax);
    05489               }
    05490               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
    05491             }
    05492             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
    05493           }
    05494           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
    05495         }
    05496       return *this;
    05497     }
    05498
    05500
    05513     CImg& draw_rectangle(const int x0,const int y0,const int z0,const int v0,
    05514                          const int x1,const int y1,const int z1,const int v1,
    05515                          const T& val,float opacity=1) {
    05516       cimg_test(*this,"CImg<T>::draw_rectangle");
    05517       const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1);
    05518       const int nx0=bx?x0:x1, nx1=bx?x1:x0, ny0=by?y0:y1, ny1=by?y1:y0, nz0=bz?z0:z1, nz1=bz?z1:z0, nv0=bv?v0:v1, nv1=bv?v1:v0;
    05519       const int
    05520         lX = (1+nx1-nx0) + (nx1>=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0),
    05521         lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0),
    05522         lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0),
    05523         lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0);
    05524       const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ);
    05525       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05526       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
    05527       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05528         for (int v=0; v<lV; v++) {
    05529           for (int z=0; z<lZ; z++) {
    05530             for (int y=0; y<lY; y++) {
    05531               if (opacity>=1) {
    05532                 if (sizeof(T)!=1) { for (int x=0; x<lX; x++) *(ptrd++) = val; ptrd+=offX; }
    05533                 else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
    05534               } else { for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ptrd++; } ptrd+=offX; }
    05535             }
    05536             ptrd+=offY;
    05537           }
    05538           ptrd+=offZ;
    05539         }
    05540       return *this;
    05541     }
    05542
    05544
    05555     CImg& draw_rectangle(const int x0,const int y0,const int z0,
    05556                          const int x1,const int y1,const int z1,
    05557                          const T *const color,const float opacity=1) {
    05558       if (!color) throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",pixel_type());
    05559       cimg_mapV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
    05560       return *this;
    05561     }
    05562
    05564
    05573     CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1,
    05574                          const T *const color,const float opacity=1) {
    05575       draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
    05576       return *this;
    05577     }
    05578
    05580
    05591     CImg& draw_triangle(const int x0,const int y0,
    05592                         const int x1,const int y1,
    05593                         const int x2,const int y2,
    05594                         const T *const color, const float opacity=1) {
    05595       cimg_test(*this,"CImg<T>::draw_triangle");
    05596       if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : specified color is (null).");
    05597       const T* col = color;
    05598       int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,whz=width*height*depth;
    05599       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
    05600       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
    05601       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
    05602       if (ny0>=dimy() || ny2<0) return *this;
    05603       const float
    05604         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
    05605         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
    05606         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1);
    05607       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05608       float xleft = (float)nx0, xright = xleft, pleft = (p1<p2)?p1:p2, pright = (p1<p2)?p2:p1;
    05609       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; }
    05610
    05611       const int ya = ny1>dimy()?height:ny1;
    05612       for (int y=ny0<0?0:ny0; y<ya; y++) {
    05613         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<width)?(int)xright:(width-1);
    05614         if (xmin<=xmax) {
    05615           const int offx = whz-xmax+xmin-1;
    05616           T *ptrd = ptr(xmin,y,0,0);
    05617           if (opacity>=1) cimg_mapV(*this,k) {
    05618             if (sizeof(T)!=1) { const T& cval=*(col++); for (int x=xmin; x<=xmax; x++) *(ptrd++)=cval; ptrd+=offx; }
    05619             else { std::memset(ptrd,(int)*(col++),xmax-xmin+1); ptrd+=whz; }
    05620           } else cimg_mapV(*this,k) {
    05621             const T& cval=*(col++);
    05622             for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(cval*nopacity + copacity*(*ptrd)); ptrd++; }
    05623             ptrd+=offx;
    05624           }
    05625           col-=dim;
    05626         }
    05627         xleft+=pleft; xright+=pright;
    05628       }
    05629
    05630       if (p1<p2) { xleft=(float)nx1;  pleft=p3;  if (ny1<0) xleft-=ny1*pleft; }
    05631       else       { xright=(float)nx1; pright=p3; if (ny1<0) xright-=ny1*pright; }
    05632
    05633       const int yb = ny2>=dimy()?height-1:ny2;
    05634       for (int yy=ny1<0?0:ny1; yy<=yb; yy++) {
    05635         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<width)?(int)xright:(width-1);
    05636         if (xmin<=xmax) {
    05637           const int offx=whz-xmax+xmin-1;
    05638           T *ptrd = ptr(xmin,yy,0,0);
    05639           if (opacity>=1) cimg_mapV(*this,k) {
    05640             if (sizeof(T)!=1) { const T& cval=*(col++); for (int x=xmin; x<=xmax; x++) *(ptrd++)=cval; ptrd+=offx; }
    05641             else { std::memset(ptrd,(int)*(col++),xmax-xmin+1); ptrd+=whz; }
    05642           } else cimg_mapV(*this,k) {
    05643             const T& cval=*(col++);
    05644             for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(cval*nopacity + copacity*(*ptrd)); ptrd++; }
    05645             ptrd+=offx;
    05646           }
    05647           col-=dim;
    05648         }
    05649         xleft+=pleft; xright+=pright;
    05650       }
    05651       return *this;
    05652     }
    05653
    05655
    05672     template<typename t> CImg& draw_triangle(const int x0,const int y0,
    05673                                              const int x1,const int y1,
    05674                                              const int x2,const int y2,
    05675                                              const CImg<t>& texture,
    05676                                              const int tx0,const int ty0,
    05677                                              const int tx1,const int ty1,
    05678                                              const int tx2,const int ty2,
    05679                                              const float opacity=1) {
    05680       cimg_test(*this,"CImg<T>::draw_triangle"); cimg_test(texture,"CImg<T>::draw_triangle");
    05681       int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2,whz=width*height*depth;
    05682       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    05683       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
    05684       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
    05685       if (ny0>=dimy() || ny2<0) return *this;
    05686       const float
    05687         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
    05688         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
    05689         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1),
    05690         tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0,
    05691         tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0,
    05692         tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0,
    05693         tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0,
    05694         tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0,
    05695         tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0;
    05696       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05697       float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,
    05698         xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft;
    05699       if (p1<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; }
    05700       else       { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; }
    05701       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft;
    05702         txright-=ny0*tpxright; tyright-=ny0*tpyright; }
    05703       const int ya = ny1<dimy()?ny1:height;
    05704       for (int y=(ny0<0?0:ny0); y<ya; y++) {
    05705         const int dx = (int)xright-(int)xleft;
    05706         const float
    05707           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    05708           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    05709           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    05710           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
    05711         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
    05712         if (xmin<=xmax) {
    05713           const int offx=whz-xmax+xmin-1;
    05714           T* ptrd = ptr(xmin,y,0,0);
    05715           if (opacity>=1) cimg_mapV(*this,k) {
    05716             float tx=txi, ty=tyi;
    05717             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
    05718             ptrd+=offx;
    05719           } else cimg_mapV(*this,k) {
    05720             float tx=txi, ty=tyi;
    05721             for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; }
    05722             ptrd+=offx;
    05723           }
    05724         }
    05725         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
    05726       }
    05727
    05728       if (p1<p2) {
    05729         xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3;
    05730         if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; }
    05731       } else {
    05732         xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3;
    05733         if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; }
    05734       }
    05735       const int yb = ny2>=dimy()?(height-1):ny2;
    05736       for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) {
    05737         const int dx = (int)xright-(int)xleft;
    05738         const float
    05739           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    05740           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    05741           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    05742           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
    05743         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
    05744         if (xmin<=xmax) {
    05745           const int offx=whz-xmax+xmin-1;
    05746           T* ptrd = ptr(xmin,yy,0,0);
    05747           if (opacity>=1) cimg_mapV(*this,k) {
    05748             float tx=txi, ty=tyi;
    05749             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
    05750             ptrd+=offx;
    05751           } else cimg_mapV(*this,k) {
    05752             float tx=txi, ty=tyi;
    05753             for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; }
    05754             ptrd+=offx;
    05755           }
    05756         }
    05757         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
    05758       }
    05759       return *this;
    05760     }
    05761
    05763     template<typename t1,typename t2>
    05764       CImg& draw_triangle(const int x0,const int y0,
    05765                           const int x1,const int y1,
    05766                           const int x2,const int y2,
    05767                           const CImg<t1>& texture,
    05768                           const int tx0,const int ty0,
    05769                           const int tx1,const int ty1,
    05770                           const int tx2,const int ty2,
    05771                           const CImg<t2>& displacement,
    05772                           const int mx0,const int my0,
    05773                           const int mx1,const int my1,
    05774                           const int mx2,const int my2,
    05775                           const float opacity=1) {
    05776       cimg_test(*this,"CImg<T>::draw_triangle"); cimg_test(texture,"CImg<T>::draw_triangle"); cimg_test(displacement,"CImg<T>::draw_triangle");
    05777       if (displacement.dim!=2 || displacement.depth!=1)
    05778         throw CImgArgumentException("CImg<%s>::draw_triangle() : Displacement map (%d,%d,%d,%d) should be (*,*,1,2)",
    05779                                     pixel_type(),displacement.width,displacement.height,
    05780                                     displacement.depth,displacement.dim);
    05781       int nx0=x0, ny0=y0, nx1=x1, ny1=y1, nx2=x2, ny2=y2,
    05782         ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1, ntx2=tx2, nty2=ty2,
    05783         nmx0=mx0, nmy0=my0, nmx1=mx1, nmy1=my1, nmx2=mx2, nmy2=my2, whz=width*height*depth;
    05784       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nmx0,nmx1,nmy0,nmy1);
    05785       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nmx0,nmx2,nmy0,nmy2);
    05786       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nmx1,nmx2,nmy1,nmy2);
    05787       if (ny0>=dimy() || ny2<0) return *this;
    05788       const float
    05789         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
    05790         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
    05791         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1),
    05792         tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0,
    05793         tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0,
    05794         tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0,
    05795         tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0,
    05796         tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0,
    05797         tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0,
    05798         mpx1 = (ny1-ny0)?(nmx1-nmx0)/(float)(ny1-ny0):0,
    05799         mpy1 = (ny1-ny0)?(nmy1-nmy0)/(float)(ny1-ny0):0,
    05800         mpx2 = (ny2-ny0)?(nmx2-nmx0)/(float)(ny2-ny0):0,
    05801         mpy2 = (ny2-ny0)?(nmy2-nmy0)/(float)(ny2-ny0):0,
    05802         mpx3 = (ny2-ny1)?(nmx2-nmx1)/(float)(ny2-ny1):0,
    05803         mpy3 = (ny2-ny1)?(nmy2-nmy1)/(float)(ny2-ny1):0;
    05804       float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,mpxleft,mpyleft,mpxright,mpyright,
    05805         txleft  = (float)ntx0,
    05806         tyleft  = (float)nty0,
    05807         mxleft  = (float)nmx0,
    05808         myleft  = (float)nmy0,
    05809         xleft   = (float)nx0,
    05810         txright = txleft,
    05811         tyright = tyleft,
    05812         mxright = mxleft,
    05813         myright = myleft,
    05814         xright  = xleft,
    05815         nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05816       if (p1<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2;
    05817         mpxleft=mpx1; mpyleft=mpy1; mpxright=mpx2; mpyright=mpy2; }
    05818       else       { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1;
    05819         mpxleft=mpx2; mpyleft=mpy2; mpxright=mpx1; mpyright=mpy1; }
    05820       if (ny0<0) {
    05821         xleft-=ny0*pleft; xright-=ny0*pright;
    05822         txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft; txright-=ny0*tpxright; tyright-=ny0*tpyright;
    05823         mxleft-=ny0*mpxleft; myleft-=ny0*mpyleft; mxright-=ny0*mpxright; myright-=ny0*mpyright;
    05824       }
    05825       const int ya = (ny1<dimy())?ny1:height;
    05826       for (int y=(ny0<0?0:ny0); y<ya; y++) {
    05827         const int dx = (int)xright-(int)xleft;
    05828         const float
    05829           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    05830           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    05831           mpx = dx?((int)mxright-(int)mxleft)/(float)dx:0,
    05832           mpy = dx?((int)myright-(int)myleft)/(float)dx:0,
    05833           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    05834           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)),
    05835           mxi = (float)((xleft>=0)?(int)mxleft:(int)(mxleft-(int)xleft*mpx)),
    05836           myi = (float)((xleft>=0)?(int)myleft:(int)(myleft-(int)xleft*mpy));
    05837         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<width)?(int)xright:(width-1);
    05838         if (xmin<=xmax) {
    05839           const int offx=whz-xmax+xmin-1;
    05840           T* ptrd = ptr(xmin,y,0,0);
    05841           if (opacity>=1) cimg_mapV(*this,k) {
    05842             float tx=txi, ty=tyi, mx=mxi, my=myi;
    05843             for (int x=xmin; x<=xmax; x++) {
    05844               *(ptrd++)= texture(
    05845                                  (unsigned int)(tx+displacement((unsigned int)mx,(unsigned int)my,0)),
    05846                                  (unsigned int)(ty+displacement((unsigned int)mx,(unsigned int)my,1)),
    05847                                  0,k);
    05848               tx+=tpx; ty+=tpy; mx+=mpx; my+=mpy;
    05849             }
    05850             ptrd+=offx;
    05851           } else cimg_mapV(*this,k) {
    05852             float tx=txi, ty=tyi, mx=mxi, my=myi;
    05853             for (int x=xmin; x<=xmax; x++) {
    05854               *ptrd = (T)(nopacity*texture(
    05855                                            (unsigned int)(tx+displacement((unsigned int)mx,(unsigned int)my,0)),
    05856                                            (unsigned int)(ty+displacement((unsigned int)mx,(unsigned int)my,1)),
    05857                                            0,k) + copacity*(*ptrd));
    05858               ptrd++; tx+=tpx; ty+=tpy; mx+=mpx; my+=mpy; }
    05859             ptrd+=offx;
    05860           }
    05861         }
    05862         xleft+=pleft; xright+=pright;
    05863         txleft+=tpxleft; tyleft+=tpyleft;       txright+=tpxright; tyright+=tpyright;
    05864         mxleft+=mpxleft; myleft+=mpyleft;       mxright+=mpxright; myright+=mpyright;
    05865       }
    05866
    05867       if (p1<p2) {
    05868         xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3;
    05869         mxleft=(float)nmx1; myleft=(float)nmy1; mpxleft=mpx3; mpyleft=mpy3;
    05870         if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; mxleft-=ny1*mpxleft; myleft-=ny1*mpyleft; }
    05871       }
    05872       else {
    05873         xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3;
    05874         mxright=(float)nmx1; myright=(float)nmy1; mpxright=mpx3; mpyright=mpy3;
    05875         if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; mxright-=ny1*mpxright; myright-=ny1*mpyright; }
    05876       }
    05877
    05878       const int yb = (ny2<dimy())?ny2:(height-1);
    05879       for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) {
    05880         const int dx = (int)xright-(int)xleft;
    05881         const float
    05882           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    05883           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    05884           mpx = dx?((int)mxright-(int)mxleft)/(float)dx:0,
    05885           mpy = dx?((int)myright-(int)myleft)/(float)dx:0,
    05886           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    05887           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)),
    05888           mxi = (float)((xleft>=0)?(int)mxleft:(int)(mxleft-(int)xleft*mpx)),
    05889           myi = (float)((xleft>=0)?(int)myleft:(int)(myleft-(int)xleft*mpy));
    05890         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<width)?(int)xright:(width-1);
    05891         if (xmin<=xmax) {
    05892           const int offx=whz-xmax+xmin-1;
    05893           T* ptrd = ptr(xmin,yy,0,0);
    05894           if (opacity>=1) cimg_mapV(*this,k) {
    05895             float tx=txi, ty=tyi, mx=mxi, my=myi;
    05896             for (int x=xmin; x<=xmax; x++) {
    05897               *(ptrd++)= texture(
    05898                                  (unsigned int)(tx+displacement((unsigned int)mx,(unsigned int)my,0)),
    05899                                  (unsigned int)(ty+displacement((unsigned int)mx,(unsigned int)my,1)),
    05900                                  0,k);
    05901               tx+=tpx; ty+=tpy; mx+=mpx; my+=mpy; }
    05902             ptrd+=offx;
    05903           } else cimg_mapV(*this,k) {
    05904             float tx=txi, ty=tyi, mx=mxi, my=myi;
    05905             for (int x=xmin; x<=xmax; x++) {
    05906               *ptrd = (T)(nopacity*texture(
    05907                                            (unsigned int)(tx+displacement((unsigned int)mx,(unsigned int)my,0)),
    05908                                            (unsigned int)(ty+displacement((unsigned int)mx,(unsigned int)my,1)),
    05909                                            0,k) + copacity*(*ptrd));
    05910               ptrd++; tx+=tpx; ty+=tpy; mx+=mpx; my+=mpy;
    05911             } ptrd+=offx;
    05912           }
    05913         }
    05914         xleft+=pleft; xright+=pright;
    05915         txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
    05916         mxleft+=mpxleft; myleft+=mpyleft; mxright+=mpxright; myright+=mpyright;
    05917       }
    05918       return *this;
    05919     }
    05920
    05922
    05932     CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv,
    05933                        const T *const color,const float opacity=1) {
    05934       cimg_test(*this,"CImg<T>::draw_ellipse");
    05935       if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : specified color is (null).",pixel_type());
    05936       const T* col = color;
    05937       const float
    05938         norm = (float)std::sqrt(ru*ru+rv*rv),
    05939         u = norm>0?ru/norm:1,
    05940         v = norm>0?rv/norm:0,
    05941         rmax = cimg::max(r1,r2),
    05942         l1 = (float)std::pow(rmax/(r1>0?r1:1e-6),2),
    05943         l2 = (float)std::pow(rmax/(r2>0?r2:1e-6),2),
    05944         a = l1*u*u + l2*v*v,
    05945         b = u*v*(l1-l2),
    05946         c = l1*v*v + l2*u*u,
    05947         nopacity = cimg::abs(opacity),
    05948         copacity = 1-cimg::max(opacity,0.0f);
    05949       const int
    05950         yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)),
    05951         ymin = (y0-yb<0)?0:(y0-yb),
    05952         ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb),
    05953         whz = width*height*depth;
    05954       for (int y=ymin; y<=ymax; y++) {
    05955         const float
    05956           Y = (float)(y-y0),
    05957           delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax);
    05958         if (delta>=0) {
    05959           int xmin = (int)(x0-(b*Y+std::sqrt(delta))/a), xmax = (int)(x0-(b*Y-std::sqrt(delta))/a);
    05960           if (xmin<0) xmin=0;
    05961           if (xmax>=dimx()) xmax=dimx()-1;
    05962           if (xmin<=xmax) {
    05963             const int offx = whz-xmax+xmin-1;
    05964             T *ptrd = ptr(xmin,y,0,0);
    05965             if (opacity>=1) {
    05966               if (sizeof(T)!=1) cimg_mapV(*this,k) {
    05967                 const T& cval=*(col++);
    05968                 for (int x=xmin; x<=xmax; x++) *(ptrd++)=cval;
    05969                 ptrd+=offx;
    05970               } else cimg_mapV(*this,k) {
    05971                 std::memset(ptrd,(int)*(col++),xmax-xmin+1);
    05972                 ptrd+=whz;
    05973               }
    05974             } else cimg_mapV(*this,k) {
    05975               const T& cval=*(col++);
    05976               for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(cval*nopacity+copacity*(*ptrd)); ptrd++; }
    05977               ptrd+=offx;
    05978             }
    05979             col-=dim;
    05980           }
    05981         }
    05982       }
    05983       return *this;
    05984     }
    05985
    05987
    05994     CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const float opacity=1) {
    05995       return draw_ellipse(x0,y0,r,r,1,0,color,opacity);
    05996     }
    05997
    05998     // Create an auto-cropped font (along the X axis) from a input font \p font.
    05999     static CImgl<T> get_cropfont(const CImgl<T>& font,const unsigned int padding=2) {
    06000       CImgl<T> res;
    06001       cimgl_map(font,l) {
    06002         int xmin=font[l].width, xmax = 0;
    06003         cimg_mapXY(font[l],x,y) if (font[l](x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
    06004         if (xmin>xmax) res.insert(font[l]);
    06005         else {
    06006           res.insert(CImg<T>(xmax-xmin+1+padding,font[l].height,1,font[l].dim,0));
    06007           cimg_mapYV(res[l],y,k) for (int x=xmin; x<=xmax; x++) res[l](x-xmin,y,0,k) = font[l](x,y,0,k);
    06008         }
    06009       }
    06010       return res;
    06011     }
    06012
    06014
    06017     static CImgl<T> get_font7x11(const bool fixed_size = false) {
    06018       CImgl<T> font(32,1,1,1,3);
    06019       font.insert(CImgl<T>(224,7,11,1,3)).insert(CImgl<T>(32,1,1,1,1)).insert(CImgl<T>(224,7,11,1,1));
    06020       for (unsigned int i=0, off=0, boff=(unsigned int)(1<<31); i<256; i++) for (unsigned int j=0; j<font[i].width*font[i].height; j++) {
    06021         font[256+i](j) = font[i](j,0,0) = font[i](j,0,1) = font[i](j,0,2) = (cimg::font7x11[off]&boff)?(T)1:(T)0;
    06022         if (!(boff>>=1)) { boff=(unsigned int)(1<<31); off++; }
    06023       }
    06024       if (!fixed_size) return get_cropfont(font,2);
    06025       return font;
    06026     }
    06027
    06029
    06040     template<typename t> CImg& draw_text(const char *const text,
    06041                                          const int x0,const int y0,
    06042                                          const T *const fgcolor,const T *const bgcolor,
    06043                                          const CImgl<t>& font,const float opacity=1) {
    06044       cimg_test(*this,"CImg<T>::draw_text");
    06045       int x=x0, y=y0;
    06046       CImg letter;
    06047       for (int i=0; i<cimg::strlen(text); i++) {
    06048         const unsigned char c = text[i];
    06049         switch (c) {
    06050         case '\n': y+=font[' '].height; x=x0; break;
    06051         case '\t': x+=4*font[' '].width; break;
    06052         default: if (c<font.size) {
    06053             letter = font[c];
    06054             const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c];
    06055             if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) if (mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=(T)(letter(p,0,0,k)*fgcolor[k]);
    06056             if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) if (!mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=bgcolor[k];
    06057             if (!bgcolor && font.size>=512) draw_image(letter,mask,x,y,0,0,(T)1,opacity); else draw_image(letter,x,y,0,0,opacity);
    06058             x+=letter.width;
    06059           }
    06060           break;
    06061         }
    06062       }
    06063       return *this;
    06064     }
    06065
    06066
    06068
    06078     CImg& draw_text(const char *const text,
    06079                     const int x0,const int y0,
    06080                     const T *const fgcolor=NULL,const T *const bgcolor=NULL,
    06081                     const float opacity=1) {
    06082       static bool first = true;
    06083       static CImgl<T> default_font;
    06084       if (first) { default_font = get_font7x11(); first = false; }
    06085       return draw_text(text,x0,y0,fgcolor,bgcolor,default_font,opacity);
    06086     }
    06087
    06089
    06099     CImg& draw_text(const int x0,const int y0,
    06100                     const T *const fgcolor,const T *const bgcolor,
    06101                     const float opacity,const char *format,...) {
    06102       char tmp[2048];
    06103       va_list ap;
    06104       va_start(ap,format);
    06105       std::vsprintf(tmp,format,ap);
    06106       va_end(ap);
    06107       return draw_text(tmp,x0,y0,fgcolor,bgcolor,opacity);
    06108     }
    06109     template<typename t> CImg& draw_text(const int x0,const int y0,
    06110                                          const T *const fgcolor,const T *const bgcolor,
    06111                                          const CImgl<t>& font, const float opacity, const char *format,...) {
    06112       char tmp[2048]; va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap);
    06113       return draw_text(tmp,x0,y0,fgcolor,bgcolor,font);
    06114     }
    06115
    06117
    06126     template<typename t>
    06127     CImg& draw_quiver(const CImg<t>& flow,const T *const color,const unsigned int sampling=25,const float factor=-20,
    06128                       const int quiver_type=0,const float opacity=1) {
    06129       cimg_test(*this,"CImg<T>::draw_quiver"); cimg_test(flow,"CImg<T>::draw_quiver");
    06130       if (!color)
    06131         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified color is (null)",pixel_type());
    06132       if (sampling<=0)
    06133         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
    06134       if (flow.dim!=2)
    06135         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%d,%d,%d,%d)",
    06136                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
    06137       float vmax,fact;
    06138       if (factor<=0) {
    06139         CImgStats st(flow.get_norm_pointwise(2),false);
    06140         vmax = (float)cimg::max(std::fabs(st.min),std::fabs(st.max));
    06141         fact = -factor;
    06142       } else { fact = factor; vmax = 1; }
    06143
    06144       for (unsigned int y=sampling/2; y<height; y+=sampling)
    06145         for (unsigned int x=sampling/2; x<width; x+=sampling) {
    06146           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
    06147           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
    06148           if (!quiver_type) {
    06149             const int xx = x+(int)u, yy = y+(int)v;
    06150             draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,~0L,opacity);
    06151           } else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color,~0L,opacity);
    06152         }
    06153       return *this;
    06154     }
    06155
    06157
    06166     template<typename t1,typename t2>
    06167       CImg& draw_quiver(const CImg<t1>& flow,const CImg<t2>& color,const unsigned int sampling=25,const float factor=-20,
    06168                         const int quiver_type=0,const float opacity=1) {
    06169       cimg_test(*this,"CImg<T>::draw_quiver"); cimg_test(flow,"CImg<T>::draw_quiver"); cimg_test(color,"CImg<T>::draw_quiver");
    06170       if (sampling<=0)
    06171         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
    06172       if (flow.dim!=2)
    06173         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%d,%d,%d,%d)",
    06174                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
    06175       if (color.width!=flow.width || color.height!=flow.height)
    06176         throw CImgArgumentException("CImg<%s>::draw_quiver() : input color data map=(%d,%d,%d,%d)\
    06177  and data flow=(%d,%d,%d,%d) must have same dimension.",
    06178                                     color.width,color.height,color.depth,color.data,
    06179                                     flow.width,flow.height,flow.depth,flow.data);
    06180       float vmax,fact;
    06181       if (factor<=0) {
    06182         CImgStats st(flow.get_norm_pointwise(2),false);
    06183         vmax = (float)cimg::max(std::fabs(st.min),std::fabs(st.max));
    06184         fact = -factor;
    06185       } else { fact = factor; vmax = 1; }
    06186
    06187       for (unsigned int y=sampling/2; y<height; y+=sampling)
    06188         for (unsigned int x=sampling/2; x<width; x+=sampling) {
    06189           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
    06190           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
    06191           if (!quiver_type) {
    06192             const int xx = x+(int)u, yy = y+(int)v;
    06193             draw_arrow(x,y,xx,yy,color.get_vector(X,Y).data,45,sampling/5,~0L,opacity);
    06194           } else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color(X,Y),~0L,opacity);
    06195         }
    06196       return *this;
    06197     }
    06198
    06200
    06214     template<typename t>
    06215     CImg& draw_graph(const CImg<t>& data,const T *const color,const unsigned int gtype=0,
    06216                      const double ymin=0,const double ymax=0,const float opacity=1) {
    06217       cimg_test(*this,"CImg<T>::draw_graph");
    06218       if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : specified color is (null)",pixel_type());
    06219       T *color1 = new T[dim], *color2 = new T[dim];
    06220       cimg_mapV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); }
    06221       CImgStats st;
    06222       if (ymin==ymax) st = CImgStats(data,false); else { st.min = ymin; st.max = ymax; }
    06223       if (st.min==st.max) { st.min--; st.max++; }
    06224       const float Y0 = (float)((height-1)*(1+st.min/(st.max-st.min)));
    06225       int pY=0;
    06226       cimg_mapoff(data,off) {
    06227         const int Y = (int)((height-1)*(1-(data[off]-st.min)/(st.max-st.min)));
    06228         switch (gtype) {
    06229         case 0: // plot with segments
    06230           if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity);
    06231           break;
    06232         case 1: { // plot with bars
    06233           const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1;
    06234           draw_rectangle(X,(int)Y0,nX,Y,color1,opacity);
    06235           draw_line(X,Y,X,(int)Y0,color2,~0L,opacity);
    06236           draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity);
    06237           draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity);
    06238           draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity);
    06239         } break;
    06240         }
    06241         pY=Y;
    06242       }
    06243       if (gtype==2) { // plot with cubic interpolation
    06244         const CImgROI<t> ndata(data.size(),1,1,1,data.ptr());
    06245         cimg_mapX(*this,x) {
    06246           const int Y = (int)(height-1-height*(ndata.cubic_pix1d((float)x*ndata.width/width)-st.min)/(st.max-st.min+1));
    06247           if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity);
    06248           pY=Y;
    06249         }
    06250       }
    06251       delete[] color1; delete[] color2;
    06252       return *this;
    06253     }
    06254
    06256
    06266     CImg& draw_axeX(const double x0,const double x1,const int y,const T *const color,
    06267                     const double precision=0,const float opacity=1) {
    06268       if (x0==x1) return *this;
    06269       if (x0<x1) draw_arrow(0,y,width-1,y,color,30,5,~0L,opacity);
    06270       else draw_arrow(width-1,y,0,y,color,30,5,~0L,opacity);
    06271       const int yt = (y+14)<dimy()?(y+3):(y-14);
    06272       double nprecision=precision;
    06273       if (precision<=0) {
    06274         const double nb_pow = std::floor(std::log10(std::fabs(x1-x0)))-1;
    06275         nprecision = std::pow(10.0,nb_pow);
    06276         while ((std::fabs(x1-x0)/nprecision)>(dimx()/40)) nprecision*=2;
    06277       }
    06278       const double xmin=x0<x1?x0:x1, xmax=x0<x1?x1:x0,
    06279         tx0 = cimg::mod(xmin,nprecision)==0?xmin:((xmin+nprecision)-cimg::mod(xmin+nprecision,nprecision)),
    06280         tx1 = cimg::mod(xmax,nprecision)==0?xmax:((xmax+nprecision)-cimg::mod(xmax+nprecision,nprecision));
    06281       char txt[32];
    06282       for (double x=tx0; x<=tx1; x+=nprecision) {
    06283         std::sprintf(txt,"%g",x);
    06284         const int xi=(int)((x-x0)*(width-1)/(x1-x0)), xt = xi-(int)std::strlen(txt)*3;
    06285         draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
    06286           draw_text(txt,xt<0?0:xt,yt,color,NULL,opacity);
    06287       }
    06288       return *this;
    06289     }
    06290
    06292
    06302     CImg& draw_axeY(const int x,const double y0,const double y1,const T *const color,
    06303                     const double precision=0,const float opacity=1) {
    06304       if (y0==y1) return *this;
    06305       if (y0<y1) draw_arrow(x,0,x,height-1,color,30,5,~0L,opacity);
    06306       else draw_arrow(x,height-1,x,0,color,30,5,~0L,opacity);
    06307       double nprecision=precision;
    06308       if (precision<=0) {
    06309         const double nb_pow = std::floor(std::log10(std::fabs(y1-y0)))-1;
    06310         nprecision = std::pow(10.0,nb_pow);
    06311         while ((std::fabs(y1-y0)/nprecision)>(dimy()/40)) nprecision*=2;
    06312       }
    06313       const double ymin=y0<y1?y0:y1, ymax=y0<y1?y1:y0,
    06314         ty0 = cimg::mod(ymin,nprecision)==0?ymin:((ymin+nprecision)-cimg::mod(ymin+nprecision,nprecision)),
    06315         ty1 = cimg::mod(ymax,nprecision)==0?ymax:((ymax+nprecision)-cimg::mod(ymax+nprecision,nprecision));
    06316       char txt[32];
    06317       for (double y=ty0; y<=ty1; y+=nprecision) {
    06318         std::sprintf(txt,"%g",y);
    06319         const int yi = (int)((y-y0)*(height-1)/(y1-y0)), xt = x-(int)std::strlen(txt)*7;
    06320         draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
    06321         if (xt>0) draw_text(txt,xt,yi-5,color,NULL,opacity);
    06322         else draw_text(txt,x+3,yi-5,color,NULL,opacity);
    06323       }
    06324       return *this;
    06325     }
    06326
    06328
    06340     CImg& draw_axeXY(const double x0,const double x1,const double y0,const double y1,const T *const color,
    06341                      const double precisionx=0,const double precisiony=0,const float opacity=1) {
    06342       if (x0*x1<=0) {
    06343         const int xz = (int)(-x0*(width-1)/(x1-x0));
    06344         if (xz>=0 && xz<dimx()) draw_axeY(xz,y0,y1,color,precisiony,opacity);
    06345       }
    06346       if (y0*y1<=0) {
    06347         const int yz = (int)(-y0*(height-1)/(y1-y0));
    06348         if (yz>=0 && yz<dimy()) draw_axeX(x0,x1,yz,color,precisionx,opacity);
    06349       }
    06350       return *this;
    06351     }
    06352
    06353     // Local class used by function CImg<>::draw_fill()
    06354     template<typename T1,typename T2> struct _draw_fill {
    06355       const T1 *const color;
    06356       const float sigma,opacity;
    06357       const CImg<T1> value;
    06358       CImg<T2> region;
    06359
    06360       _draw_fill(const CImg<T1>& img,const int x,const int y,const int z,
    06361                  const T *const pcolor,const float psigma,const float popacity):
    06362         color(pcolor),sigma(psigma),opacity(popacity),
    06363         value(img.get_vector(x,y,z)), region(CImg<T2>(img.width,img.height,img.depth).fill((T2)false)) {
    06364         cimg_test(img,"CImg<T>::draw_fill");
    06365         if (!color) throw CImgArgumentException("CImg<%s>::draw_fill() : specified color is (null)",img.pixel_type());
    06366       }
    06367
    06368            _draw_fill& operator=(const _draw_fill& d) {
    06369                         color = d.color;
    06370                         sigma = d.sigma;
    06371                         opacity = d.opacity;
    06372                         value = d.value;
    06373                         region = d.region;
    06374                 }
    06375
    06376       bool comp(const CImg<T1>& A,const CImg<T1>& B) const {
    06377         bool res=true;
    06378         const T *pA=A.data+A.size();
    06379         for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) );
    06380         return res;
    06381       }
    06382
    06383       void fill(CImg<T1>& img,const int x,const int y,const int z) {
    06384         if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return;
    06385         if (!region(x,y,z) && comp(value,img.get_vector(x,y,z))) {
    06386           const T *col=color;
    06387           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06388           int xmin,xmax;
    06389           if (opacity>=1) cimg_mapV(img,k) img(x,y,z,k)=*(col++);
    06390           else cimg_mapV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k));
    06391           col-=img.dim;
    06392           region(x,y,z) = (T2)true;
    06393           for (xmin=x-1; xmin>=0 && comp(value,img.get_vector(xmin,y,z)); xmin--) {
    06394             if (opacity>=1) cimg_mapV(img,k) img(xmin,y,z,k) = *(col++);
    06395             else cimg_mapV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k));
    06396             col-=img.dim;
    06397             region(xmin,y,z)=(T2)true;
    06398           }
    06399           for (xmax=x+1; xmax<img.dimx() && comp(value,img.get_vector(xmax,y,z)); xmax++) {
    06400             if (opacity>=1) cimg_mapV(img,k) img(xmax,y,z,k) = *(col++);
    06401             else cimg_mapV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k));
    06402             col-=img.dim;
    06403             region(xmax,y,z)=(T2)true;
    06404           }
    06405           xmin++; xmax--;
    06406           for (; xmin<=xmax; xmin++) {
    06407             fill(img,xmin,y-1,z);
    06408             fill(img,xmin,y+1,z);
    06409             fill(img,xmin,y,z-1);
    06410             fill(img,xmin,y,z+1);
    06411           }
    06412         }
    06413       }
    06414     };
    06415
    06417
    06426     template<typename t> CImg& draw_fill(const int x,const int y,const int z,
    06427                                          const T *const color,CImg<t>& region,const float sigma=0,
    06428                                          const float opacity=1) {
    06429       _draw_fill<T,t> F(*this,x,y,z,color,sigma,opacity);
    06430       F.fill(*this,x,y,z);
    06431       region = F.region;
    06432       return *this;
    06433     }
    06434
    06436
    06444     CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) {
    06445       CImg<bool> tmp;
    06446       return draw_fill(x,y,z,color,tmp,sigma,opacity);
    06447     }
    06448
    06450
    06457     CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) {
    06458       CImg<bool> tmp;
    06459       return draw_fill(x,y,0,color,tmp,sigma,opacity);
    06460     }
    06461
    06463
    06472     CImg& draw_plasma(const int x0,const int y0,const int x1,const int y1,
    06473                       const double alpha=1.0,const double beta=1.0,const float opacity=1) {
    06474       cimg_test(*this,"CImg<T>::draw_plasma");
    06475       int nx0=x0,nx1=x1,ny0=y0,ny1=y1;
    06476       if (nx1<nx0) cimg::swap(nx0,nx1);
    06477       if (ny1<ny0) cimg::swap(ny0,ny1);
    06478       if (nx0<0) nx0=0;
    06479       if (nx1>=dimx()) nx1=width-1;
    06480       if (ny0<0) ny0=0;
    06481       if (ny1>=dimy()) ny1=height-1;
    06482       const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0);
    06483       const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta;
    06484       cimg_mapV(*this,k) {
    06485         if (opacity>=1) {
    06486           (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k)));
    06487           (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k)));
    06488           (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k)));
    06489           (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k)));
    06490           (*this)(xc,yc,0,k)  = (T)(0.25*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
    06491                                           (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand());
    06492         } else {
    06493           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06494           (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))*nopacity + copacity*(*this)(xc,ny0,0,k));
    06495           (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(xc,ny1,0,k));
    06496           (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))*nopacity + copacity*(*this)(nx0,yc,0,k));
    06497           (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(nx1,yc,0,k));
    06498           (*this)(xc,yc,0,k)  = (T)(0.25*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
    06499                                            (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity
    06500                                     + copacity*(*this)(xc,yc,0,k));
    06501         }
    06502       }
    06503       if (xc!=nx0 || yc!=ny0) {
    06504         draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
    06505         draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
    06506         draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
    06507         draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
    06508       }
    06509       return *this;
    06510     }
    06511
    06513
    06518     CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) {
    06519       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
    06520     }
    06521
    06523     template<typename t> CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) {
    06524       cimg_test(*this,"CImg<T>::draw_gaussian");
    06525       if (sigma<=0) throw CImgArgumentException("CImg<%s>::draw_gaussian() : sigma must be strictly positive, given is %g",pixel_type(),sigma);
    06526       const double sigma2 = -2*sigma*sigma;
    06527       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06528       const T *col = color;
    06529       const unsigned int whz = width*height*depth;
    06530       cimg_mapX(*this,x) {
    06531         const float dx = (x-xc);
    06532         const double val = std::exp( dx*dx/sigma2 );
    06533         T *ptrd = ptr(x,0,0,0);
    06534         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06535         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06536         col-=dim;
    06537       }
    06538       return *this;
    06539     }
    06540
    06542     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const double sigma,
    06543                                              const CImg<t> tensor,const T *const color,const float opacity=1) {
    06544       cimg_test(*this,"CImg<T>::draw_gaussian"); cimg_test_square(tensor,"CImg<T>::draw_gaussian");
    06545       if (tensor.width!=2) throw CImgArgumentException("CImg<%s>::draw_gaussian() : gaussian tensor must be a 2x2 matrix, given is (%d,%d,%d,%d)",
    06546                                                        pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
    06547       if (sigma<=0) throw CImgArgumentException("CImg<%s>::draw_gaussian() : sigma must be strictly positive, given is %g",pixel_type(),sigma);
    06548       const CImg<t> invT = tensor.get_inverse();
    06549       const t a=invT(0,0), b=2*invT(1,0), c=invT(1,1);
    06550       const double sigma2 = -2*sigma*sigma;
    06551       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06552       const T *col = color;
    06553       const unsigned int whz = width*height*depth;
    06554       cimg_mapXY(*this,x,y) {
    06555         const float dx = (x-xc), dy = (y-yc);
    06556         const double val = std::exp( ( a*dx*dx + b*dx*dy + c*dy*dy )/sigma2 );
    06557         T *ptrd = ptr(x,y,0,0);
    06558         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06559         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06560         col-=dim;
    06561       }
    06562       return *this;
    06563     }
    06564
    06565     CImg& draw_gaussian(const float xc,const float yc,const double sigma,const T *const color,const float opacity=1) {
    06566       return draw_gaussian(xc,yc,sigma,CImg<float>::get_identity_matrix(2),color,opacity);
    06567     }
    06568
    06570     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const float zc,const double sigma,
    06571                                              const CImg<t> tensor,const T *const color,const float opacity=1) {
    06572       cimg_test(*this,"CImg<T>::draw_gaussian"); cimg_test_square(tensor,"CImg<T>::draw_gaussian");
    06573       if (tensor.width!=3) throw CImgArgumentException("CImg<%s>::draw_gaussian() : gaussian tensor must be a 3x3 matrix, given is (%d,%d,%d,%d)",
    06574                                                        pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
    06575       if (sigma<=0) throw CImgArgumentException("CImg<%s>::draw_gaussian() : sigma must be strictly positive, given is %g",pixel_type(),sigma);
    06576       const CImg<t> invT = tensor.get_inverse();
    06577       const t 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);
    06578       const double sigma2 = -2*sigma*sigma;
    06579       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06580       const T *col = color;
    06581       const unsigned int whz = width*height*depth;
    06582       cimg_mapXYZ(*this,x,y,z) {
    06583         const float dx = (x-xc), dy = (y-yc), dz = (z-zc);
    06584         const double val = std::exp( ( a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz )/sigma2 );
    06585         T *ptrd = ptr(x,y,z,0);
    06586         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06587         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06588         col-=dim;
    06589       }
    06590       return *this;
    06591     }
    06592
    06593     CImg& draw_gaussian(const float xc,const float yc,const float zc,const double sigma,const T *const color,const float opacity=1) {
    06594       return draw_gaussian(xc,yc,zc,sigma,CImg<float>::get_identity_matrix(3),color,opacity);
    06595     }
    06596
    06598     //---------------------------------------
    06599     //---------------------------------------
    06600     //
    06602
    06603     //---------------------------------------
    06604     //---------------------------------------
    06605
    06607     template<typename t> CImg get_correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) const {
    06608       cimg_test_scalar(mask,"CImg<T>::get_correlate");
    06609       CImg dest(*this,false);
    06610       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
    06611         // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1)
    06612         switch (mask.depth) {
    06613         case 3: {
    06614           CImg_3x3x3(I,T);
    06615           if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr3x3x3(I,mask);
    06616           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
    06617             const double norm = (double)cimg_squaresum3x3x3(I);
    06618             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0;
    06619           }
    06620         } break;
    06621         case 2: {
    06622           CImg_2x2x2(I,T);
    06623           if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr2x2x2(I,mask);
    06624           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
    06625             const double norm = (double)cimg_squaresum2x2x2(I);
    06626             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0;
    06627           }
    06628         } break;
    06629         default:
    06630         case 1:
    06631           switch (mask.width) {
    06632           case 5: {
    06633             CImg_5x5(I,T);
    06634             if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr5x5(I,mask);
    06635             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
    06636               const double norm = (double)cimg_squaresum5x5(I);
    06637               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0;
    06638             }
    06639           } break;
    06640           case 4: {
    06641             CImg_4x4(I,T);
    06642             if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr4x4(I,mask);
    06643             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
    06644               const double norm = (double)cimg_squaresum4x4(I);
    06645               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0;
    06646             }
    06647           } break;
    06648           case 3: {
    06649             CImg_3x3(I,T);
    06650             if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr3x3(I,mask);
    06651             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
    06652               const double norm = (double)cimg_squaresum3x3(I);
    06653               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0;
    06654             }
    06655           } break;
    06656           case 2: {
    06657             CImg_2x2(I,T);
    06658             if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_corr2x2(I,mask);
    06659             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
    06660               const double norm = (double)cimg_squaresum2x2(I);
    06661               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0;
    06662             }
    06663           } break;
    06664           case 1: dest = mask(0)*(*this); break;
    06665           }
    06666         }
    06667       } else {
    06668         // Generic version for other masks
    06669         const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
    06670         cimg_mapV(*this,v)
    06671           if (!weighted_correl) {       // Classical correlation
    06672             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06673               double val = 0;
    06674               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06675                 val+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06676               dest(x,y,z,v)=(T)val;
    06677             }
    06678             if (cond) cimg_mapYZV(*this,y,z,v)
    06679               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06680                 double val = 0;
    06681                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06682                   val+= neumann_pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06683                 dest(x,y,z,v)=(T)val;
    06684               }
    06685             else cimg_mapYZV(*this,y,z,v)
    06686               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06687                 double val = 0;
    06688                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
    06689                   val+= dirichlet_pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
    06690                 dest(x,y,z,v)=(T)val;
    06691               }
    06692           } else {      // Weighted correlation
    06693             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06694               double val = 0, norm = 0;
    06695               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06696                 const T cval = (*this)(x+xm,y+ym,z+zm,v);
    06697                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06698                 norm+= cval*cval;
    06699               }
    06700               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06701             }
    06702             if (cond) cimg_mapYZV(*this,y,z,v)
    06703               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06704                 double val = 0, norm = 0;
    06705                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06706                   const T cval = neumann_pix3d(x+xm,y+ym,z+zm,v);
    06707                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06708                   norm+=cval*cval;
    06709                 }
    06710                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06711               }
    06712             else cimg_mapYZV(*this,y,z,v)
    06713               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06714                 double val = 0, norm = 0;
    06715                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06716                   const T cval = dirichlet_pix3d(x+xm,y+ym,z+zm,v,0);
    06717                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06718                   norm+= cval*cval;
    06719                 }
    06720                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06721               }
    06722           }
    06723       }
    06724       return dest;
    06725     }
    06727     template<typename t> CImg& correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) {
    06728       return get_correlate(mask,cond,weighted_correl).swap(*this);
    06729     }
    06730
    06732     template<typename t> CImg get_convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) const {
    06733       cimg_test_scalar(mask,"CImg<T>::get_convolve");
    06734       CImg dest(*this,false);
    06735       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version
    06736         switch (mask.depth) {
    06737         case 3: {
    06738           CImg_3x3x3(I,T);
    06739           if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv3x3x3(I,mask);
    06740           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
    06741             const double norm = (double)cimg_squaresum3x3x3(I);
    06742             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):(T)0;
    06743           }
    06744         } break;
    06745         case 2: {
    06746           CImg_2x2x2(I,T);
    06747           if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv2x2x2(I,mask);
    06748           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
    06749             const double norm = (double)cimg_squaresum2x2x2(I);
    06750             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):(T)0;
    06751           }
    06752         } break;
    06753         default:
    06754         case 1:
    06755           switch (mask.width) {
    06756           case 5: {
    06757             CImg_5x5(I,T);
    06758             if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv5x5(I,mask);
    06759             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
    06760               const double norm = (double)cimg_squaresum5x5(I);
    06761               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv5x5(I,mask)/std::sqrt(norm)):(T)0;
    06762             }
    06763           } break;
    06764           case 4: {
    06765             CImg_4x4(I,T);
    06766             if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv4x4(I,mask);
    06767             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
    06768               const double norm = (double)cimg_squaresum4x4(I);
    06769               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv4x4(I,mask)/std::sqrt(norm)):(T)0;
    06770             }
    06771           } break;
    06772           case 3: {
    06773             CImg_3x3(I,T);
    06774             if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv3x3(I,mask);
    06775             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
    06776               const double norm = (double)cimg_squaresum3x3(I);
    06777               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3(I,mask)/std::sqrt(norm)):(T)0;
    06778             }
    06779           } break;
    06780           case 2: {
    06781             CImg_2x2(I,T);
    06782             if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv2x2(I,mask);
    06783             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
    06784               const double norm = (double)cimg_squaresum2x2(I);
    06785               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2(I,mask)/std::sqrt(norm)):(T)0;
    06786             }
    06787           } break;
    06788           case 1: dest = mask(0)*(*this); break;
    06789           }
    06790         }
    06791       } else { // generic version
    06792
    06793         const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
    06794         cimg_mapV(*this,v)
    06795           if (!weighted_convol) {       // Classical convolution
    06796             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06797               double val = 0;
    06798               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06799                 val+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06800               dest(x,y,z,v)=(T)val;
    06801             }
    06802             if (cond) cimg_mapYZV(*this,y,z,v)
    06803               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06804                 double val = 0;
    06805                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06806                   val+= neumann_pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06807                 dest(x,y,z,v)=(T)val;
    06808               }
    06809             else cimg_mapYZV(*this,y,z,v)
    06810               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06811                 double val = 0;
    06812                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
    06813                   val+= dirichlet_pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
    06814                 dest(x,y,z,v)=(T)val;
    06815               }
    06816           } else {      // Weighted convolution
    06817             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06818               double val = 0, norm = 0;
    06819               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06820                 const T cval = (*this)(x-xm,y-ym,z-zm,v);
    06821                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06822                 norm+= cval*cval;
    06823               }
    06824               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    06825             }
    06826             if (cond) cimg_mapYZV(*this,y,z,v)
    06827               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06828                 double val = 0, norm = 0;
    06829                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06830                   const T cval = neumann_pix3d(x-xm,y-ym,z-zm,v);
    06831                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06832                   norm+=cval*cval;
    06833                 }
    06834                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    06835               }
    06836             else cimg_mapYZV(*this,y,z,v)
    06837               for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
    06838                 double val = 0, norm = 0;
    06839                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++) {
    06840                   const T cval = dirichlet_pix3d(x-xm,y-ym,z-zm,v,0);
    06841                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06842                   norm+= cval*cval;
    06843                 }
    06844                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    06845               }
    06846           }
    06847       }
    06848       return dest;
    06849     }
    06850
    06852     template<typename t> CImg& convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) {
    06853       return get_convolve(mask,cond,weighted_convol).swap(*this);
    06854     }
    06855
    06857     CImg& noise(const double psigma=-20,const unsigned int ntype=0) {
    06858       cimg_test(*this,"CImg<T>::noise");
    06859       double sigma = psigma;
    06860       static bool first_time = true;
    06861       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
    06862       CImgStats st;
    06863       if (sigma==0) return *this;
    06864       if (sigma<0 || ntype==2) st = CImgStats(*this,false);
    06865       if (sigma<0) sigma = -sigma*(st.max-st.min)/100.0;
    06866       switch (ntype) {
    06867       case 0: { cimg_map(*this,ptr,T) *ptr=(T)(*ptr+sigma*cimg::grand()); } break;    // Gaussian noise
    06868       case 1: { cimg_map(*this,ptr,T) *ptr=(T)(*ptr+sigma*cimg::crand()); } break;    // Uniform noise
    06869       case 2: {                                                                       // Salt & Pepper
    06870         if (st.max==st.min) { st.min=0; st.max=255; }
    06871         cimg_map(*this,ptr,T) if (cimg::rand()*100<sigma) *ptr=(T)(cimg::rand()<0.5?st.max:st.min);
    06872       } break;
    06873       }
    06874       return *this;
    06875     }
    06877     CImg get_noise(const double sigma=-20,const unsigned int ntype=0) const { return CImg<T>(*this).noise(sigma,ntype); }
    06878
    06880     CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) {
    06881       cimg_test(*this,"CImg<T>::deriche");
    06882       if (sigma<0 || order<0 || order>2) throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order);
    06883       if (sigma<0.01f) return *this;
    06884       const float alpha=sigma>0?1.695f/sigma:0,ea=(float)std::exp(alpha),ema=(float)std::exp(-alpha),em2a=ema*ema,b1=2*ema,b2=-em2a;
    06885       float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0;
    06886       double *Y,Y0,Y1,Y2;
    06887       int i,offset,nb;
    06888       T *ima,I1,I2;
    06889       switch(order) {
    06890       case 1:                 // first derivative
    06891         ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0;  a2 = ek*ema; a3 = -ek*ema; parity =-1;\
    06892         if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } \
    06893         else g0 = sumg0 = sumg1 = 0;
    06894         break;
    06895       case 2:               // second derivative
    06896         ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
    06897         ek = -(em2a-1)/(2*alpha*ema); a1 = ekn;  a2 = -ekn*(1+ek*alpha)*ema; a3 = ekn*(1-ek*alpha)*ema; a4 = -ekn*em2a; parity =1;
    06898         if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; }
    06899         else g0=sumg0=sumg1=0;
    06900         break;
    06901       default:              // smoothing
    06902         ek = (1-ema)*(1-ema) / (1+2*alpha*ema - em2a); a1 = ek;  a2 = ek*ema*(alpha-1); a3 = ek*ema*(alpha+1); a4 = -ek*em2a; parity = 1;
    06903         if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; }
    06904         else  g0=sumg0=sumg1=0;
    06905         break;
    06906       }
    06907       // filter init
    06908       Y = new double[cimg::max(width,height,depth)];
    06909       switch(cimg::uncase(axe)) {
    06910       case 'x': if (width>1)  { offset = 1;            nb = width;  cimg_mapYZV(*this,y,z,k) cimg_deriche_map(0,y,z,k,nb,offset,T); }   break;
    06911       case 'y': if (height>1) { offset = width;        nb = height; cimg_mapXZV(*this,x,z,k) cimg_deriche_map(x,0,z,k,nb,offset,T); }   break;
    06912       case 'z': if (depth>1)  { offset = width*height; nb = depth;  cimg_mapXYV(*this,x,y,k) cimg_deriche_map(x,y,0,k,nb,offset,T); }   break;
    06913       default : cimg::warn(true,"CImg<%s>::deriche() : Unknown axe '%c'",pixel_type(),axe); break;
    06914       }
    06915       delete[] Y;
    06916       return *this;
    06917     }
    06919     CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const {
    06920       return CImg<T>(*this).deriche(sigma,order,axe,cond);
    06921     }
    06923     CImg& blur(const float sigma=1,const unsigned int cond=1) {
    06924       cimg_test(*this,"CImg<T>::blur");
    06925       if (width>1)  deriche(sigma,0,'x',cond);
    06926       if (height>1) deriche(sigma,0,'y',cond);
    06927       if (depth>1)  deriche(sigma,0,'z',cond);
    06928       return *this;
    06929     }
    06931     CImg get_blur(const float sigma=1,const unsigned int cond=1) const { return CImg<T>(*this).blur(sigma,cond); }
    06932
    06934     CImg get_erode(const unsigned int n=1) {
    06935       CImg_3x3x3(I,T);
    06936       if (n==1) {
    06937         CImg dest(*this);
    06938         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I)
    06939           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) dest(x,y,z,k) = 0;
    06940         return dest;
    06941       }
    06942       CImg img1(*this),img2(*this,false);
    06943       CImg *src = &img1, *dest = &img2, *tmp = NULL;
    06944       for (unsigned int iter=0; iter<n; iter++) {
    06945         *dest = *src;
    06946         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I)
    06947           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) (*dest)(x,y,z,k) = 0;
    06948         tmp = src;
    06949         src = dest;
    06950         dest = tmp;
    06951       }
    06952       return *src;
    06953     }
    06955     CImg& erode(const unsigned int n=1) { return get_erode(n).swap(*this); }
    06956
    06958     CImg get_dilate(const unsigned int n=1) {
    06959       CImgStats stats(*this);
    06960       const T tmax = stats.max!=0?(T)stats.max:(T)1;
    06961       CImg_3x3x3(I,T);
    06962       if (n==1) {
    06963         CImg dest(*this);
    06964         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I)
    06965           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) dest(x,y,z,k) = tmax;
    06966         return dest;
    06967       }
    06968       CImg img1(*this),img2(*this,false);
    06969       CImg *src = &img1, *dest = &img2, *tmp = NULL;
    06970       for (unsigned int iter=0; iter<n; iter++) {
    06971         *dest = *src;
    06972         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I)
    06973           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) (*dest)(x,y,z,k) = tmax;
    06974         tmp = src;
    06975         src = dest;
    06976         dest = tmp;
    06977       }
    06978       return *src;
    06979     }
    06981     CImg& dilate(const unsigned int n=1) { return get_dilate(n).swap(*this); }
    06982
    06984     //------------------------------------------
    06985     //------------------------------------------
    06986     //
    06988
    06989     //------------------------------------------
    06990     //------------------------------------------
    06991
    06993     template<typename t> CImg operator*(const CImg<t>& img) const {
    06994       cimg_test_matrix(*this,"CImg<T>::operator*");
    06995       cimg_test_matrix(img,"CImg<T>::operator*");
    06996       if (width!=img.height)
    06997         throw CImgArgumentException("CImg<%s>::operator*() : can't multiply a matrix *this = (%dx%d) by a matrix (%dx%d)",
    06998                                     pixel_type(),width,height,img.width,img.height);
    06999       CImg res(img.width,height);
    07000       double val;
    07001       cimg_mapXY(res,i,j) { val=0; cimg_mapX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = (T)val; }
    07002       return res;
    07003     }
    07005     template<typename t> CImg& operator*=(const CImg<t>& img) { return ((*this)*img).swap(*this); }
    07006
    07008     CImg get_vector(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07009       CImg dest(dim);
    07010       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
    07011       return dest;
    07012     }
    07013
    07015     CImg get_matrix(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07016       const int n = (int)std::sqrt((double)dim);
    07017       CImg dest(n,n);
    07018       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
    07019       return dest;
    07020     }
    07021
    07023     CImg get_tensor(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07024       CImg dest(dim==3?2:3,dim==3?2:3,1,1);
    07025       if (dim==3) {
    07026         dest[0] = (*this)(x,y,z,0);
    07027         dest[1] = dest[2] = (*this)(x,y,z,1);
    07028         dest[3] = (*this)(x,y,z,2);
    07029       }
    07030       else {
    07031         dest[0] = (*this)(x,y,z,0);
    07032         dest[1] = dest[3] = (*this)(x,y,z,1);
    07033         dest[2] = dest[6] = (*this)(x,y,z,2);
    07034         dest[4] = (*this)(x,y,z,3);
    07035         dest[5] = dest[7] = (*this)(x,y,z,4);
    07036         dest[8] = (*this)(x,y,z,5);
    07037       }
    07038       return dest;
    07039     }
    07041     CImg& set_vector(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07042       return draw_point(x,y,z,vec.data,1);
    07043     }
    07045     CImg& set_matrix(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07046       return set_vector(mat,x,y,z);
    07047     }
    07049     CImg& set_tensor(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07050       if (ten.height==2) {
    07051         (*this)(x,y,z,0)=ten[0];
    07052         (*this)(x,y,z,1)=ten[1];
    07053         (*this)(x,y,z,2)=ten[3];
    07054       }
    07055       else {
    07056         (*this)(x,y,z,0)=ten[0];
    07057         (*this)(x,y,z,1)=ten[1];
    07058         (*this)(x,y,z,2)=ten[2];
    07059         (*this)(x,y,z,3)=ten[4];
    07060         (*this)(x,y,z,4)=ten[5];
    07061         (*this)(x,y,z,5)=ten[8];
    07062       }
    07063       return *this;
    07064     }
    07066     CImg& identity_matrix() {
    07067       cimg_test_square(*this,"CImg<T>::identity_matrix");
    07068       fill(0);
    07069       cimg_mapX(*this,x) (*this)(x,x) = (T)1;
    07070       return *this;
    07071     }
    07073     static CImg get_identity_matrix(const unsigned int dim) {
    07074       return CImg<T>(dim,dim).identity_matrix();
    07075     }
    07076
    07078     CImg get_transpose() const {
    07079       cimg_test_matrix(*this,"CImg<T>::get_transpose");
    07080       CImg res(height,width);
    07081       cimg_mapXY(res,x,y) res(x,y) = (*this)(y,x);
    07082       return res;
    07083     }
    07085     CImg& transpose() { return get_transpose().swap(*this); }
    07086
    07088     CImg get_diagonal() const {
    07089       cimg_test(*this,"CImg<T>::get_diagonal");
    07090       CImg res(size(),size(),1,1,0);
    07091       cimg_mapoff(*this,off) res(off,off)=(*this)(off);
    07092       return res;
    07093     }
    07095     CImg& diagonal() { return get_diagonal().swap(*this); }
    07096
    07098     CImg& inverse() {
    07099       cimg_test_square(*this,"CImg<T>::inverse");
    07100       switch (width) {
    07101       case 2:
    07102         {
    07103           const double
    07104             a = data[0], c = data[1],
    07105             b = data[2], d = data[3],
    07106             dete = det();
    07107           if (dete) {
    07108             data[0] = (T)(d/dete);  data[1] = (T)(-c/dete);
    07109             data[2] = (T)(-b/dete), data[3] = (T)(a/dete);
    07110           } else {
    07111             cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
    07112             fill(0);
    07113           }
    07114         }
    07115         break;
    07116       case 3:
    07117         {
    07118           const double
    07119             a = data[0], d = data[1], g = data[2],
    07120             b = data[3], e = data[4], h = data[5],
    07121             c = data[6], f = data[7], i = data[8],
    07122             dete = det();
    07123           if (dete) {
    07124             data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
    07125             data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
    07126             data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
    07127           } else {
    07128             cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
    07129             fill(0);
    07130           }
    07131         }
    07132         break;
    07133       default:
    07134         {
    07135           int N = width, LWORK = 4*N, *IPIV = new int[N], INFO;
    07136           double *A = new double[N*N], *WORK = new double[LWORK];
    07137           for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) A[k*N+l] = (*this)(k,l);
    07138           dgetrf_(&N,&N,A,&N,IPIV,&INFO);
    07139           cimg::warn(INFO!=0,"CImg<%s>::inverse() : LAPACK Error code = %d, from dgetrf_()",pixel_type(),INFO);
    07140           if (!INFO) {
    07141             dgetri_(&N,A,&N,IPIV,WORK,&LWORK,&INFO);
    07142             cimg::warn(INFO!=0,"CImg<%s>::inverse() : LAPACK Error code = %d, from dgetri_()",pixel_type(),INFO);
    07143           }
    07144           if (!INFO) for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) (*this)(k,l) = (T)(A[k*N+l]);
    07145           else fill(0);
    07146           delete[] IPIV; delete[] A; delete[] WORK;
    07147         }
    07148       }
    07149       return *this;
    07150     }
    07152     CImg get_inverse() const { return CImg<T>(*this).inverse(); }
    07153
    07155     double trace() const {
    07156       cimg_test_square(*this,"CImg<T>::trace");
    07157       double res=0;
    07158       cimg_mapX(*this,k) res+=(*this)(k,k);
    07159       return res;
    07160     }
    07162     double dot(const CImg& img) const {
    07163       cimg_test(*this,"CImg<T>::dot"); cimg_test(img,"CImg<T>::dot");
    07164       const unsigned int nb = cimg::min(size(),img.size());
    07165       double res=0;
    07166       for (unsigned int off=0; off<nb; off++) res+=data[off]*img[off];
    07167       return res;
    07168     }
    07169
    07171     CImg& cross(const CImg& img) {
    07172       if (width!=1 || height<3 || img.width!=1 || img.height<3)
    07173         throw CImgInstanceException("CImg<%s>::cross() : cannot get cross product between two matrices (%d,%d) and (%d,%d)",
    07174                                     pixel_type(),width,height,img.width,img.height);
    07175       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
    07176       (*this)[0] = y*img[2]-z*img[1];
    07177       (*this)[1] = z*img[0]-x*img[2];
    07178       (*this)[2] = x*img[1]-y*img[0];
    07179       return *this;
    07180     }
    07182     CImg get_cross(const CImg& img) const { return CImg<T>(*this).cross(img); }
    07183
    07185     double det() const {
    07186       cimg_test_square(*this,"CImg<T>::det");
    07187       switch (width) {
    07188       case 1: return (*this)(0,0);
    07189       case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
    07190       case 3:
    07191         {
    07192           const double
    07193             a = data[0], d = data[1], g = data[2],
    07194             b = data[3], e = data[4], h = data[5],
    07195             c = data[6], f = data[7], i = data[8];
    07196           return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
    07197         }
    07198       }
    07199       return 0;
    07200     }
    07202     double norm(const int ntype=2) const {
    07203       cimg_test(*this,"CImg<T>::norm");
    07204       double res = 0;
    07205       switch (ntype) {
    07206       case -1: { cimg_mapoff(*this,off) if (std::fabs((double)data[off])>res) res = std::fabs((double)data[off]); return res; }
    07207       case 1 : { cimg_mapoff(*this,off) res+=std::fabs((double)data[off]); return res; }
    07208       default: { return std::sqrt(dot(*this)); }
    07209       }
    07210       return 0;
    07211     }
    07213     double sum() const {
    07214       cimg_test(*this,"CImg<T>::sum");
    07215       double res=0;
    07216       cimg_map(*this,ptr,T) res+=*ptr;
    07217       return res;
    07218     }
    07220     template<typename t> const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
    07221       cimg_test_square(*this,"CImg<T>::eigen");
    07222       if (val.size()<width)
    07223         throw CImgArgumentException("CImg<%s>::eigen() : Argument 'val' is not large enough to be filled with eigenvalues (size=%d, needed is %d)",
    07224                                     pixel_type(),val.size(),width);
    07225       if (vec.data && vec.size()<width*width)
    07226         throw CImgArgumentException("CImg<%s>::eigen() : Argument 'vec' is not large enough to be filled with eigenvectors (size=%d, needed is %d)",
    07227                                     pixel_type(),val.size(),width*width);
    07228       switch(width) {
    07229       case 1:
    07230         val[0]=(t)(*this)[0];
    07231         if (vec.data) vec[0]=(t)1;
    07232         break;
    07233       case 2:
    07234         {
    07235           const double
    07236             a = (*this)[0], b = (*this)[1],
    07237             c = (*this)[2], d = (*this)[3],
    07238             e = a+d;
    07239           double f = e*e-4*(a*d-b*c);
    07240           cimg::warn(f<0,"CImg<%s>::eigen() : Complex eigenvalues",pixel_type());
    07241           f = std::sqrt(f);
    07242           const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
    07243           val[0]=(t)l1; val[1]=(t)l2;
    07244           if (vec.data) {
    07245             double u,v,n;
    07246             if (std::fabs(b)>std::fabs(a-l1)) { u = 1; v = (l1-a)/b; }
    07247             else { if (a-l1!=0) { u = -b/(a-l1); v = 1; } else { u = 1; v = 0; } }
    07248             n = std::sqrt(u*u+v*v); u/=n; v/=n; vec[0] = (t)u; vec[1] = (t)v;
    07249             if (std::fabs(b)>std::fabs(a-l2)) { u = 1; v = (l2-a)/b; }
    07250             else { if (a-l2!=0) { u = -b/(a-l2); v = 1; } else { u = 0; v = 1; } }
    07251             n = std::sqrt(u*u+v*v); u/=n; v/=n; vec[2] = (t)u; vec[3] = (t)v;
    07252           }
    07253         }
    07254         break;
    07255       default:
    07256         throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices (given is %dx%d)",
    07257                                     pixel_type(),width,height);
    07258       }
    07259       return *this;
    07260     }
    07261
    07263     template<typename t> const CImg<T>& eigen(CImg<t>& val) const { CImg foo; return eigen(val,foo); }
    07264     CImgl<T> get_eigen(const bool compute_vectors=true) const {
    07265       cimg_test_square(*this,"CImg<T>::get_eigen");
    07266       CImgl<T> res(1,1,width);
    07267       if (compute_vectors) res.insert(CImg<T>(width,width));
    07268       eigen(res[0],res[1]);
    07269       return res;
    07270     }
    07271
    07273     template<typename t> const CImg<T>& symeigen(CImg<t>& val, CImg<t>& vec) const {
    07274       cimg_test_square(*this,"CImg<T>::symeigen");
    07275       if (val.size()<width)
    07276         throw CImgArgumentException("CImg<%s>::symeigen() : Argument 'val' is not large enough to be filled with eigenvalues (size=%d, needed is %d)",
    07277                                     pixel_type(),val.size(),width);
    07278       if (vec.data && vec.size()<width*width)
    07279         throw CImgArgumentException("CImg<%s>::symeigen() : Argument 'vec' is not large enough to be filled with eigenvectors (size=%d, needed is %d)",
    07280                                     pixel_type(),val.size(),width*width);
    07281       char JOBZ=vec.data?'V':'N', UPLO='U';
    07282       int N,INFO=0,LWORK;
    07283       double *WORK,*A,*VAL;
    07284       if (width<3) return eigen(val,vec);
    07285       N = width;
    07286       LWORK = 5*N;
    07287       A    = new double[N*N];
    07288       WORK = new double[LWORK];
    07289       VAL  = new double[width];
    07290       for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) A[k*N+l] = (*this)(k,l);
    07291       dsyev_(&JOBZ,&UPLO,&N,A,&N,VAL,WORK,&LWORK,&INFO);
    07292       cimg::warn(INFO!=0,"CImg<%s>::symeigen() : LAPACK Error code = %d, from ssyev_()",pixel_type(),INFO);
    07293       cimg_mapX(*this,x) val(x) = (t)VAL[x];
    07294       if (vec.data) cimg_mapXY(*this,x,y) vec(x,y) = (t)A[x+y*N];
    07295       delete[] A;
    07296       delete[] WORK;
    07297       delete[] VAL;
    07298       return *this;
    07299     }
    07301     template<typename t> const CImg<T>& symeigen(CImg<t>& val) const { CImg foo; return symeigen(val,foo); }
    07302     CImgl<T> get_symeigen(const bool compute_vectors=true) const {
    07303       cimg_test_square(*this,"CImg<T>::symeigen");
    07304       CImgl<T> res(1,1,width);
    07305       if (compute_vectors) res.insert(CImg<T>(width,width));
    07306       symeigen(res[0],res[1]);
    07307       return res;
    07308     }
    07309
    07311     //------------------------------------------
    07312     //------------------------------------------
    07313     //
    07315
    07316     //------------------------------------------
    07317     //------------------------------------------
    07318
    07320     CImgDisplay* new_display(const char *title="",const int normalize=1,const unsigned int attributes=3) const {
    07321       return new CImgDisplay(*this,title,normalize,attributes);
    07322     }
    07324     const CImg& display(CImgDisplay& disp,const unsigned int ymin=0,const unsigned int ymax=~0) const { disp.display(*this,ymin,ymax); return *this; }
    07325
    07327     const CImg& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
    07328
    07332     const CImg& display(const char* title,const int min_size=128,const int max_size=1024) const {
    07333       cimg_test(*this,"CImg<T>::display");
    07334       CImgDisplay *disp;
    07335       unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3];
    07336       print(title);
    07337       const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
    07338       if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
    07339       const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
    07340       if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
    07341       disp = CImg<unsigned char>(w,h,1,1,0).new_display(title,0,3);
    07342       XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2;
    07343       while (!disp->closed && !disp->key) feature_selection(NULL,1,*disp,XYZ);
    07344       delete disp;
    07345       return *this;
    07346     }
    07347
    07349     const CImg& display(const int min_size=128,const int max_size=1024) const { return display("",min_size,max_size); }
    07350
    07352     const CImg& feature_selection(int *const selection, const int feature_type,CImgDisplay &disp,
    07353                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
    07354       cimg_test(*this,"CImg<T>::feature_selection");
    07355       if (disp.events<3)
    07356         throw CImgArgumentException("CImg<%s>::feature_selection() : Input display must be able to catch keyboard and mouse events (events>=3). Given display has 'events = %s'.",pixel_type(),disp.events);
    07357       unsigned char fgcolor[3]={255,255,105},bgcolor[3]={0,0,0};
    07358       if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv()));
    07359       int carea=0,area=0,phase=0,
    07360         X0=(XYZ?XYZ[0]:width/2)%width, Y0=(XYZ?XYZ[1]:height/2)%height, Z0=(XYZ?XYZ[2]:depth/2)%depth,
    07361         X=-1,Y=-1,Z=-1,oX=-1,oY=-1,oZ=-1,X1=-1,Y1=-1,Z1=-1;
    07362       unsigned long hatch=feature_type?0xF0F0F0F0:~0L;
    07363       bool feature_selected = false, ytext = false;
    07364       CImg<unsigned char> visu, visu0;
    07365       char text[1024];
    07366
    07367       while (!disp.key && !disp.closed && !feature_selected) {
    07368
    07369         // Init visu0 if necessary
    07370         if (disp.resized || !visu0.data) {
    07371           if (disp.resized) disp.resize();
    07372           if (depth==1) visu0=get_normalize(0,(T)255); else visu0=get_3dplanes(X0,Y0,Z0).get_normalize(0,(T)255);
    07373           visu0.resize(disp.width,disp.height,1,cimg::min(3,dimv()));
    07374         }
    07375         visu = visu0;
    07376
    07377         // Handle motion and selection
    07378         const int mx = disp.mousex, my = disp.mousey, b = disp.button;
    07379         if (mx>=0 && my>=0) {
    07380           const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
    07381           if (mX<dimx() && mY<dimy())   { area=1; X=mX; Y=mY; Z=phase?Z1:Z0; }
    07382           if (mX<dimx() && mY>=dimy())  { area=2; X=mX; Y=phase?Y1:Y0; Z=mY-height; }
    07383           if (mX>=dimx() && mY<dimy())  { area=3; X=phase?X1:X0; Y=mY; Z=mX-width;  }
    07384           if (mX>=dimx() && mY>=dimy()) { X=X0; Y=Y0; Z=Z0; }
    07385           if ((!(phase%2) && (b&1)) || (phase%2 && !(b&1))) {
    07386             if (!carea) carea=area;
    07387             if (!(phase++)) { X0=X; Y0=Y; Z0=Z; }
    07388           }
    07389           if (b&2) { if (!phase) { X0=X; Y0=Y; Z0=Z; } else { X1=Y1=Z1=-1; phase=carea=0; }}
    07390           if ((b&2 || phase) && depth>1)
    07391             visu0 = get_3dplanes(X,Y,Z).normalize(0,(T)255).resize(disp.width,disp.height,1,cimg::min(3,dimv()));
    07392           if (phase) {
    07393             if (!feature_type) feature_selected = phase?true:false;
    07394             else {
    07395               if (depth>1) feature_selected = (phase==3)?true:false;
    07396               else feature_selected = (phase==2)?true:false;
    07397             }
    07398             if (!feature_selected) {
    07399               if (phase<2) { X1=X; Y1=Y; Z1=Z; }
    07400               else switch(carea) {
    07401               case 1: Z1=Z; break;
    07402               case 2: Y1=Y; break;
    07403               case 3: X1=X; break;
    07404               }
    07405             }
    07406           }
    07407           if (!phase || !feature_type) {
    07408             if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y);
    07409             cimg_mapV(*this,k) std::sprintf(text+cimg::strlen(text),"%g ",(double)(*this)(X,Y,Z,k));
    07410             std::sprintf(text+cimg::strlen(text),"}");
    07411             if (!feature_type) { X1=X0; Y1=Y0; Z1=Z0; }
    07412           } else
    07413             switch (feature_type) {
    07414             case 1:
    07415               {
    07416                 const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
    07417                 if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm);
    07418                 else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm);
    07419               }
    07420               break;
    07421             case 2:
    07422               if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)",
    07423                                         X0<X1?X0:X1,Y0<Y1?Y0:Y1,Z0<Z1?Z0:Z1,
    07424                                         X0<X1?X1:X0,Y0<Y1?Y1:Y0,Z0<Z1?Z1:Z0,
    07425                                         1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
    07426               else  std::sprintf(text,"Box (%d,%d)-(%d,%d), Size=(%d,%d)",
    07427                                  X0<X1?X0:X1,Y0<Y1?Y0:Y1,X0<X1?X1:X0,Y0<Y1?Y1:Y0,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
    07428               break;
    07429             }
    07430           if (my<12) ytext=true;
    07431           if (my>=visu.dimy()-11) ytext=false;
    07432           visu.draw_text(text,0,ytext?visu.dimy()-11:0,fgcolor,bgcolor,0.7f);
    07433         } else { X=Y=Z=-1; if (phase) disp.button=phase%2; }
    07434
    07435         // Draw image + selection on display window
    07436         if (X>=0 && Y>=0 && Z>=0) {
    07437           hatch=cimg::ror(hatch);
    07438           if (feature_type==1 && phase) {
    07439             const int d=(depth>1)?depth:0,
    07440               x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)),
    07441               x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d));
    07442             visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch);
    07443             if (d) {
    07444               const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)),
    07445                 zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d));
    07446               visu.draw_arrow(zx0,y0,zx1,y1,fgcolor,30.0f,5.0f,hatch).draw_arrow(x0,zy0,x1,zy1,fgcolor,30.0f,5.0f,hatch);
    07447             }
    07448           } else {
    07449             const bool cond=(phase&&feature_type);
    07450             const int d=(depth>1)?depth:0,
    07451               nX0=cond?X0:X, nY0=cond?Y0:Y, nZ0=cond?Z0:Z,
    07452               nX1=cond?X1:X, nY1=cond?Y1:Y, nZ1=cond?Z1:Z,
    07453               x0=(nX0<nX1?nX0:nX1)*disp.width/(width+d),
    07454               y0=(nY0<nY1?nY0:nY1)*disp.height/(height+d),
    07455               x1=((nX0<nX1?nX1:nX0)+1)*disp.width/(width+d)-1,
    07456               y1=((nY0<nY1?nY1:nY0)+1)*disp.height/(height+d)-1;
    07457             const unsigned long nhatch=phase?hatch:~0L;
    07458             visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,nhatch).
    07459               draw_line(x1,y0,x1,y1,fgcolor,nhatch).draw_line(x1,y1,x0,y1,fgcolor,nhatch).draw_line(x0,y1,x0,y0,fgcolor,nhatch);
    07460             if (d) {
    07461               const int
    07462                 zx0=(int)((width+(nZ0<nZ1?nZ0:nZ1))*disp.width/(width+d)),
    07463                 zy0=(int)((height+(nZ0<nZ1?nZ0:nZ1))*disp.height/(height+d)),
    07464                 zx1=(int)((width+(nZ0<nZ1?nZ1:nZ0)+1)*disp.width/(width+d))-1,
    07465                 zy1=(int)((height+(nZ0<nZ1?nZ1:nZ0)+1)*disp.height/(height+d))-1;
    07466               visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,nhatch).
    07467                 draw_line(zx1,y0,zx1,y1,fgcolor,nhatch).draw_line(zx1,y1,zx0,y1,fgcolor,nhatch).draw_line(zx0,y1,zx0,y0,fgcolor,nhatch);
    07468               visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,nhatch).
    07469                 draw_line(x1,zy0,x1,zy1,fgcolor,nhatch).draw_line(x1,zy1,x0,zy1,fgcolor,nhatch).draw_line(x0,zy1,x0,zy0,fgcolor,nhatch);
    07470             }
    07471           }
    07472         }
    07473         visu.display(disp).wait(32);
    07474         if (!feature_selected && (!phase && oX==X && oY==Y && oZ==Z) || (X<0 || Y<0 || Z<0)) disp.wait();
    07475         oX=X; oY=Y; oZ=Z;
    07476       }
    07477
    07478       // Return result
    07479       if (XYZ) { XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; }
    07480       if (feature_selected) {
    07481         if (feature_type==2) {
    07482           if (X0>X1) cimg::swap(X0,X1);
    07483           if (Y0>Y1) cimg::swap(Y0,Y1);
    07484           if (Z0>Z1) cimg::swap(Z0,Z1);
    07485         }
    07486         if (selection) {
    07487           if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1;
    07488           switch(feature_type) {
    07489           case 1:
    07490           case 2:  selection[3] = X1; selection[4] = Y1; selection[5] = Z1;
    07491           default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0;
    07492           }
    07493         }
    07494       } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1;
    07495       disp.button=0;
    07496       return *this;
    07497     }
    07498
    07500     const CImg& feature_selection(int *const selection, const int feature_type,
    07501                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
    07502       unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0);
    07503       const unsigned int dmin = cimg::min(w,h), minsiz = 256;
    07504       if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
    07505       const unsigned int dmax = cimg::max(w,h), maxsiz = 1024;
    07506       if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
    07507       CImgDisplay disp(w,h,"",0,3);
    07508       return feature_selection(selection,feature_type,disp,XYZ,color);
    07509     }
    07510
    07511
    07513     //------------------------------------------
    07514     //------------------------------------------
    07515     //
    07517
    07518     //------------------------------------------
    07519     //------------------------------------------
    07520
    07522     static CImg load(const char *filename) {
    07523       const char *ext = cimg::filename_split(filename);
    07524       if (!filename) throw CImgArgumentException("CImg<%s>::load() : Can't load (null) filename",pixel_type());
    07525       if (!cimg::strcasecmp(ext,"inr")) return load_inr(filename);
    07526       if (!cimg::strcasecmp(ext,"asc")) return load_ascii(filename);
    07527       if (!cimg::strcasecmp(ext,"dlm")) return load_dlm(filename);
    07528       if (!cimg::strcasecmp(ext,"hdr")) return load_analyze(filename);
    07529       if (!cimg::strcasecmp(ext,"pan")) return load_pandore(filename);
    07530       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return load_raw(filename);
    07531       if (!cimg::strcasecmp(ext,"ppm") || !cimg::strcasecmp(ext,"pgm") || !cimg::strcasecmp(ext,"pnm")) return load_pnm(filename);
    07532       return load_convert(filename);
    07533     }
    07534
    07536     static CImg load_inr(const char *filename, float *voxsize = NULL) {
    07537       CImg<T> dest;
    07538       int fopt[8];
    07539       bool loaded = false;
    07540       std::FILE *file = cimg::fopen(filename,"rb");
    07541       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
    07542       cimg::inr_header_read(file,fopt,voxsize);
    07543       dest = CImg<T>(fopt[0],fopt[1],fopt[2],fopt[3]);
    07544       cimg_load_inr_case(0,0,8, unsigned char, T);
    07545       cimg_load_inr_case(0,1,8, char,  T);
    07546       cimg_load_inr_case(0,0,16,unsigned short,T);
    07547       cimg_load_inr_case(0,1,16,short, T);
    07548       cimg_load_inr_case(0,0,32,unsigned int,  T);
    07549       cimg_load_inr_case(0,1,32,int,  T);
    07550       cimg_load_inr_case(1,0,32,float, T);
    07551       cimg_load_inr_case(1,1,32,float, T);
    07552       cimg_load_inr_case(1,0,64,double,T);
    07553       cimg_load_inr_case(1,1,64,double,T);
    07554       if (!loaded) throw CImgIOException("CImg<%s>::load_inr() : file '%s', can't read images of the type specified in the file",
    07555                                          pixel_type(),filename);
    07556       cimg::fclose(file);
    07557       return dest;
    07558     }
    07559
    07561     static CImg load_pandore(const char *filename) {
    07562       typedef unsigned char uchar;
    07563       typedef unsigned short ushort;
    07564       typedef unsigned int uint;
    07565       typedef unsigned long ulong;
    07566       CImg<T> dest;
    07567       std::FILE *file = cimg::fopen(filename,"r");
    07568       char tmp[16];
    07569       cimg::fread(tmp,sizeof(char),12,file);
    07570       if (cimg::strncasecmp("PANDORE",tmp,7))
    07571         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', unknown PANDORE header.",pixel_type(),filename);
    07572       unsigned int id,dims[8];
    07573       long ptbuf[4];
    07574       cimg::fread(&id,sizeof(int),1,file);
    07575       bool endian = (id>32767);
    07576       if (endian) cimg::bswap(&id,1,sizeof(uint));
    07577       cimg::fread(tmp,sizeof(char),20,file);
    07578       switch (id) {
    07579         cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
    07580         cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
    07581         cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
    07582         cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
    07583         cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
    07584         cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
    07585         cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
    07586         cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
    07587         cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
    07588       case 11: { // Region 1D
    07589         cimg::fread(dims,sizeof(unsigned int),3,file);
    07590         if (endian) cimg::bswap(dims,3,sizeof(unsigned int));
    07591         dest = CImg<T>(dims[1],1,1,1);
    07592         if (dims[2]<256) {
    07593           unsigned char *buffer = new unsigned char[dest.size()];
    07594           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    07595           if (endian) cimg::bswap(buffer,sizeof(unsigned char),dest.size());
    07596           T *ptrd = dest.ptr();
    07597           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07598           buffer-=dest.size();
    07599           delete[] buffer;
    07600         } else {
    07601           if (dims[2]<65536) {
    07602             unsigned short *buffer = new unsigned short[dest.size()];
    07603             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    07604             if (endian) cimg::bswap(buffer,sizeof(unsigned short),dest.size());
    07605             T *ptrd = dest.ptr();
    07606             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07607             buffer-=dest.size();
    07608             delete[] buffer;
    07609           } else {
    07610             unsigned long *buffer = new unsigned long[dest.size()];
    07611             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    07612             if (endian) cimg::bswap(buffer,sizeof(unsigned long),dest.size());
    07613             T *ptrd = dest.ptr();
    07614             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07615             buffer-=dest.size();
    07616             delete[] buffer;
    07617           }
    07618         }
    07619       }
    07620         break;
    07621       case 12: { // Region 2D
    07622         cimg::fread(dims,sizeof(unsigned int),4,file);
    07623         if (endian) cimg::bswap(dims,4,sizeof(unsigned int));
    07624         dest = CImg<T>(dims[2],dims[1],1,1);
    07625         if (dims[3]<256) {
    07626           unsigned char *buffer = new unsigned char[dest.size()];
    07627           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    07628           if (endian) cimg::bswap(buffer,sizeof(unsigned char),dest.size());
    07629           T *ptrd = dest.ptr();
    07630           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07631           buffer-=dest.size();
    07632           delete[] buffer;
    07633         } else {
    07634           if (dims[3]<65536) {
    07635             unsigned short *buffer = new unsigned short[dest.size()];
    07636             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    07637             if (endian) cimg::bswap(buffer,sizeof(unsigned short),dest.size());
    07638             T *ptrd = dest.ptr();
    07639             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07640             buffer-=dest.size();
    07641             delete[] buffer;
    07642           } else {
    07643             unsigned long *buffer = new unsigned long[dest.size()];
    07644             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    07645             if (endian) cimg::bswap(buffer,sizeof(unsigned long),dest.size());
    07646             T *ptrd = dest.ptr();
    07647             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07648             buffer-=dest.size();
    07649             delete[] buffer;
    07650           }
    07651         }
    07652       }
    07653         break;
    07654       case 13: { // Region 3D
    07655         cimg::fread(dims,sizeof(unsigned int),5,file);
    07656         if (endian) cimg::bswap(dims,5,sizeof(unsigned int));
    07657         dest = CImg<T>(dims[3],dims[2],dims[1],1);
    07658         if (dims[4]<256) {
    07659           unsigned char *buffer = new unsigned char[dest.size()];
    07660           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    07661           if (endian) cimg::bswap(buffer,sizeof(unsigned char),dest.size());
    07662           T *ptrd = dest.ptr();
    07663           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07664           buffer-=dest.size();
    07665           delete[] buffer;
    07666         } else {
    07667           if (dims[4]<65536) {
    07668             unsigned short *buffer = new unsigned short[dest.size()];
    07669             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    07670             if (endian) cimg::bswap(buffer,sizeof(unsigned short),dest.size());
    07671             T *ptrd = dest.ptr();
    07672             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07673             buffer-=dest.size();
    07674             delete[] buffer;
    07675           } else {
    07676             unsigned long *buffer = new unsigned long[dest.size()];
    07677             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    07678             if (endian) cimg::bswap(buffer,sizeof(unsigned long),dest.size());
    07679             T *ptrd = dest.ptr();
    07680             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    07681             buffer-=dest.size();
    07682             delete[] buffer;
    07683           }
    07684         }
    07685       }
    07686         break;
    07687         cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
    07688         cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
    07689         cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
    07690         cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
    07691         cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
    07692         cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
    07693         cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
    07694         cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
    07695         cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
    07696         cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
    07697         cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
    07698         cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
    07699         cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
    07700         cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
    07701         cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
    07702         cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
    07703         cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
    07704         cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);
    07705       case 34: // Points 1D
    07706         cimg::fread(ptbuf,sizeof(long),1,file);
    07707         if (endian) cimg::bswap(ptbuf,sizeof(long),1);
    07708         dest = CImg<T>(1); dest[0]=(T)ptbuf[0];
    07709         break;
    07710       case 35: // Points 2D
    07711         cimg::fread(ptbuf,sizeof(long),2,file);
    07712         if (endian) cimg::bswap(ptbuf,sizeof(long),2);
    07713         dest = CImg<T>(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0];
    07714         break;
    07715       case 36: // Points 3D
    07716         cimg::fread(ptbuf,sizeof(long),3,file);
    07717         if (endian) cimg::bswap(ptbuf,sizeof(long),3);
    07718         dest = CImg<T>(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0];
    07719         break;
    07720       default:
    07721         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', can't read images with ID_type=%d",pixel_type(),filename,id);
    07722       }
    07723       return dest;
    07724     }
    07725
    07727     static CImg load_pnm(const char *filename) {
    07728       unsigned int ppm_type,width,height,colormax=255;
    07729       unsigned char *raw=NULL,*raw2=NULL;
    07730       char item[256];
    07731       T *rdata,*gdata,*bdata;
    07732       CImg dest;
    07733       std::FILE *file;
    07734       int rval,gval,bval;
    07735       file=cimg::fopen(filename,"rb");
    07736       while (fscanf(file," %1023[^\n]",item)==1 && item[0]=='#'); fgetc(file);
    07737       if(std::sscanf(item,"P%d",&ppm_type)!=1)
    07738         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',PPM header 'P?' not found",pixel_type(),filename);
    07739       while (fscanf(file," %1023[^\n]",item)==1 && item[0]=='#'); fgetc(file);
    07740       if (std::sscanf(item,"%d %d",&width,&height)!=2)
    07741         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',WIDTH and HEIGHT not defined",pixel_type(),filename);
    07742       while (fscanf(file," %1023[^\n]",item)==1 && item[0]=='#'); fgetc(file);
    07743       cimg::warn(std::sscanf(item,"%d",&colormax)!=1,"CImg<%s>::load_pnm() : file '%s',COLORMAX not defined",pixel_type(),filename);
    07744       cimg::warn(colormax!=255,"CImg<%s>::load_pnm() : file '%s', COLORMAX=%d mode is not supported",pixel_type(),filename,colormax);
    07745       switch (ppm_type) {
    07746       case 2:                 /* Grey Ascii */
    07747         {
    07748           dest = CImg<T>(width,height,1,1);
    07749           rdata= dest.ptr();
    07750           for (unsigned int xy=0; xy<width*height; xy++) { fscanf(file,"%d",&rval); *(rdata++)=(unsigned char)rval; }
    07751         }
    07752         break;
    07753       case 3:               /* Color Ascii */
    07754         {
    07755           dest = CImg<T>(width,height,1,3);
    07756           rdata=dest.ptr(0,0,0,0); gdata=dest.ptr(0,0,0,1); bdata=dest.ptr(0,0,0,2);
    07757           for (unsigned int xy=0; xy<width*height; xy++) { fscanf(file,"%d %d %d",&rval,&gval,&bval); *(rdata++)=(unsigned char)rval; *(gdata++)=(unsigned char)gval; *(bdata++)=(unsigned char)bval; }
    07758         }
    07759         break;
    07760       case 5:               /* Grey Binary */
    07761         {
    07762           raw2 = raw = new unsigned char[width*height];
    07763           cimg::fread(raw,sizeof(unsigned char),width*height,file);
    07764           dest = CImg<T>(width,height,1,1);
    07765           rdata = dest.ptr(); for (unsigned int xy=0; xy<dest.size(); xy++) *(rdata++)=(T)*(raw2++);
    07766           delete[] raw;
    07767         }
    07768         break;
    07769       case 6:               /* Color Binary */
    07770         {
    07771           raw2 = raw = new unsigned char[width*height*3];
    07772           cimg::fread(raw,sizeof(unsigned char),width*height*3,file);
    07773           dest = CImg<T>(width,height,1,3);
    07774           rdata=dest.ptr(0,0,0,0); gdata=dest.ptr(0,0,0,1); bdata=dest.ptr(0,0,0,2);
    07775           for (unsigned int xy=0; xy<width*height; xy++) { *(rdata++)=(T)*(raw2++); *(gdata++)=(T)*(raw2++); *(bdata++)=(T)*(raw2++); }
    07776           delete[] raw;
    07777         }
    07778         break;
    07779       default:
    07780         {
    07781           cimg::fclose(file);
    07782           throw CImgIOException("CImg<%s>::load_pnm() : file '%s', PPM type 'P%d' not supported",pixel_type(),filename,ppm_type);
    07783         }
    07784       }
    07785       cimg::fclose(file);
    07786       return dest;
    07787     }
    07788
    07790     static CImg load_ascii(const char *filename) {
    07791       int err=1,xy,w,h,z,k;
    07792       CImg dest;
    07793       std::FILE *file;
    07794       double v;
    07795       file=cimg::fopen(filename,"r");
    07796       fscanf(file,"%d %d %d %d\n",&w,&h,&z,&k);
    07797       dest=CImg<T>(w,h,z,k);
    07798       for (xy=0; xy<w*h*z*k && err==1; xy++) { err=fscanf(file,"%lf ",&v); dest.data[xy]=(T)v; }
    07799       cimg::warn(xy<w*h*z*k,"CImg<%s>::load_ascii() : file '%s', %d values read, instead of %d",pixel_type(),filename,xy,w*h*z*k);
    07800       cimg::fclose(file);
    07801       return dest;
    07802     }
    07803
    07805     static CImg load_dlm(const char *filename) {
    07806       std::FILE *file = cimg::fopen(filename,"r");
    07807       unsigned int cdimx,dimx=0,dimy=0;
    07808       double tmpf;
    07809       char c;
    07810       for (int err=0; err!=EOF; ) {
    07811         cdimx=0;
    07812         do { if ((err=fscanf(file,"%lg%c",&tmpf,&c))>0) cdimx++; }
    07813         while (err==2 && c!='\n');
    07814         if (cdimx) {
    07815           if (!dimx) dimx=cdimx;
    07816           if (cdimx!=dimx) throw CImgIOException("CImg<%s>::load_dlm() : File '%s', Line %d contains %d elements, instead of %d",
    07817                                                  pixel_type(),filename,dimy+1,cdimx,dimx);
    07818           dimy++;
    07819         } else err=EOF;
    07820       }
    07821       rewind(file);
    07822       CImg<T> dest(dimx,dimy);
    07823       T *ptr_data = dest.data;
    07824       cimg_mapoff(dest,off) if (fscanf(file,"%lg",&tmpf)) *(ptr_data++) = (T)tmpf;  else { fgetc(file); off--; }
    07825
    07826       cimg::fclose(file);
    07827       return dest;
    07828     }
    07829
    07831     static CImg load_analyze(const char *filename, float *voxsize = NULL) {
    07832       CImg dest;
    07833       float scalefactor;
    07834       char tmp[1024];
    07835       const char *ext;
    07836       int header_size,endian=0;
    07837       short dimx=1,dimy,dimz,dimv,*dim,bitpix,datatype;
    07838       unsigned char *header;
    07839       std::FILE *file_header=NULL,*file=NULL;
    07840       ext = cimg::filename_split(filename);
    07841       if (!cimg::strncasecmp(ext,"hdr",3)) {
    07842         file_header = cimg::fopen(filename,"rb");
    07843         std::strcpy(tmp,filename);
    07844         std::sprintf(tmp+cimg::strlen(tmp)-3,"img");
    07845         file = cimg::fopen(tmp,"rb");
    07846       }
    07847       else {
    07848         if (!cimg::strncasecmp(ext,"img",3)) {
    07849           file = cimg::fopen(filename,"rb");
    07850           std::strcpy(tmp,filename);
    07851           std::sprintf(tmp+cimg::strlen(tmp)-3,"hdr");
    07852           file_header = cimg::fopen(tmp,"rb");
    07853         } else throw CImgIOException("CImg<%s>::load_analyze() : Cannot load filename '%s' as an analyze format",pixel_type(),filename);
    07854       }
    07855       cimg::fread(&header_size,sizeof(int),1,file_header);
    07856       if ((unsigned int)header_size>=4096) { endian = 1; cimg::bswap(&header_size,1,sizeof(int)); }
    07857       header = new unsigned char[header_size];
    07858       cimg::fread(header+sizeof(int),1,header_size-sizeof(int),file_header);
    07859       cimg::fclose(file_header);
    07860       dim = (short*)(header+40);
    07861       if (endian) { cimg::bswap(dim,5,sizeof(short)); }
    07862       if (dim[0]<=0) throw CImgIOException("CImg<%s>::load_analyze() : Specified image dimension is %d\n",pixel_type(),dim[0]);
    07863       cimg::warn(dim[0]>4,"CImg<%s>::load_analyze() : Image dimension is %d, reading only 4 first dimensions",pixel_type(),dim[0]);
    07864       if (dim[0]>=1) dimx = dim[1];
    07865       if (dim[0]>=1) dimy = dim[2]; else dimy = 1;
    07866       if (dim[0]>=2) dimz = dim[3]; else dimz = 1;
    07867       if (dim[0]>=3) dimv = dim[4]; else dimv = 1;
    07868       if (endian) {
    07869         cimg::bswap(header+112,1,sizeof(float));
    07870         cimg::bswap(header+70,1,sizeof(short));
    07871         cimg::bswap(header+72,1,sizeof(short));
    07872         cimg::bswap(header+76,4,sizeof(float));
    07873       }
    07874       scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
    07875       datatype = *(short*)(header+70); bitpix = *(short*)(header+72);
    07876       if (voxsize) { float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
    07877       delete[] header;
    07878       dest = CImg<T>(dimx,dimy,dimz,dimv);
    07879       switch (datatype) {
    07880       case 2:
    07881         {
    07882           unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
    07883           cimg::fread(buffer,sizeof(unsigned char),dimx*dimy*dimz*dimv,file);
    07884           cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    07885           delete[] buffer; break;
    07886         }
    07887       case 4:
    07888         {
    07889           short *buffer = new short[dimx*dimy*dimz*dimv];
    07890           cimg::fread(buffer,sizeof(short),dimx*dimy*dimz*dimv,file);
    07891           if (endian) cimg::bswap(buffer,dimx*dimy*dimz*dimv,sizeof(short));
    07892           cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    07893           delete[] buffer; break;
    07894         }
    07895       case 8:
    07896         {
    07897           int *buffer = new int[dimx*dimy*dimz*dimv];
    07898           cimg::fread(buffer,sizeof(int),dimx*dimy*dimz*dimv,file);
    07899           if (endian) cimg::bswap(buffer,dimx*dimy*dimz*dimv,sizeof(int));
    07900           cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    07901           delete[] buffer; break;
    07902         }
    07903       case 16:
    07904         {
    07905           float *buffer = new float[dimx*dimy*dimz*dimv];
    07906           cimg::fread(buffer,sizeof(float),dimx*dimy*dimz*dimv,file);
    07907           if (endian) cimg::bswap(buffer,dimx*dimy*dimz*dimv,sizeof(float));
    07908           cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    07909           delete[] buffer; break;
    07910         }
    07911       case 64:
    07912         {
    07913           double *buffer = new double[dimx*dimy*dimz*dimv];
    07914           cimg::fread(buffer,sizeof(double),dimx*dimy*dimz*dimv,file);
    07915           if (endian) cimg::bswap(buffer,dimx*dimy*dimz*dimv,sizeof(double));
    07916           cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    07917           delete[] buffer; break;
    07918         }
    07919       default: throw CImgIOException("CImg<%s>::load_analyze() : Cannot read images width 'datatype = %d'",pixel_type(),datatype);
    07920       }
    07921       cimg::fclose(file);
    07922       return dest;
    07923     }
    07924
    07926     static CImg load_raw(const char *filename,const char axe='v',const char align='p') { return (CImgl<T>(filename))[0]; }
    07927
    07931     static CImg load_convert(const char *filename) {
    07932       srand((unsigned int)::time(NULL));
    07933       char command[512], filetmp[512];
    07934       std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),::rand()%10000);
    07935       std::sprintf(command,"\"%s\" \"%s\" %s",cimg::convert_path(),filename,filetmp);
    07936       cimg::system(command);
    07937       std::FILE *file = std::fopen(filetmp,"rb");
    07938       if (!file) {
    07939         std::fclose(cimg::fopen(filename,"r"));
    07940         throw CImgIOException("CImg<%s>::load_convert() : Failed to open image '%s' with 'convert'.\n\
    07941 Check that you have installed the ImageMagick package in a standart directory.",pixel_type(),filename);
    07942       } else cimg::fclose(file);
    07943       const CImg dest(filetmp);
    07944       std::remove(filetmp);
    07945       return dest;
    07946     }
    07947
    07951     const CImg& save(const char *filename,const int number=-1) const {
    07952       cimg_test(*this,"CImg<T>::save");
    07953       const char *ext = cimg::filename_split(filename);
    07954       char nfilename[1024];
    07955       if (number>=0) filename = cimg::file_number(filename,number,6,nfilename);
    07956       if (!cimg::strcasecmp(ext,"inr")) return save_inr(filename);
    07957       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(filename);
    07958       if (!cimg::strcasecmp(ext,"dlm")) return save_dlm(filename);
    07959       if (!cimg::strcasecmp(ext,"hdr")) return save_analyze(filename);
    07960       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(filename);
    07961       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return save_raw(filename);
    07962       if (!cimg::strcasecmp(ext,"pgm") || !cimg::strcasecmp(ext,"ppm") || !cimg::strcasecmp(ext,"pnm"))
    07963         return save_pnm(filename);
    07964       return save_convert(filename);
    07965     }
    07966
    07968     const CImg& save_ascii(const char *filename) const {
    07969       cimg_test(*this,"CImg<T>::save_ascii");
    07970       std::FILE *file = cimg::fopen(filename,"w");
    07971       std::fprintf(file,"%d %d %d %d\n",width,height,depth,dim);
    07972       for (unsigned int xy=0; xy<size(); xy++)  std::fprintf(file,"%g ",(double)data[xy]);
    07973       cimg::fclose(file);
    07974       return *this;
    07975     }
    07976
    07978     const CImg& save_dlm(const char *filename) const {
    07979       cimg_test(*this,"CImg<T>::save_dlm");
    07980       std::FILE *file;
    07981       unsigned int x;
    07982       file=cimg::fopen(filename,"w");
    07983       cimg_mapY(*this,y) {
    07984         for (x=0; x<width-1; x++) std::fprintf(file,"%g,",(double)(*this)(x,y));
    07985         std::fprintf(file,"%g\n",(double)(*this)(x,y));
    07986       }
    07987       cimg::fclose(file);
    07988       return *this;
    07989     }
    07990
    07992     const CImg& save_pnm(const char *filename) const {
    07993       cimg_test(*this,"CImg<T>::save_pnm");
    07994       const char *ext = cimg::filename_split(filename);
    07995       unsigned char *xptr,*xdata;
    07996       T *r,*g,*b;
    07997       std::FILE *file;
    07998       if (depth!=1)  return get_3dplanes(width/2,height/2,depth/2).save_pnm(filename);
    07999       switch(dim) {
    08000       case 1:
    08001         {
    08002           if (!cimg::strcasecmp(ext,"ppm")) { get_resize(width,height,1,3,2).save_pnm(filename); return *this; }
    08003           xptr = xdata = new unsigned char[size()];
    08004           r = data;
    08005           file = cimg::fopen(filename,"wb");
    08006           std::fprintf(file,"P5\n# CREATOR: CImg : Original size=%dx%dx%dx%d\n%d %d\n255\n",width,height,depth,dim,width,height);
    08007           for (unsigned int xy = 0; xy<size(); xy++) *(xptr++) = (unsigned char)(*(r++));
    08008           cimg::fwrite(xdata,sizeof(unsigned char),size(),file);
    08009           cimg::fclose(file);
    08010           delete[] xdata;
    08011         }
    08012         break;
    08013       case 2:
    08014         {
    08015           get_resize(width,height,1,3,0).save_pnm(filename);
    08016           return *this;
    08017         }
    08018       default:
    08019         {
    08020           if (!cimg::strcasecmp(ext,"pgm")) { get_norm_pointwise(2).normalize(0,255).save_pnm(filename); return *this; }
    08021           xptr = xdata = new unsigned char[size()];
    08022           r = data; g = ptr(0,0,0,1); b = ptr(0,0,0,2);
    08023           file = cimg::fopen(filename,"wb");
    08024           std::fprintf(file,"P6\n# CREATOR: CImg : Original size=%dx%dx%dx%d\n%d %d\n255\n",width,height,depth,dim,width,height);
    08025           for (unsigned int xy = 0; xy<size(); xy+=3) { *(xptr++) = (unsigned char)(*(r++)); *(xptr++) = (unsigned char)(*(g++)); *(xptr++) = (unsigned char)(*(b++)); }
    08026           cimg::fwrite(xdata,sizeof(unsigned char),size(),file);
    08027           cimg::fclose(file);
    08028           delete[] xdata;
    08029         }
    08030         break;
    08031       }
    08032       return *this;
    08033     }
    08034
    08036     const CImg& save_analyze(const char *filename,const float *const voxsize=NULL) const {
    08037       cimg_test(*this,"CImg<T>::save_analyze");
    08038       std::FILE *file;
    08039       char header[348],hname[1024],iname[1024];
    08040       const char *ext = cimg::filename_split(filename);
    08041       short datatype=-1;
    08042       std::memset(header,0,348);
    08043       if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
    08044       if (!cimg::strncasecmp(ext,"hdr",3)) { std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img"); }
    08045       if (!cimg::strncasecmp(ext,"img",3)) { std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr"); }
    08046       ((int*)(header))[0] = 348;
    08047       std::sprintf(header+4,"CImg");
    08048       std::sprintf(header+14," ");
    08049       ((short*)(header+36))[0] = 4096;
    08050       ((char*)(header+38))[0] = 114;
    08051       ((short*)(header+40))[0] = 4;
    08052       ((short*)(header+40))[1] = width;
    08053       ((short*)(header+40))[2] = height;
    08054       ((short*)(header+40))[3] = depth;
    08055       ((short*)(header+40))[4] = dim;
    08056       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
    08057       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
    08058       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
    08059       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
    08060       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
    08061       ((short*)(header+70))[0] = datatype;
    08062       ((short*)(header+72))[0] = sizeof(T);
    08063       ((float*)(header+112))[0] = 1;
    08064       ((float*)(header+76))[0] = 0;
    08065       if (voxsize) {
    08066         ((float*)(header+76))[1] = voxsize[0];
    08067         ((float*)(header+76))[2] = voxsize[1];
    08068         ((float*)(header+76))[3] = voxsize[2];
    08069       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
    08070       file = cimg::fopen(hname,"wb");
    08071       cimg::fwrite(header,sizeof(char),348,file);
    08072       cimg::fclose(file);
    08073       file = cimg::fopen(iname,"wb");
    08074       cimg::fwrite(data,sizeof(T),size(),file);
    08075       cimg::fclose(file);
    08076       return *this;
    08077     }
    08078
    08080     const CImg& save_raw(const char *filename) const {
    08081       cimg_test(*this,"CImg<T>::save_raw");
    08082       std::FILE *file;
    08083       file=cimg::fopen(filename,"wb");
    08084       std::fprintf(file,"1#%s\n%d %d %d %d\n",pixel_type(),width,height,depth,dim);
    08085       if (!cimg::CPU_endian()) {
    08086         CImg<T> tmp(*this);
    08087         cimg::bswap(tmp.data,tmp.size(),sizeof(T));
    08088         cimg::fwrite(tmp.data,sizeof(T),width*height*depth*dim,file);
    08089       }
    08090       else {
    08091         cimg::fwrite(data,sizeof(T),width*height*depth*dim,file);
    08092       }
    08093       cimg::fclose(file);
    08094       return *this;
    08095     }
    08096
    08100     const CImg& save_convert(const char *filename) const {
    08101       cimg_test(*this,"CImg<T>::save_convert");
    08102       srand((unsigned int)::time(NULL));
    08103       char command[512],filetmp[512];
    08104       std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),::rand()%10000);
    08105       save_pnm(filetmp);
    08106       std::sprintf(command,"\"%s\" -quality 100%% \"%s\" %s",cimg::convert_path(),filetmp,filename);
    08107       cimg::system(command);
    08108       std::FILE *file = std::fopen(filename,"rb");
    08109       if (!file) throw CImgIOException("CImg<%s>::save_convert() : Failed to save image '%s' with 'convert'.\n\
    08110 Check that you have installed the ImageMagick package in a standart directory.",pixel_type(),filename);
    08111       if (file) cimg::fclose(file);
    08112       std::remove(filetmp);
    08113       return *this;
    08114     }
    08115
    08117     const CImg& save_inr(const char *filename,const float *const voxsize = NULL) const {
    08118       cimg_test(*this,"CImg<T>::save_inr");
    08119       std::FILE *file;
    08120       int inrpixsize=-1,err;
    08121       char header[257];
    08122       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
    08123       if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
    08124       else { if (!cimg::strcasecmp(pixel_type(),"char")) {      inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
    08125         else { if (!cimg::strcasecmp(pixel_type(),"unsigned short")) {  inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
    08126           else { if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
    08127             else { if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
    08128               else { if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
    08129                 else { if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
    08130                   else { if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
    08131                   }
    08132                 }
    08133               }
    08134             }
    08135           }
    08136         }
    08137       }
    08138       if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of <%s>",pixel_type(),pixel_type());
    08139       file = cimg::fopen(filename,"wb");
    08140       err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%d\nYDIM=%d\nZDIM=%d\nVDIM=%d\n",width,height,depth,dim);
    08141       if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
    08142       err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::CPU_endian()?"decm":"sun");
    08143       std::memset(header+err,'\n',252-err);
    08144       std::memcpy(header+252,"##}\n",4);
    08145       cimg::fwrite(header,sizeof(char),256,file);
    08146       cimg_mapXYZ(*this,x,y,z) cimg_mapV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),inrpixsize,1,file);
    08147       cimg::fclose(file);
    08148       return *this;
    08149     }
    08150
    08151     unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims) const {
    08152       unsigned int nbdims=0;
    08153       if (id==2 || id==3 || id==4) { dims[0]=1; dims[1]=width; nbdims=2; }
    08154       if (id==5 || id==6 || id==7) { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; }
    08155       if (id==8 || id==9 || id==10) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
    08156       if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=1; nbdims=4; }
    08157       if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=0; nbdims=5; }
    08158       if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; }
    08159       if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; }
    08160       if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
    08161       return nbdims;
    08162     }
    08163
    08165     const CImg& save_pandore(const char* filename) const {
    08166       cimg_test(*this,"CImg<T>::save_pandore");
    08167       std::FILE *file = cimg::fopen(filename,"wb");
    08168       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
    08169                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,
    08170                                    '2','0','0','0','/','0','1','/','0','1',
    08171                                    0 };
    08172       unsigned int nbdims,dims[5];
    08173       bool saved=false;
    08174       cimg_save_pandore_case(1,1,1,"unsigned char",2);
    08175       cimg_save_pandore_case(1,1,1,"char",3);
    08176       cimg_save_pandore_case(1,1,1,"short",3);
    08177       cimg_save_pandore_case(1,1,1,"unsigned short",3);
    08178       cimg_save_pandore_case(1,1,1,"unsigned int",3);
    08179       cimg_save_pandore_case(1,1,1,"int",3);
    08180       cimg_save_pandore_case(1,1,1,"unsigned long",4);
    08181       cimg_save_pandore_case(1,1,1,"long",3);
    08182       cimg_save_pandore_case(1,1,1,"float",4);
    08183       cimg_save_pandore_case(1,1,1,"double",4);
    08184
    08185       cimg_save_pandore_case(0,1,1,"unsigned char",5);
    08186       cimg_save_pandore_case(0,1,1,"char",6);
    08187       cimg_save_pandore_case(0,1,1,"short",6);
    08188       cimg_save_pandore_case(0,1,1,"unsigned short",6);
    08189       cimg_save_pandore_case(0,1,1,"unsigned int",6);
    08190       cimg_save_pandore_case(0,1,1,"int",6);
    08191       cimg_save_pandore_case(0,1,1,"unsigned long",7);
    08192       cimg_save_pandore_case(0,1,1,"long",6);
    08193       cimg_save_pandore_case(0,1,1,"float",7);
    08194       cimg_save_pandore_case(0,1,1,"double",7);
    08195
    08196       cimg_save_pandore_case(0,0,1,"unsigned char",8);
    08197       cimg_save_pandore_case(0,0,1,"char",9);
    08198       cimg_save_pandore_case(0,0,1,"short",9);
    08199       cimg_save_pandore_case(0,0,1,"unsigned short",9);
    08200       cimg_save_pandore_case(0,0,1,"unsigned int",9);
    08201       cimg_save_pandore_case(0,0,1,"int",9);
    08202       cimg_save_pandore_case(0,0,1,"unsigned long",10);
    08203       cimg_save_pandore_case(0,0,1,"long",9);
    08204       cimg_save_pandore_case(0,0,1,"float",10);
    08205       cimg_save_pandore_case(0,0,1,"double",10);
    08206
    08207       cimg_save_pandore_case(0,1,3,"unsigned char",16);
    08208       cimg_save_pandore_case(0,1,3,"char",17);
    08209       cimg_save_pandore_case(0,1,3,"short",17);
    08210       cimg_save_pandore_case(0,1,3,"unsigned short",17);
    08211       cimg_save_pandore_case(0,1,3,"unsigned int",17);
    08212       cimg_save_pandore_case(0,1,3,"int",17);
    08213       cimg_save_pandore_case(0,1,3,"unsigned long",18);
    08214       cimg_save_pandore_case(0,1,3,"long",17);
    08215       cimg_save_pandore_case(0,1,3,"float",18);
    08216       cimg_save_pandore_case(0,1,3,"double",18);
    08217
    08218       cimg_save_pandore_case(0,0,3,"unsigned char",19);
    08219       cimg_save_pandore_case(0,0,3,"char",20);
    08220       cimg_save_pandore_case(0,0,3,"short",20);
    08221       cimg_save_pandore_case(0,0,3,"unsigned short",20);
    08222       cimg_save_pandore_case(0,0,3,"unsigned int",20);
    08223       cimg_save_pandore_case(0,0,3,"int",20);
    08224       cimg_save_pandore_case(0,0,3,"unsigned long",21);
    08225       cimg_save_pandore_case(0,0,3,"long",20);
    08226       cimg_save_pandore_case(0,0,3,"float",21);
    08227       cimg_save_pandore_case(0,0,3,"double",21);
    08228
    08229       cimg_save_pandore_case(1,1,0,"unsigned char",22);
    08230       cimg_save_pandore_case(1,1,0,"char",23);
    08231       cimg_save_pandore_case(1,1,0,"short",23);
    08232       cimg_save_pandore_case(1,1,0,"unsigned short",23);
    08233       cimg_save_pandore_case(1,1,0,"unsigned int",23);
    08234       cimg_save_pandore_case(1,1,0,"int",23);
    08235       cimg_save_pandore_case(1,1,0,"unsigned long",25);
    08236       cimg_save_pandore_case(1,1,0,"long",23);
    08237       cimg_save_pandore_case(1,1,0,"float",25);
    08238       cimg_save_pandore_case(1,1,0,"double",25);
    08239
    08240       cimg_save_pandore_case(0,1,0,"unsigned char",26);
    08241       cimg_save_pandore_case(0,1,0,"char",27);
    08242       cimg_save_pandore_case(0,1,0,"short",27);
    08243       cimg_save_pandore_case(0,1,0,"unsigned short",27);
    08244       cimg_save_pandore_case(0,1,0,"unsigned int",27);
    08245       cimg_save_pandore_case(0,1,0,"int",27);
    08246       cimg_save_pandore_case(0,1,0,"unsigned long",29);
    08247       cimg_save_pandore_case(0,1,0,"long",27);
    08248       cimg_save_pandore_case(0,1,0,"float",29);
    08249       cimg_save_pandore_case(0,1,0,"double",29);
    08250
    08251       cimg_save_pandore_case(0,0,0,"unsigned char",30);
    08252       cimg_save_pandore_case(0,0,0,"char",31);
    08253       cimg_save_pandore_case(0,0,0,"short",31);
    08254       cimg_save_pandore_case(0,0,0,"unsigned short",31);
    08255       cimg_save_pandore_case(0,0,0,"unsigned int",31);
    08256       cimg_save_pandore_case(0,0,0,"int",31);
    08257       cimg_save_pandore_case(0,0,0,"unsigned long",33);
    08258       cimg_save_pandore_case(0,0,0,"long",31);
    08259       cimg_save_pandore_case(0,0,0,"float",33);
    08260       cimg_save_pandore_case(0,0,0,"double",33);
    08261
    08262       cimg::fclose(file);
    08263       return *this;
    08264     }
    08265
    08266
    08268     //------------------------------------------
    08269     //------------------------------------------
    08270     //
    08272
    08273     //------------------------------------------
    08274     //------------------------------------------
    08275     CImg& swap(CImg& img) {
    08276       int tmp = img.width; img.width = width;   width = tmp;
    08277       tmp = img.height;    img.height = height; height = tmp;
    08278       tmp = img.depth;     img.depth = depth;   depth = tmp;
    08279       tmp = img.dim;       img.dim = dim;       dim = tmp;
    08280       T* const ptr = img.data; img.data = data; data = ptr;
    08281       return img;
    08282     }
    08283
    08285   };
    08286
    08287
    08288   /*-------------------------------------------------------
    08289
    08290
    08291
    08292
    08293   Definition of the CImgl<> structure
    08294
    08295
    08296
    08297
    08298   ------------------------------------------------------*/
    08300   template<typename T> struct CImgl {
    08302
    08305     unsigned int size;
    08306
    08308
    08312     CImg<T> *data;
    08313
    08314     //------------------------------------------
    08315     //------------------------------------------
    08316     //
    08318
    08319     //------------------------------------------
    08320     //------------------------------------------
    08321
    08323     static const char* pixel_type() { T val; return cimg::get_type(val); }
    08324
    08326     CImgl(const unsigned int n=0,const unsigned int width=0,const unsigned int height=1,
    08327           const unsigned int depth=1, const unsigned int dim=1):size(n) {
    08328       if (n) {
    08329         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
    08330         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim);
    08331       } else data = NULL;
    08332     }
    08333
    08334     // ! Create a list of \p n copy of the input image.
    08335     template<typename t> CImgl(const unsigned int n, const CImg<t>& img):size(n) {
    08336       if (n) {
    08337         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
    08338         cimgl_map(*this,l) data[l]=img;
    08339       } else data = NULL;
    08340     }
    08341
    08343     template<typename t> CImgl(const CImgl<t>& list):size(list.size) {
    08344       if (size) {
    08345         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
    08346         cimgl_map(*this,l) data[l] = list[l];
    08347       } else data = NULL;
    08348     }
    08349     CImgl(const CImgl<T>& list):size(list.size) {
    08350       if (size>0) {
    08351         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
    08352         cimgl_map(*this,l) data[l] = list[l];
    08353       } else data = NULL;
    08354     }
    08355
    08357     CImgl(const char* filename):size(0),data(NULL) { load(filename).swap(*this); }
    08358
    08360     CImgl(const CImg<T>& img):size(0),data(NULL) { CImgl<T>(1,img).swap(*this); }
    08361
    08363     CImgl(const CImg<T>& img1,const CImg<T>& img2):size(2) {
    08364       data = new CImg<T>[cimg::lblock];
    08365       data[0] = img1;
    08366       data[1] = img2;
    08367     }
    08368
    08370     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3):size(3) {
    08371       data = new CImg<T>[cimg::lblock];
    08372       data[0] = img1;
    08373       data[1] = img2;
    08374       data[2] = img3;
    08375     }
    08376
    08378     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3,const CImg<T>& img4):size(4) {
    08379       data = new CImg<T>[cimg::lblock];
    08380       data[0] = img1;
    08381       data[1] = img2;
    08382       data[2] = img3;
    08383       data[3] = img4;
    08384     }
    08385
    08387     template<typename t> CImgl& operator=(const CImgl<t>& list) { return CImgl<T>(list).swap(*this); }
    08388     CImgl& operator=(const CImgl<T>& list) { if (&list==this) return *this; return CImgl<T>(list).swap(*this); }
    08389
    08391     ~CImgl() { if (data) delete[] data; }
    08392
    08394     CImgl& empty() { return CImgl<T>().swap(*this); }
    08395
    08397     //------------------------------------------
    08398     //------------------------------------------
    08399     //
    08401
    08402     //------------------------------------------
    08403     //------------------------------------------
    08404
    08406     template<typename t> CImgl& operator+=(const CImgl<t>& list) {
    08407       const unsigned int sizemax = min(size,list.size);
    08408       for (unsigned int l=0; l<sizemax; l++) (*this)[l]+=list[l];
    08409       return *this;
    08410     }
    08411
    08413     template<typename t> CImgl& operator-=(const CImgl<t>& list) {
    08414       const unsigned int sizemax = min(size,list.size);
    08415       for (unsigned int l=0; l<sizemax; l++) (*this)[l]-=list[l];
    08416       return *this;
    08417     }
    08418
    08420     CImgl& operator+=(const T& val) { cimgl_map(*this,l) (*this)[l]+=val; return *this; }
    08421
    08423     CImgl& operator-=(const T& val) { cimgl_map(*this,l) (*this)[l]-=val; return *this; }
    08424
    08426     CImgl& operator*=(const double val) { cimgl_map(*this,l) (*this)[l]*=val; return *this; }
    08427
    08429     CImgl& operator/=(const double val) { cimgl_map(*this,l) (*this)[l]/=val; return *this; }
    08430
    08432     CImgl operator+(const T& val) const { return CImgl<T>(*this)+=val;  }
    08433
    08435     CImgl operator*(const double val) const { return CImgl<T>(*this)*=val;  }
    08436
    08438     CImgl operator-(const T& val) const { return CImgl<T>(*this)-=val;  }
    08439
    08441     CImgl operator/(const double val) const { return CImgl<T>(*this)/=val;  }
    08442
    08444     CImgl operator+(const CImgl& list) const { return CImgl<T>(*this)+=list; }
    08445
    08447     CImgl operator-(const CImgl& list) const { return CImgl<T>(*this)-=list; }
    08448
    08450     friend CImgl operator+(const T& val, const CImgl& list) { return CImgl<T>(list)+=val; }
    08451
    08453     friend CImgl operator*(const double val, const CImgl& list) { return CImgl<T>(list)*=val; }
    08454
    08456     //------------------------------------------
    08457     //------------------------------------------
    08458     //
    08460
    08461     //------------------------------------------
    08462     //------------------------------------------
    08463
    08465     CImg<T>& operator[](const unsigned int pos) const {
    08466 #if cimg_debug>1
    08467       if (pos>=size) {
    08468         cimg::warn(true,"CImgl<%s>::operator[] : bad list position %d, in a list of %d images",pixel_type(),pos,size);
    08469         return *data;
    08470       }
    08471 #endif
    08472       return data[pos];
    08473     }
    08474
    08476     CImg<T>& operator()(const unsigned int pos) const { return (*this)[pos]; }
    08477
    08479     CImgl& insert(const CImg<T>& img,const unsigned int pos) {
    08480       if (pos>size) throw CImgArgumentException("CImgl<%s>::insert() : Can't insert at position %d into a list with %d elements",pixel_type(),pos,size);
    08481       CImg<T> *new_data = (!((++size)%cimg::lblock) || !data)?new CImg<T>[(size/cimg::lblock+1)*cimg::lblock]:NULL;
    08482       if (!data) { data=new_data; *data=img; }
    08483       else {
    08484         if (new_data) {
    08485           std::memcpy(new_data,data,sizeof(CImg<T>)*pos);
    08486           if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
    08487           std::memset(data,0,sizeof(CImg<T>)*(size-1));
    08488           delete[] data;
    08489           data = new_data;
    08490         }
    08491         else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
    08492         data[pos].data = NULL;
    08493         data[pos] = img;
    08494       }
    08495       return *this;
    08496     }
    08497
    08499     CImgl& insert(const CImg<T>& img) { return insert(img,size); }
    08500
    08502     CImgl& insert(const CImgl<T>& list,const unsigned int pos) { cimgl_map(list,l) insert(list[l],pos+l); return *this; }
    08503
    08505     CImgl& insert(const CImgl<T>& list) { return insert(list,size); }
    08506
    08508     CImgl& remove(const unsigned int pos) {
    08509       if (pos>=size) {
    08510         cimg::warn(true,"CImgl<%s>::remove() : Can't remove an image from a list (%p,%d), at position %d",pixel_type(),data,size,pos);
    08511         return *this;
    08512       }
    08513       CImg<T> tmp; tmp.swap(data[pos]); // the image to remove will be freed
    08514       size--;
    08515       if (pos!=size) {
    08516         memmove(data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
    08517         CImg<T> &tmp = data[size];
    08518         tmp.width = tmp.height = tmp.depth = tmp.dim = 0;
    08519         tmp.data = NULL;
    08520       }
    08521       return *this;
    08522     }
    08523
    08525     CImgl& remove() { return remove(size); }
    08526
    08528     //------------------------------------------
    08529     //------------------------------------------
    08530     //
    08532
    08533     //------------------------------------------
    08534     //------------------------------------------
    08535
    08537     const CImgl& print(const char* title=NULL,const int print_flag=1) const {
    08538       char tmp[1024];
    08539       std::fprintf(stderr,"%-8s(%p) : (%d,%p)\n",title?title:"CImgl",this,size,data);
    08540       if (print_flag>0) cimgl_map(*this,l) {
    08541         std::sprintf(tmp,"%s[%d]",title?title:"CImgl",l);
    08542         data[l].print(tmp,print_flag);
    08543       }
    08544       return *this;
    08545     }
    08547     static CImgl load_raw(const char *filename) {
    08548       typedef unsigned char uchar;
    08549       typedef unsigned short ushort;
    08550       typedef unsigned int uint;
    08551       typedef unsigned long ulong;
    08552       std::FILE *file = cimg::fopen(filename,"rb");
    08553       char tmp[256],tmp2[256];
    08554       int i;
    08555       bool loaded = false;
    08556       unsigned int n,j,w,h,z,k,err;
    08557       j=0; while((i=fgetc(file))!='\n' && i!=EOF) tmp[j++]=i; tmp[j]='\0';
    08558       err=std::sscanf(tmp,"%d#%255[A-Za-z ]",&n,tmp2);
    08559       if (err!=2) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', Unknow .raw header",pixel_type(),filename);
    08560       CImgl<T> res(n);
    08561       cimg_load_raw_case("unsigned char",uchar);
    08562       cimg_load_raw_case("uchar",uchar);
    08563       cimg_load_raw_case("char",char);
    08564       cimg_load_raw_case("unsigned short",ushort);
    08565       cimg_load_raw_case("ushort",ushort);
    08566       cimg_load_raw_case("short",short);
    08567       cimg_load_raw_case("unsigned int",uint);
    08568       cimg_load_raw_case("uint",uint);
    08569       cimg_load_raw_case("int",int);
    08570       cimg_load_raw_case("unsigned long",ulong);
    08571       cimg_load_raw_case("ulong",ulong);
    08572       cimg_load_raw_case("long",long);
    08573       cimg_load_raw_case("float",float);
    08574       cimg_load_raw_case("double",double);
    08575       if (!loaded) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', can't read images of %s",pixel_type(),filename,tmp2);
    08576       cimg::fclose(file);
    08577       return res;
    08578     }
    08579
    08581     static CImgl load(const char *filename) {
    08582       CImgl res;
    08583       const char *ext = cimg::filename_split(filename);
    08584       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return load_raw(filename); else return CImg<T>(filename);
    08585     }
    08586
    08588     const CImgl& save_raw(const char *filename) const {
    08589       cimgl_test(*this,"CImgl<T>::save_raw");
    08590       CImg<T> img,tmp;
    08591       std::FILE *file;
    08592       file=cimg::fopen(filename,"wb");
    08593       std::fprintf(file,"%d#%s\n",size,data[0].pixel_type());
    08594       cimgl_map(*this,l) {
    08595         img = data[l];
    08596         std::fprintf(file,"%d %d %d %d\n",img.width,img.height,img.depth,img.dim);
    08597         if (!cimg::CPU_endian()) {
    08598           tmp = img;
    08599           cimg::bswap(tmp.data,tmp.size(),sizeof(T));
    08600           cimg::fwrite(tmp.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
    08601         }
    08602         else {
    08603           cimg::fwrite(img.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
    08604         }
    08605       }
    08606       cimg::fclose(file);
    08607       return *this;
    08608     }
    08609
    08612     const CImgl& save(const char *filename) const {
    08613       cimgl_test(*this,"CImgl<T>::save");
    08614       const char *ext = cimg::filename_split(filename);
    08615       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return save_raw(filename);
    08616       else {
    08617         if (size==1) data[0].save(filename,-1);
    08618         else cimgl_map(*this,l) data[l].save(filename,l);
    08619       }
    08620       return *this;
    08621     }
    08622
    08624     // centering them using the alignment \p align.
    08625     CImg<T> get_append(const char axe='x',const char align='c') const {
    08626       cimgl_test(*this,"CImgl<T>::get_append");
    08627       unsigned int dx=0,dy=0,dz=0,dv=0,pos=0;
    08628       CImg<T> res;
    08629       switch(axe) {
    08630       case 'x':
    08631         {
    08632           cimgl_map(*this,l) {
    08633             const CImg<T>& img = (*this)[l];
    08634             dx += img.width;
    08635             dy = cimg::max(dy,img.height);
    08636             dz = cimg::max(dz,img.depth);
    08637             dv = cimg::max(dv,img.dim);
    08638           }
    08639           res = CImg<T>(dx,dy,dz,dv).fill(0);
    08640           switch (align) {
    08641           case 'p' : { cimgl_map(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break;
    08642           case 'n' : { cimgl_map(*this,ll) {
    08643             res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width;
    08644           }} break;
    08645           default  : { cimgl_map(*this,ll) {
    08646             res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
    08647             pos+=(*this)[ll].width;
    08648           }} break;
    08649           }
    08650         }
    08651         break;
    08652       case 'y':
    08653         {
    08654           cimgl_map(*this,l) {
    08655             const CImg<T>& img = (*this)[l];
    08656             dx = cimg::max(dx,img.width);
    08657             dy += img.height;
    08658             dz = cimg::max(dz,img.depth);
    08659             dv = cimg::max(dv,img.dim);
    08660           }
    08661           res = CImg<T>(dx,dy,dz,dv).fill(0);
    08662           switch (align) {
    08663           case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break;
    08664           case 'n': { cimgl_map(*this,ll) {
    08665             res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height;
    08666           }} break;
    08667           default : { cimgl_map(*this,ll) {
    08668             res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
    08669             pos+=(*this)[ll].height;
    08670           }} break;
    08671           }
    08672         }
    08673         break;
    08674       case 'z':
    08675         {
    08676           cimgl_map(*this,l) {
    08677             const CImg<T>& img = (*this)[l];
    08678             dx = cimg::max(dx,img.width);
    08679             dy = cimg::max(dy,img.height);
    08680             dz += img.depth;
    08681             dv = cimg::max(dv,img.dim);
    08682           }
    08683           res = CImg<T>(dx,dy,dz,dv).fill(0);
    08684           switch (align) {
    08685           case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break;
    08686           case 'n': { cimgl_map(*this,ll) {
    08687             res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth;
    08688           }} break;
    08689           case 'c': { cimgl_map(*this,ll) {
    08690             res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2);
    08691             pos+=(*this)[ll].depth;
    08692           }} break;
    08693           }
    08694         }
    08695         break;
    08696       case 'v':
    08697         {
    08698           cimgl_map(*this,l) {
    08699             const CImg<T>& img = (*this)[l];
    08700             dx = cimg::max(dx,img.width);
    08701             dy = cimg::max(dy,img.height);
    08702             dz = cimg::max(dz,img.depth);
    08703             dv += img.dim;
    08704           }
    08705           res = CImg<T>(dx,dy,dz,dv).fill(0);
    08706           switch (align) {
    08707           case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break;
    08708           case 'n': { cimgl_map(*this,ll) {
    08709             res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim;
    08710           }} break;
    08711           case 'c': { cimgl_map(*this,ll) {
    08712             res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos);
    08713             pos+=(*this)[ll].dim;
    08714           }} break;
    08715           }
    08716         }
    08717         break;
    08718       }
    08719       return res;
    08720     }
    08721
    08728     CImgDisplay* new_display(const char *title="",const int normalize=1,const unsigned int attributes=3,const char axe='x',const char align='c') const  {
    08729       return get_append(axe,align).new_display(title,normalize,attributes);
    08730     }
    08734     const CImgl& display(CImgDisplay& disp,const char axe='x',const char align='c') const { get_append(axe,align).display(disp); return *this; }
    08738     const CImgl& display(CImgDisplay* disp,const char axe='x',const char align='c') const {
    08739       if (!disp) throw CImgArgumentException("CImgl<%s>::display() : given display pointer is (null)",pixel_type());
    08740       else display(*disp,axe,align);
    08741       return *this;
    08742     }
    08746     const CImgl& display(const char* title,const char axe='x',const char align='c',const int min_size=128,const int max_size=1024) const {
    08747       get_append(axe,align).display(title,min_size,max_size);
    08748       return *this;
    08749     }
    08753     const CImgl& display(const char axe='x',const char align='c',const int min_size=128,const int max_size=1024) const {
    08754       return display("",axe,align,min_size,max_size);
    08755     }
    08757     const CImgl& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
    08758
    08759     CImgl& swap(CImgl& list) {
    08760       int tmp = list.size; list.size = size; size = tmp;
    08761       CImg<T>* ptr = list.data; list.data = data; data = ptr;
    08762       return list;
    08763     }
    08764
    08766   };
    08767
    08768
    08770
    08776   template<typename T> struct CImgROI : public CImg<T> {
    08777     CImgROI(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,T *const pdata) {
    08778       CImg<T>::width = dx; CImg<T>::height = dy; CImg<T>::depth = dz; CImg<T>::dim = dv; CImg<T>::data = pdata;
    08779     }
    08780     CImgROI(const CImgROI& roi) {
    08781       CImg<T>::width = roi.width; CImg<T>::height = roi.height; CImg<T>::depth = roi.depth; CImg<T>::dim = roi.dim;
    08782       CImg<T>::data = roi.data;
    08783     }
    08784     ~CImgROI() { CImg<T>::width=CImg<T>::height=CImg<T>::depth=CImg<T>::dim=0; CImg<T>::data=NULL;}
    08785   };
    08786
    08787 }
    08788
    08789 // Overcome VisualC++ 6.0 and DMC compilers namespace bug
    08790 #if ( defined(_MSC_VER) || defined(__DMC__) ) && defined(std)
    08791 #undef std
    08792 #endif
    08793
    08794 /*--------------------------------------------------------------------------------------
    08795
    08796
    08797
    08798   Additional documentation for the generation of the reference page (using doxygen)
    08799
    08800
    08801
    08802   -------------------------------------------------------------------------------------*/
    08819 //---------------------------------------------------------------------------------------------------------------
    08821
    08949
    08950 //--------------------------------------------------------------------------------------------------------------------
    08952
    09018
    09019 //--------------------------------------------------------------------------------------------------------------------
    09021
    09118
    09119 //----------------------------------------------------------------------------------------------------
    09121
    09143
    09144 //----------------------------------------------------------------------------------------------------
    09146
    09382 //----------------------------------------------------------------------------------------------------
    09384
    09405
    09406 //----------------------------------------------------------------------------------------------------
    09408
    09494 //----------------------------------------------------------------------------------------------------
    09495 #endif