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

Generated on Thu Dec 2 11:26:17 2004 for The CImg Library by  doxygen 1.3.9.1