C++ Template Image Processing Library.    

[Introduction]- [News]- [Download]- [Screenshots]- [Tutorial]- [Forums-Eng]- [Forums-Fr]- [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                 ( http://cimg.sourceforge.net )
00007 
00008   Copyright   : David Tschumperle
00009                 ( http://www.greyc.ensicaen.fr/~dtschump/ )
00010    
00011   This software is governed by the CeCILL  license under French law and
00012   abiding by the rules of distribution of free software.  You can  use, 
00013   modify and/ or redistribute the software under the terms of the CeCILL
00014   license as circulated by CEA, CNRS and INRIA at the following URL
00015   "http://www.cecill.info". 
00016   
00017   As a counterpart to the access to the source code and  rights to copy,
00018   modify and redistribute granted by the license, users are provided only
00019   with a limited warranty  and the software's author,  the holder of the
00020   economic rights,  and the successive licensors  have only  limited
00021   liability. 
00022   
00023   In this respect, the user's attention is drawn to the risks associated
00024   with loading,  using,  modifying and/or developing or reproducing the
00025   software by the user in light of its specific status of free software,
00026   that may mean  that it is complicated to manipulate,  and  that  also
00027   therefore means  that it is reserved for developers  and  experienced
00028   professionals having in-depth computer knowledge. Users are therefore
00029   encouraged to load and test the software's suitability as regards their
00030   requirements in conditions enabling the security of their systems and/or 
00031   data to be ensured and,  more generally, to use and operate it in the 
00032   same conditions as regards security. 
00033   
00034   The fact that you are presently reading this means that you have had
00035   knowledge of the CeCILL license and that you accept its terms.
00036   
00037   ----------------------------------------------------------------------------------------------------*/
00038 
00039 #ifndef cimg_version
00040 #define cimg_version 1.09
00041 #include <cstdio>
00042 #include <cstdlib>
00043 #include <cstdarg>
00044 #include <cstring>
00045 #include <cmath>
00046 #include <ctime>
00047 
00048 // Overcome VisualC++ 6.0 and DMC compilers namespace 'std::' bug
00049 #if ( defined(_MSC_VER) && _MSC_VER<=1200 ) || defined(__DMC__)
00050 #define std
00051 #endif
00052 
00053 /*-------------------------------------------------------------
00054   
00055   Set CImg configuration flags.
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)       || defined(linux)       || defined(__linux)    \
00065  || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__OPENBSD__) || defined(__MACOSX__) \
00066  || defined(__APPLE__)  || defined(sgi)         || defined(__sgi)
00067 // Unix (Linux,Solaris,BSD,Irix,...)
00068 #define cimg_OS            1
00069 #ifndef cimg_display_type
00070 #define cimg_display_type  1
00071 #endif
00072 #ifndef cimg_color_terminal
00073 #define cimg_color_terminal
00074 #endif
00075 #elif defined(_WIN32) || defined(__WIN32__)
00076 // Windows
00077 #define cimg_OS            2
00078 #ifndef cimg_display_type
00079 #define cimg_display_type  2
00080 #endif
00081 #else
00082 // Unknown configuration : compile with minimal dependencies.
00083 #define cimg_OS            0
00084 #ifndef cimg_display_type
00085 #define cimg_display_type  0
00086 #endif
00087 #endif
00088 #endif
00089 
00090 // Debug configuration.
00091 //--------------------
00092 // Define 'cimg_debug' to : 0 to remove dynamic debug messages (exceptions are still thrown)
00093 //                          1 to display dynamic debug messages (default behavior).
00094 //                          2 to add extra memory access controls (may slow down the code)
00095 #ifndef cimg_debug
00096 #define cimg_debug         1
00097 #endif
00098 
00099 // Architecture-dependent includes
00100 //---------------------------------
00101 #if cimg_OS==1
00102 #include <sys/time.h>
00103 #include <unistd.h>
00104 #else
00105 #include <windows.h>
00106 // Discard unuseful macros in windows.h
00107 #ifdef min
00108 #undef min
00109 #undef max
00110 #undef abs
00111 #endif
00112 #endif
00113 #if cimg_display_type==1
00114 #include <X11/Xlib.h>
00115 #include <X11/Xutil.h>
00116 #include <X11/keysym.h>
00117 #include <pthread.h>
00118 #endif
00119 
00120 // Native PNG and JPEG support
00121 //-----------------------------
00122 // Define 'cimg_use_png' or 'cimg_use_jpeg' to enable native PNG or JPEG files support.
00123 // This requires you link your code either with the zlib/png libraries or the jpeg library.
00124 #ifdef cimg_use_png
00125 #include "png.h"
00126 #endif
00127 #ifdef cimg_use_jpeg
00128 #include "jpeglib.h"
00129 #endif
00130 
00131 /*-----------------------------------------------------------------------------------
00132 
00133 
00134    Define some macros. Macros of the CImg Library are prefixed by 'cimg_'
00135    Documented macros below may be safely used in your own code.
00136 
00137 
00138    ---------------------------------------------------------------------------------*/
00139 
00140 // Macros used to describe the program usage, and retrieve command line arguments
00141 // (See corresponding module 'Retrieving command line arguments' in the generated documentation).
00142 #define cimg_usage(usage) cimg_library::cimg::option((char*)NULL,(unsigned int)argc,(char**)argv,(char*)NULL,(char*)usage)
00143 #define cimg_option(name,defaut,usage) cimg_library::cimg::option((char*)name,(unsigned int)argc,(char**)argv,defaut,(char*)usage)
00144 
00145 // Macros used for dynamic debug messages. Shouldn't be used in your own source code.
00146 #define cimg_test(x,func)                                               \
00147   if(!(x).width || !(x).height || !(x).depth || !(x).dim || !(x).data)  \
00148     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is empty", \
00149                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
00150 #define cimgl_test(x,func) \
00151   if(!(x).size || !(x).data) \
00152     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImgl<%s> %s = (%d,%p) is empty", \
00153                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).size,(x).data)
00154 #define cimg_test_scalar(x,func) \
00155   if(!(x).width || !(x).height || !(x).depth || (x).dim!=1 || !(x).data) \
00156     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not scalar", \
00157                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
00158 #define cimg_test_matrix(x,func) \
00159   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || !(x).data) \
00160     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a matrix", \
00161                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
00162 #define cimg_test_square(x,func) \
00163   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || (x).width!=(x).height || !(x).data) \
00164     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a square matrix", \
00165                                 func,__FILE__,__LINE__,(x).pixel_type,#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
00166 #define cimg_test_display(x,func) \
00167   if (!(x).width || !(x).height) \
00168     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', l.%d), CImgDisplay %s = (%d,%d) is not a valid display", \
00169                                 func,__FILE__,__LINE__,#x,(x).width,(x).height)
00170   
00171 // Macros used for neighborhood definitions and manipulations (see module 'Using Image Loops' in the generated documentation).
00172 #define CImg_2x2(I,T)     T I##cc,I##nc=0,I##cn,I##nn=0
00173 #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
00174 #define CImg_4x4(I,T)     T I##pp,I##cp,I##np=0,I##ap=0, \
00175                             I##pc,I##cc,I##nc=0,I##ac=0, \
00176                             I##pn,I##cn,I##nn=0,I##an=0, \
00177                             I##pa,I##ca,I##na=0,I##aa=0
00178 #define CImg_5x5(I,T)     T I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \
00179                             I##bp,I##pp,I##cp,I##np=0,I##ap=0, \
00180                             I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \
00181                             I##bn,I##pn,I##cn,I##nn=0,I##an=0, \
00182                             I##ba,I##pa,I##ca,I##na=0,I##aa=0
00183 #define CImg_2x2x2(I,T)   T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \
00184                             I##ccn,I##ncn=0,I##cnn,I##nnn=0
00185 #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, \
00186                             I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \
00187                             I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0
00188 
00189 #define CImg_2x2_ref(I,T,tab)   T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3];
00190 #define CImg_3x3_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \
00191                                   &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \
00192                                   &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8]
00193 #define CImg_4x4_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2],&I##ap=(tab)[3], \
00194                                   &I##pc=(tab)[4],&I##cc=(tab)[5],&I##nc=(tab)[6],&I##ap=(tab)[7], \
00195                                   &I##pn=(tab)[8],&I##cn=(tab)[9],&I##nn=(tab)[10],&I##aa=(tab)[11], \
00196                                   &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15]
00197 #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], \
00198                                   &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \
00199                                   &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \
00200                                   &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \
00201                                   &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24]
00202 #define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \
00203                                   &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7]
00204 #define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \
00205                                   &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \
00206                                   &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \
00207                                   &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \
00208                                   &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \
00209                                   &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \
00210                                   &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \
00211                                   &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \
00212                                   &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26]
00213 
00214 #define cimg_squaresum2x2(I) ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn )
00215 #define cimg_squaresum3x3(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \
00216                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \
00217                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn )
00218 #define cimg_squaresum4x4(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
00219                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
00220                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
00221                                I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
00222 #define cimg_squaresum5x5(I) ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \
00223                                I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
00224                                I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
00225                                I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
00226                                I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
00227 #define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \
00228                                  I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn )
00229 #define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \
00230                                  I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \
00231                                  I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \
00232                                  I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \
00233                                  I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \
00234                                  I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \
00235                                  I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \
00236                                  I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \
00237                                  I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn )
00238 
00239 #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) )
00240 #define cimg_corr3x3(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \
00241                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \
00242                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) )
00243 #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) + \
00244                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \
00245                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \
00246                             I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) )
00247 #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) + \
00248                             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) + \
00249                             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) + \
00250                             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) + \
00251                             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) )
00252 #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) + \
00253                               I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) )
00254 #define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \
00255                               I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \
00256                               I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \
00257                               I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \
00258                               I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \
00259                               I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \
00260                               I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \
00261                               I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \
00262                               I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) )
00263 
00264 #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) )
00265 #define cimg_conv3x3(I,m) ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \
00266                             I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \
00267                             I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
00268 #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) + \
00269                             I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
00270                             I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
00271                             I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
00272 #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) + \
00273                             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) + \
00274                             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) + \
00275                             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) + \
00276                             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) )
00277 #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) + \
00278                               I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
00279 #define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \
00280                               I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \
00281                               I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \
00282                               I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \
00283                               I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \
00284                               I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
00285                               I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \
00286                               I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \
00287                               I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
00288 
00289 #define cimg_get2x2(img,x,y,z,v,I) I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
00290     I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
00291 #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), \
00292     I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
00293     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)
00294 #define cimg_get4x4(img,x,y,z,v,I)                                      \
00295   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), \
00296     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), \
00297     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), \
00298     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)
00299 #define cimg_get5x5(img,x,y,z,v,I)                                      \
00300   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), \
00301     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), \
00302     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), \
00303     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), \
00304     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)
00305 #define cimg_get2x2x2(img,x,y,z,v,I)                                    \
00306   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), \
00307     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)
00308 #define cimg_get3x3x3(img,x,y,z,v,I)                                    \
00309   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), \
00310     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), \
00311     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), \
00312     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), \
00313     I##pcc=(img)(_p##x,    y,    z,v), I##ccc=(img)(x,    y,    z,v), I##ncc=(img)(_n##x,    y,    z,v), \
00314     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), \
00315     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), \
00316     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), \
00317     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)
00318 
00319 #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, \
00320     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), \
00321     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), \
00322     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)
00323 
00324 // Macros used to define special image loops (see module 'Using Image Loops' in the generated documentation).
00325 #define cimg_map(img,ptr,T_ptr)   for (T_ptr *ptr=(img).data+(img).size()-1; ptr>=(img).data; ptr--)
00326 #define cimgl_map(list,l)         for (unsigned int l=0; l<(list).size; l++)
00327 #define cimg_mapoff(img,off)      for (unsigned int off=0; off<(img).size(); off++)
00328 #define cimg_mapX(img,x)          for (int x=0; x<(int)((img).width); x++)
00329 #define cimg_mapY(img,y)          for (int y=0; y<(int)((img).height);y++)
00330 #define cimg_mapZ(img,z)          for (int z=0; z<(int)((img).depth); z++)
00331 #define cimg_mapV(img,v)          for (int v=0; v<(int)((img).dim);   v++)
00332 #define cimg_mapXY(img,x,y)       cimg_mapY(img,y) cimg_mapX(img,x)
00333 #define cimg_mapXZ(img,x,z)       cimg_mapZ(img,z) cimg_mapX(img,x)
00334 #define cimg_mapYZ(img,y,z)       cimg_mapZ(img,z) cimg_mapY(img,y)
00335 #define cimg_mapXV(img,x,v)       cimg_mapV(img,v) cimg_mapX(img,x)
00336 #define cimg_mapYV(img,y,v)       cimg_mapV(img,v) cimg_mapY(img,y)
00337 #define cimg_mapZV(img,z,v)       cimg_mapV(img,v) cimg_mapZ(img,z)
00338 #define cimg_mapXYZ(img,x,y,z)    cimg_mapZ(img,z) cimg_mapXY(img,x,y)
00339 #define cimg_mapXYV(img,x,y,v)    cimg_mapV(img,v) cimg_mapXY(img,x,y)
00340 #define cimg_mapXZV(img,x,z,v)    cimg_mapV(img,v) cimg_mapXZ(img,x,z)
00341 #define cimg_mapYZV(img,y,z,v)    cimg_mapV(img,v) cimg_mapYZ(img,y,z)
00342 #define cimg_mapXYZV(img,x,y,z,v) cimg_mapV(img,v) cimg_mapXYZ(img,x,y,z)
00343 #define cimg_imapX(img,x,n)       for (int x=n; x<(int)((img).width-n); x++)
00344 #define cimg_imapY(img,y,n)       for (int y=n; y<(int)((img).height-n); y++)
00345 #define cimg_imapZ(img,z,n)       for (int z=n; z<(int)((img).depth-n); z++)
00346 #define cimg_imapV(img,v,n)       for (int v=n; v<(int)((img).dim-n); v++)
00347 #define cimg_imapXY(img,x,y,n)    cimg_imapY(img,y,n) cimg_imapX(img,x,n)
00348 #define cimg_imapXYZ(img,x,y,z,n) cimg_imapZ(img,z,n) cimg_imapXY(img,x,y,n)
00349 #define cimg_bmapX(img,x,n)       for (int x=0; x<(int)((img).width);  x==(n)-1?(x=(img).width-(n)): x++)
00350 #define cimg_bmapY(img,y,n)       for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++)
00351 #define cimg_bmapZ(img,z,n)       for (int z=0; z<(int)((img).depth);  z==(n)-1?(x=(img).depth-(n)): z++)
00352 #define cimg_bmapV(img,v,n)       for (int v=0; v<(int)((img).dim);    v==(n)-1?(x=(img).dim-(n)):   v++)
00353 #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++: \
00354                                                           ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
00355 #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++: \
00356                                                              ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
00357 #define cimg_2mapX(img,x)         for (int x=0,_n##x=1; _n##x<(int)((img).width)   || x==--_n##x; x++, _n##x++)
00358 #define cimg_2mapY(img,y)         for (int y=0,_n##y=1; _n##y<(int)((img).height)  || y==--_n##y; y++, _n##y++)
00359 #define cimg_2mapZ(img,z)         for (int z=0,_n##z=1; _n##z<(int)((img).depth)   || z==--_n##z; z++, _n##z++)
00360 #define cimg_2mapXY(img,x,y)      cimg_2mapY(img,y) cimg_2mapX(img,x)
00361 #define cimg_2mapXZ(img,x,z)      cimg_2mapZ(img,z) cimg_2mapX(img,x)
00362 #define cimg_2mapYZ(img,y,z)      cimg_2mapZ(img,z) cimg_2mapY(img,y)
00363 #define cimg_2mapXYZ(img,x,y,z)   cimg_2mapZ(img,z) cimg_2mapXY(img,x,y)
00364 #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++)
00365 #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++)
00366 #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++)
00367 #define cimg_3mapXY(img,x,y)      cimg_3mapY(img,y) cimg_3mapX(img,x)
00368 #define cimg_3mapXZ(img,x,z)      cimg_3mapZ(img,z) cimg_3mapX(img,x)
00369 #define cimg_3mapYZ(img,y,z)      cimg_3mapZ(img,z) cimg_3mapY(img,y)
00370 #define cimg_3mapXYZ(img,x,y,z)   cimg_3mapZ(img,z) cimg_3mapXY(img,x,y)
00371 #define cimg_4mapX(img,x)         for (int _p##x=0,x=0,_n##x=1,_a##x=2; \
00372                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
00373                                        _p##x=x++,_n##x++,_a##x++)
00374 #define cimg_4mapY(img,y)         for (int _p##y=0,y=0,_n##y=1,_a##y=2; \
00375                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
00376                                        _p##y=y++,_n##y++,_a##y++)
00377 #define cimg_4mapZ(img,z)         for (int _p##z=0,z=0,_n##z=1,_a##z=2; \
00378                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
00379                                        _p##z=z++,_n##z++,_a##z++)
00380 #define cimg_4mapXY(img,x,y)      cimg_4mapY(img,y) cimg_4mapX(img,x)
00381 #define cimg_4mapXZ(img,x,z)      cimg_4mapZ(img,z) cimg_4mapX(img,x)
00382 #define cimg_4mapYZ(img,y,z)      cimg_4mapZ(img,z) cimg_4mapY(img,y)
00383 #define cimg_4mapXYZ(img,x,y,z)   cimg_4mapZ(img,z) cimg_4mapXY(img,x,y)
00384 #define cimg_5mapX(img,x)         for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \
00385                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
00386                                        _b##x=_p##x,_p##x=x++,_n##x++,_a##x++)
00387 #define cimg_5mapY(img,y)         for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \
00388                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
00389                                        _b##y=_p##y,_p##y=y++,_n##y++,_a##y++)
00390 #define cimg_5mapZ(img,z)         for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \
00391                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
00392                                        _b##z=_p##z,_p##z=z++,_n##z++,_a##z++)
00393 #define cimg_5mapXY(img,x,y)      cimg_5mapY(img,y) cimg_5mapX(img,x)
00394 #define cimg_5mapXZ(img,x,z)      cimg_5mapZ(img,z) cimg_5mapX(img,x)
00395 #define cimg_5mapYZ(img,y,z)      cimg_5mapZ(img,z) cimg_5mapY(img,y)
00396 #define cimg_5mapXYZ(img,x,y,z)   cimg_5mapZ(img,z) cimg_5mapXY(img,x,y)
00397 
00398 #define cimg_map2x2(img,x,y,z,v,I) cimg_2mapY(img,y)                    \
00399        for (int _n##x=1, x=((int)(I##cc=(img)(0,  y,z,v),               \
00400                                   I##cn=(img)(0,_n##y,z,v)),0);         \
00401             (_n##x<(int)((img).width) && (                              \
00402                                           I##nc=(img)(_n##x,    y,z,v), \
00403                                           I##nn=(img)(_n##x,_n##y,z,v), \
00404                                           1)) || x==--_n##x;            \
00405             I##cc=I##nc, I##cn=I##nn,                                   \
00406               x++,_n##x++ )
00407 
00408 #define cimg_map3x3(img,x,y,z,v,I) cimg_3mapY(img,y)                    \
00409        for (int _n##x=1, _p##x=(int)(I##cp=I##pp=(img)(0,_p##y,z,v),    \
00410                                      I##cc=I##pc=(img)(0,  y,z,v),      \
00411                                      I##cn=I##pn=(img)(0,_n##y,z,v)     \
00412                                      ), x=_p##x=0;                      \
00413             (_n##x<(int)((img).width) && (                              \
00414                                           I##np=(img)(_n##x,_p##y,z,v), \
00415                                           I##nc=(img)(_n##x,    y,z,v), \
00416                                           I##nn=(img)(_n##x,_n##y,z,v), \
00417                                           1)) || x==--_n##x;            \
00418             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn,                      \
00419               I##cp=I##np, I##cc=I##nc, I##cn=I##nn,                    \
00420               _p##x=x++,_n##x++ )
00421 
00422 #define cimg_map4x4(img,x,y,z,v,I) cimg_4mapY(img,y)                    \
00423        for (int _a##x=2, _n##x=1, x=((int)(I##cp=I##pp=(img)(0,_p##y,z,v), \
00424                                            I##cc=I##pc=(img)(0,    y,z,v), \
00425                                            I##cn=I##pn=(img)(0,_n##y,z,v), \
00426                                            I##ca=I##pa=(img)(0,_a##y,z,v), \
00427                                            I##np=(img)(_n##x,_p##y,z,v), \
00428                                            I##nc=(img)(_n##x,    y,z,v), \
00429                                            I##nn=(img)(_n##x,_n##y,z,v), \
00430                                            I##na=(img)(_n##x,_a##y,z,v)),0), \
00431               _p##x=0;                                                  \
00432             (_a##x<(int)((img).width) && (                              \
00433                                           I##ap=(img)(_a##x,_p##y,z,v), \
00434                                           I##ac=(img)(_a##x,    y,z,v), \
00435                                           I##an=(img)(_a##x,_n##y,z,v), \
00436                                           I##aa=(img)(_a##x,_a##y,z,v), \
00437                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
00438             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca,         \
00439               I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na,       \
00440               I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa,       \
00441               _p##x=x++, _n##x++, _a##x++ )
00442 
00443 #define cimg_map5x5(img,x,y,z,v,I) cimg_5mapY(img,y)                    \
00444        for (int _a##x=2, _n##x=1, _b##x=(int)(I##cb=I##pb=I##bb=(img)(0,_b##y,z,v), \
00445                                               I##cp=I##pp=I##bp=(img)(0,_p##y,z,v), \
00446                                               I##cc=I##pc=I##bc=(img)(0,    y,z,v), \
00447                                               I##cn=I##pn=I##bn=(img)(0,_n##y,z,v), \
00448                                               I##ca=I##pa=I##ba=(img)(0,_a##y,z,v), \
00449                                               I##nb=(img)(_n##x,_b##y,z,v), \
00450                                               I##np=(img)(_n##x,_p##y,z,v), \
00451                                               I##nc=(img)(_n##x,   y,z,v), \
00452                                               I##nn=(img)(_n##x,_n##y,z,v), \
00453                                               I##na=(img)(_n##x,_a##y,z,v)), \
00454               x=0, _p##x=_b##x=0;                                       \
00455             (_a##x<(int)((img).width) && (                              \
00456                                           I##ab=(img)(_a##x,_b##y,z,v), \
00457                                           I##ap=(img)(_a##x,_p##y,z,v), \
00458                                           I##ac=(img)(_a##x,    y,z,v), \
00459                                           I##an=(img)(_a##x,_n##y,z,v), \
00460                                           I##aa=(img)(_a##x,_a##y,z,v), \
00461                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
00462             I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \
00463               I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \
00464               I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \
00465               I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \
00466               _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ )
00467 
00468 #define cimg_map2x2x2(img,x,y,z,v,I) cimg_2mapYZ(img,y,z)               \
00469        for (int _n##x=1, x=((int)(I##ccc=(img)(0,    y,    z,v),        \
00470                                   I##cnc=(img)(0,_n##y,    z,v),        \
00471                                   I##ccn=(img)(0,    y,_n##z,v),        \
00472                                   I##cnn=(img)(0,_n##y,_n##z,v)),0);    \
00473             (_n##x<(int)((img).width) && (                              \
00474                                           I##ncc=(img)(_n##x,    y,    z,v), \
00475                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
00476                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
00477                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
00478                                           1)) || x==--_n##x;            \
00479             I##ccc=I##ncc, I##cnc=I##nnc,                               \
00480               I##ccn=I##ncn, I##cnn=I##nnn,                             \
00481               x++, _n##x++ )
00482 
00483 #define cimg_map3x3x3(img,x,y,z,v,I) cimg_3mapYZ(img,y,z)               \
00484        for (int _n##x=1, _p##x=(int)(I##cpp=I##ppp=(img)(0,_p##y,_p##z,v), \
00485                                      I##ccp=I##pcp=(img)(0,    y,_p##z,v), \
00486                                      I##cnp=I##pnp=(img)(0,_n##y,_p##z,v), \
00487                                      I##cpc=I##ppc=(img)(0,_p##y,    z,v), \
00488                                      I##ccc=I##pcc=(img)(0,    y,    z,v), \
00489                                      I##cnc=I##pnc=(img)(0,_n##y,    z,v), \
00490                                      I##cpn=I##ppn=(img)(0,_p##y,_n##z,v), \
00491                                      I##ccn=I##pcn=(img)(0,    y,_n##z,v), \
00492                                      I##cnn=I##pnn=(img)(0,_n##y,_n##z,v)),\
00493               x=_p##x=0;                                                \
00494             (_n##x<(int)((img).width) && (                              \
00495                                           I##npp=(img)(_n##x,_p##y,_p##z,v), \
00496                                           I##ncp=(img)(_n##x,    y,_p##z,v), \
00497                                           I##nnp=(img)(_n##x,_n##y,_p##z,v), \
00498                                           I##npc=(img)(_n##x,_p##y,    z,v), \
00499                                           I##ncc=(img)(_n##x,    y,    z,v), \
00500                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
00501                                           I##npn=(img)(_n##x,_p##y,_n##z,v), \
00502                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
00503                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
00504                                           1)) || x==--_n##x;            \
00505             I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp,                \
00506               I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp,              \
00507               I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc,              \
00508               I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc,              \
00509               I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn,              \
00510               I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn,              \
00511               _p##x=x++, _n##x++ )
00512 
00513 /*-------------------------------------------------
00514   -------------------------------------------------
00515 
00516 
00517     Definition of the cimg_library:: namespace
00518 
00519 
00520   -------------------------------------------------
00521   -------------------------------------------------*/
00522 
00524 
00534 namespace cimg_library {
00535   struct CImgStats;
00536   struct CImgDisplay;
00537   struct CImgException;
00538   template<typename T=float> struct CImg;
00539   template<typename T=float> struct CImgl;
00540   template<typename T=float> struct CImgROI;
00541  
00542   namespace cimg {
00543     static int dialog(const char *title,const char *msg,const char *button1_txt="OK",
00544                       const char *button2_txt=NULL,const char *button3_txt=NULL,
00545                       const char *button4_txt=NULL,const char *button5_txt=NULL,
00546                       const char *button6_txt=NULL);
00547   }
00548   
00549   /*----------------------------------------------------
00550     
00551   
00552   
00553   Definition of the CImgException structures
00554   
00555   
00556   
00557   -------------------------------------------------*/
00558 
00559 #define cimg_exception_err(etype,disp_flag)                         \
00560   if (cimg_debug>=1) {                                              \
00561     char tmp[1024];                                                 \
00562     std::va_list ap;                                                \
00563     va_start(ap,format);                                            \
00564     std::vsprintf(message,format,ap);                               \
00565     va_end(ap);                                                     \
00566     std::sprintf(tmp,"==> %s \n\nGeneral : %s\n\n", message,etype); \
00567     if (disp_flag) cimg::dialog("CImg Error",tmp,"Abort");          \
00568     else std::fprintf(stderr,tmp);                                  \
00569   }
00570     
00572 
00607   struct CImgException {
00608     char message[1024]; 
00609     CImgException() { message[0]='\0'; }
00610     CImgException(const char *format,...) {
00611       cimg_exception_err("This error has been generated by a 'CImgException' throw,\n"
00612                          "corresponding to a general exception problem.",true); 
00613     }
00614   };
00615 
00618 
00629   struct CImgInstanceException : CImgException { 
00630     CImgInstanceException(const char *format,...) {
00631       cimg_exception_err("This error has been generated by a 'CImgInstanceException' throw.\n"
00632                          "The instance passed through the function above has a bad structure\n"
00633                          "(perhaps an empty image, list or display object ?)",true);
00634     }};
00635 
00638 
00649   struct CImgArgumentException : CImgException { 
00650     CImgArgumentException(const char *format,...) { 
00651       cimg_exception_err("This error has been generated by a 'CImgArgumentException' throw.\n"
00652                          "At least one argument passed to the function above has been\n"
00653                          "considered as not valid.",true);
00654     }};
00655 
00658 
00668   struct CImgIOException : CImgException { 
00669     CImgIOException(const char *format,...) {
00670       cimg_exception_err("This error has been generated by a 'CImgIOException' throw.\n"
00671                          "When trying to load or save a file, the function above has\n"
00672                          "encountered a problem.",true);
00673     }};
00674 
00677 
00685   struct CImgDisplayException : CImgException {
00686     CImgDisplayException(const char *format,...) {
00687       cimg_exception_err("This error has been generated by a 'CImgDisplayException' throw.\n"
00688                          "When trying to operate on a CImgDisplay instance, the function above\n"
00689                          "has encountered a problem.",false); 
00690     }};
00691   
00692 
00693   /*----------------------------------------
00694     
00695   
00696   
00697     Definition of the namespace 'cimg'
00698   
00699   
00700   
00701   --------------------------------------*/
00702   
00704 
00712   namespace cimg {
00713 
00714     // Define internal library variables.
00715     const unsigned int lblock=1024;
00716 #if cimg_display_type==1
00717     struct X11info {
00718       pthread_mutex_t* mutex;
00719       pthread_t*       event_thread;
00720       CImgDisplay*     wins[1024];
00721       Display*         display;
00722       unsigned int     nb_wins;
00723       bool             thread_finished;
00724       unsigned int     nb_bits;
00725       GC*              gc;
00726       bool             endian;
00727       X11info():mutex(NULL),event_thread(NULL),display(NULL),nb_wins(0),
00728                 thread_finished(false),nb_bits(0),gc(NULL),endian(false) {};
00729     };
00730 #if defined(cimg_module)
00731     X11info& X11attr();
00732 #elif defined(cimg_main)
00733     X11info& X11attr() { static X11info val; return val; }
00734 #else
00735     inline X11info& X11attr() { static X11info val; return val; }
00736 #endif
00737 #endif
00738 #ifdef cimg_color_terminal
00739     const char t_normal[9]  = {0x1b,'[','0',';','0',';','0','m','\0'};
00740     const char t_red[11]    = {0x1b,'[','4',';','3','1',';','5','9','m','\0'};
00741     const char t_bold[5]    = {0x1b,'[','1','m','\0'};
00742     const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'};
00743 #else
00744     const char t_normal[1]  = {'\0'};
00745     static const char *t_red = cimg::t_normal, *t_bold = cimg::t_normal, *t_purple = cimg::t_normal;
00746 #endif
00747     
00748 #if cimg_display_type==1
00749     // Keycodes for X11-based graphical systems
00750     const unsigned int keyESC        = XK_Escape;
00751     const unsigned int keyF1         = XK_F1;
00752     const unsigned int keyF2         = XK_F2;
00753     const unsigned int keyF3         = XK_F3;
00754     const unsigned int keyF4         = XK_F4;
00755     const unsigned int keyF5         = XK_F5;
00756     const unsigned int keyF6         = XK_F6;
00757     const unsigned int keyF7         = XK_F7;
00758     const unsigned int keyF8         = XK_F8;
00759     const unsigned int keyF9         = XK_F9;
00760     const unsigned int keyF10        = XK_F10;
00761     const unsigned int keyF11        = XK_F11;
00762     const unsigned int keyF12        = XK_F12;
00763     const unsigned int keyPAUSE      = XK_Pause;
00764     const unsigned int key1          = XK_1;
00765     const unsigned int key2          = XK_2;
00766     const unsigned int key3          = XK_3;
00767     const unsigned int key4          = XK_4;
00768     const unsigned int key5          = XK_5;
00769     const unsigned int key6          = XK_6;
00770     const unsigned int key7          = XK_7;
00771     const unsigned int key8          = XK_8;
00772     const unsigned int key9          = XK_9;
00773     const unsigned int key0          = XK_0;
00774     const unsigned int keyBACKSPACE  = XK_BackSpace;
00775     const unsigned int keyINSERT     = XK_Insert;
00776     const unsigned int keyHOME       = XK_Home;
00777     const unsigned int keyPAGEUP     = XK_Page_Up;
00778     const unsigned int keyTAB        = XK_Tab;
00779     const unsigned int keyQ          = XK_q;
00780     const unsigned int keyW          = XK_w;
00781     const unsigned int keyE          = XK_e;
00782     const unsigned int keyR          = XK_r;
00783     const unsigned int keyT          = XK_t;
00784     const unsigned int keyY          = XK_y;
00785     const unsigned int keyU          = XK_u;
00786     const unsigned int keyI          = XK_i;
00787     const unsigned int keyO          = XK_o;
00788     const unsigned int keyP          = XK_p;
00789     const unsigned int keyDELETE     = XK_Delete;
00790     const unsigned int keyEND        = XK_End;
00791     const unsigned int keyPAGEDOWN   = XK_Page_Down;
00792     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
00793     const unsigned int keyA          = XK_a;
00794     const unsigned int keyS          = XK_s;
00795     const unsigned int keyD          = XK_d;
00796     const unsigned int keyF          = XK_f;
00797     const unsigned int keyG          = XK_g;
00798     const unsigned int keyH          = XK_h;
00799     const unsigned int keyJ          = XK_j;
00800     const unsigned int keyK          = XK_k;
00801     const unsigned int keyL          = XK_l;
00802     const unsigned int keyENTER      = XK_Return;
00803     const unsigned int keySHIFTLEFT  = XK_Shift_L;
00804     const unsigned int keyZ          = XK_z;
00805     const unsigned int keyX          = XK_x;
00806     const unsigned int keyC          = XK_c;
00807     const unsigned int keyV          = XK_v;
00808     const unsigned int keyB          = XK_b;
00809     const unsigned int keyN          = XK_n;
00810     const unsigned int keyM          = XK_m;
00811     const unsigned int keySHIFTRIGHT = XK_Shift_R;
00812     const unsigned int keyARROWUP    = XK_Up;
00813     const unsigned int keyCTRLLEFT   = XK_Control_L;
00814     const unsigned int keyAPPLEFT    = XK_Super_L;
00815     const unsigned int keySPACE      = XK_space;
00816     const unsigned int keyALTGR      = XK_Alt_R;
00817     const unsigned int keyAPPRIGHT   = XK_Super_R;
00818     const unsigned int keyMENU       = XK_Menu;
00819     const unsigned int keyCTRLRIGHT  = XK_Control_R;
00820     const unsigned int keyARROWLEFT  = XK_Left;
00821     const unsigned int keyARROWDOWN  = XK_Down;
00822     const unsigned int keyARROWRIGHT = XK_Right;  
00823 #endif
00824 
00825 #if cimg_display_type==2 && cimg_OS==2
00826     // Keycodes for Windows-OS
00828 
00829 
00837     const unsigned int keyESC        = 27;
00838     const unsigned int keyF1         = 112;
00839     const unsigned int keyF2         = 113;
00840     const unsigned int keyF3         = 114;
00841     const unsigned int keyF4         = 115;
00842     const unsigned int keyF5         = 116;
00843     const unsigned int keyF6         = 117;
00844     const unsigned int keyF7         = 118;
00845     const unsigned int keyF8         = 119;
00846     const unsigned int keyF9         = 120;
00847     const unsigned int keyF10        = 121;
00848     const unsigned int keyF11        = 122;
00849     const unsigned int keyF12        = 123;
00850     const unsigned int keyPAUSE      = 19;
00851     const unsigned int key1          = 49;
00852     const unsigned int key2          = 50;
00853     const unsigned int key3          = 51;
00854     const unsigned int key4          = 52;
00855     const unsigned int key5          = 53;
00856     const unsigned int key6          = 54;
00857     const unsigned int key7          = 55;
00858     const unsigned int key8          = 56;
00859     const unsigned int key9          = 57;
00860     const unsigned int key0          = 48;
00861     const unsigned int keyBACKSPACE  = 8;
00862     const unsigned int keyINSERT     = 45;
00863     const unsigned int keyHOME       = 36;
00864     const unsigned int keyPAGEUP     = 33;
00865     const unsigned int keyTAB        = 9;
00866     const unsigned int keyQ          = 81;
00867     const unsigned int keyW          = 87;
00868     const unsigned int keyE          = 69;
00869     const unsigned int keyR          = 82;
00870     const unsigned int keyT          = 84;
00871     const unsigned int keyY          = 89;
00872     const unsigned int keyU          = 85;
00873     const unsigned int keyI          = 73;
00874     const unsigned int keyO          = 79;
00875     const unsigned int keyP          = 80;
00876     const unsigned int keyDELETE     = 8;
00877     const unsigned int keyEND        = 35;
00878     const unsigned int keyPAGEDOWN   = 34;
00879     const unsigned int keyCAPSLOCK   = 20;
00880     const unsigned int keyA          = 65;
00881     const unsigned int keyS          = 83;
00882     const unsigned int keyD          = 68;
00883     const unsigned int keyF          = 70;
00884     const unsigned int keyG          = 71;
00885     const unsigned int keyH          = 72;
00886     const unsigned int keyJ          = 74;
00887     const unsigned int keyK          = 75;
00888     const unsigned int keyL          = 76;
00889     const unsigned int keyENTER      = 13;
00890     const unsigned int keySHIFTLEFT  = 16;
00891     const unsigned int keyZ          = 90;
00892     const unsigned int keyX          = 88;
00893     const unsigned int keyC          = 67;
00894     const unsigned int keyV          = 86;
00895     const unsigned int keyB          = 66;
00896     const unsigned int keyN          = 78;
00897     const unsigned int keyM          = 77;
00898     const unsigned int keySHIFTRIGHT = 16;
00899     const unsigned int keyARROWUP    = 38;
00900     const unsigned int keyCTRLLEFT   = 17;
00901     const unsigned int keyAPPLEFT    = 91;
00902     const unsigned int keySPACE      = 32;
00903     const unsigned int keyALTGR      = 17;
00904     const unsigned int keyAPPRIGHT   = 92;
00905     const unsigned int keyMENU       = 93;
00906     const unsigned int keyCTRLRIGHT  = 17;
00907     const unsigned int keyARROWLEFT  = 37;
00908     const unsigned int keyARROWDOWN  = 40;
00909     const unsigned int keyARROWRIGHT = 39;
00910 #endif
00911 
00912 
00913 #ifdef PI
00914 #undef PI
00915 #endif
00916     const double PI = 3.14159265358979323846;   
00917     const int infinity_int  = 0x7f800000;
00918     const double infinity = (double)*(float*)&cimg::infinity_int;
00919     
00920     // Definition of a 10x13 font (used in dialog boxes).
00921     const unsigned int font10x13[256*10*13/8] = {
00922       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00923       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0,
00924       0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00925       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00926       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120,
00927       0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00928       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00929       0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00930       0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
00931       0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
00932       0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
00933       0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
00934       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
00935       0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
00936       0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
00937       0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
00938       0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
00939       0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
00940       0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
00941       0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
00942       0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
00943       0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
00944       0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
00945       0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
00946       0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
00947       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
00948       0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
00949       0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00950       0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
00951       0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
00952       0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
00953       0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
00954       0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
00955       0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
00956       0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
00957       0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
00958       0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
00959       0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
00960       0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00961       0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
00962       0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
00963       0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
00964       0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
00965       0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
00966       0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
00967       0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
00968       0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
00969       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
00970       0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
00971       0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
00972       0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
00973       0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
00974       0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
00975       0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
00976       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
00977       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,
00978       0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
00979       0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0,
00980       0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
00981     };
00982     
00983     // Definition of a 7x11 font, used to return a default font for drawing text.
00984     const unsigned int font7x11[7*11*256/8] = {
00985       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00986       0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
00987       0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
00988       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00989       0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
00990       0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
00991       0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
00992       0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
00993       0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
00994       0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
00995       0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00996       0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
00997       0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00998       0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
00999       0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01000       0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
01001       0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01002       0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
01003       0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01004       0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
01005       0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01006       0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
01007       0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01008       0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
01009       0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
01010       0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
01011       0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
01012       0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
01013       0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
01014       0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
01015       0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
01016       0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
01017       0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
01018       0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
01019       0x400000,0x44,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x62018,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x80000800,
01020       0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
01021       0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
01022     };
01023 
01024     // Definition of a 40x38 'danger' color logo
01025     const unsigned char logo40x38[4576] = {
01026       177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
01027       1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
01028       0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
01029       1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
01030       2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
01031       255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
01032       189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
01033       189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
01034       22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
01035       1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
01036       0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
01037       123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
01038       189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
01039       0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
01040       189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255,
01041       0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123,
01042       123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189,
01043       189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255,
01044       0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189,
01045       189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1,
01046       0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255,
01047       255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123,
01048       123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86,
01049       200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
01050   
01051     // Return a 'stringification' of standart integral types.
01052     const char* const bool_st    = "bool";
01053     const char* const uchar_st   = "unsigned char";
01054     const char* const char_st    = "char";
01055     const char* const ushort_st  = "unsigned short";
01056     const char* const short_st   = "short";
01057     const char* const uint_st    = "unsigned int";
01058     const char* const int_st     = "int";
01059     const char* const ulong_st   = "unsigned long";
01060     const char* const long_st    = "long";
01061     const char* const float_st   = "float";
01062     const char* const double_st  = "double";
01063     const char* const unknown_st = "unknown";
01064     template<typename t> inline const char* get_type(const t&) { return cimg::unknown_st; }
01065     inline const char* get_type(const bool&          ) { return cimg::bool_st;   }
01066     inline const char* get_type(const unsigned char& ) { return cimg::uchar_st;  }
01067     inline const char* get_type(const char&          ) { return cimg::char_st;   }
01068     inline const char* get_type(const unsigned short&) { return cimg::ushort_st; }
01069     inline const char* get_type(const short&         ) { return cimg::short_st;  }
01070     inline const char* get_type(const unsigned int&  ) { return cimg::uint_st;   }
01071     inline const char* get_type(const int&           ) { return cimg::int_st;    }
01072     inline const char* get_type(const unsigned long& ) { return cimg::ulong_st;  }
01073     inline const char* get_type(const long&          ) { return cimg::long_st;   }
01074     inline const char* get_type(const float&         ) { return cimg::float_st;  }
01075     inline const char* get_type(const double&        ) { return cimg::double_st; }
01076     
01078     template<typename t> inline const t get_type_min(const t&) {
01079       static const double p = std::pow(2.0,8.0*sizeof(t)-1.0);
01080       static const t res = (t)(((t)-1)>=0?0:(-p)); 
01081       return res;
01082     }
01083     inline const float get_type_min(const float&)   { return -(float)cimg::infinity; }
01084     inline const double get_type_min(const double&) { return -cimg::infinity; }
01085 
01087     template<typename t> inline const t get_type_max(const t&) {
01088       static const double p = std::pow(2.0,8.0*sizeof(t)-1.0);
01089       static const t res = (t)(((t)-1)>=0?(2*p-1):(p-1));
01090       return res;
01091     }
01092     inline const float get_type_max(const float&)   { return (float)cimg::infinity; }
01093     inline const double get_type_max(const double&) { return cimg::infinity; }
01094                                                                        
01095     // Display a warning message
01096 #if cimg_debug>=1    
01097     static void warn(const bool cond,const char *format,...) {
01098       if (cond) {
01099         std::va_list ap;
01100         va_start(ap,format);
01101         std::fprintf(stderr,"<CImg Warning> ");
01102         std::vfprintf(stderr,format,ap);
01103         std::fputc('\n',stderr);
01104         va_end(ap);
01105       }
01106     }
01107 #else
01108     inline void warn(const bool cond,const char *format,...) {}
01109 #endif
01110 
01111     inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; }
01112     inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); }
01113     inline float atof(const char *str) {
01114       float x=0,y=1;
01115       if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
01116     }
01117     inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; }
01118     inline int strncmp(const char *s1,const char *s2,const int l) {
01119       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=std::abs(s1[k] - s2[k]); return n; }
01120       return 0;
01121     }
01122     inline int strncasecmp(const char *s1,const char *s2,const int l) {
01123       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=std::abs(uncase(s1[k])-uncase(s2[k])); return n; }
01124       return 0;
01125     }
01126     inline int strcmp(const char *s1,const char *s2) { 
01127       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
01128       return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
01129     }
01130     inline int strcasecmp(const char *s1,const char *s2) { 
01131       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
01132       return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
01133     }
01134     inline int strfind(const char *s,const char c) {
01135       if (s) { 
01136         int l; for (l=cimg::strlen(s); l>=0 && s[l]!=c; l--) ;
01137         return l; 
01138       }
01139       return -1; 
01140     }
01141     inline const char* basename(const char *s)  {
01142       return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):NULL):(s?s+1+cimg::strfind(s,'\\'):NULL); 
01143     }
01144 
01145     inline void system(const char *command) {
01146 #if cimg_OS==2
01147       PROCESS_INFORMATION pi;
01148       STARTUPINFO si;
01149       GetStartupInfo(&si);
01150       si.wShowWindow = SW_HIDE;
01151       si.dwFlags |= SW_HIDE;
01152       BOOL res = CreateProcess(NULL,(LPTSTR)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
01153       if (res) {
01154         WaitForSingleObject(pi.hProcess, INFINITE);
01155         CloseHandle(pi.hThread);
01156         CloseHandle(pi.hProcess);
01157       }
01158 #else
01159       std::system(command);
01160 #endif
01161     }
01162     
01164 
01183     inline const char* convert_path() {
01184       static char *convert_path = NULL;
01185       if (!convert_path) {
01186 #if cimg_OS==2 || defined(cimg_convert_path)
01187         bool stopflag = false;
01188         std::FILE *file;
01189 #endif
01190         convert_path = new char[1024];
01191 #ifdef cimg_convert_path
01192         std::strcpy(convert_path,cimg_convert_path);
01193         if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01194 #endif
01195 #if cimg_OS==2
01196         for (unsigned int k=0; k<=9 && !stopflag; k++) {
01197           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u-Q\\convert.exe",k);
01198           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01199         }
01200         if (!stopflag) for (unsigned int k=0; k<=9 && !stopflag; k++) {
01201           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u\\convert.exe",k);
01202           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01203         }
01204         if (!stopflag) std::strcpy(convert_path,"convert.exe");
01205 #else
01206         std::strcpy(convert_path,"convert");
01207 #endif
01208       }
01209       return convert_path;
01210     }
01211     
01213 
01230     inline const char* temporary_path() {
01231       static char *st_temporary_path = NULL;
01232       if (!st_temporary_path) {
01233         st_temporary_path = new char[1024];
01234 #ifdef cimg_temporary_path
01235         std::strcpy(st_temporary_path,cimg_temporary_path);
01236         const char* testing_path[7] = { st_temporary_path, "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
01237 #else
01238         const char* testing_path[6] = { "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
01239 #endif
01240         char filetmp[1024];
01241         std::FILE *file=NULL;
01242         int i=-1;
01243         while (!file && testing_path[++i]) {
01244           std::sprintf(filetmp,"%s/CImg%.4d.ppm",testing_path[i],std::rand()%10000);
01245           if ((file=std::fopen(filetmp,"w"))!=NULL) { std::fclose(file); std::remove(filetmp); }
01246         }
01247         if (!file) 
01248           throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
01249                                 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
01250                                 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
01251         std::strcpy(st_temporary_path,testing_path[i]);
01252       }
01253       return st_temporary_path;
01254     }
01255     
01256     inline const char *filename_split(const char *const filename, char *const body=NULL) {
01257       if (!filename) throw CImgArgumentException("cimg::filename_split() : Can't split the (null) filename");
01258       int l = cimg::strfind(filename,'.');
01259       if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }}
01260       else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; }
01261       return filename+l+1;
01262     }
01263     
01264     inline char* filename_number(const char *filename,const int number,const unsigned int n,char *const string) {
01265       char format[1024],body[1024];
01266       const char *ext = cimg::filename_split(filename,body);
01267       if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
01268       else std::sprintf(format,"%s_%%d.%s",body,ext);
01269       std::sprintf(string,format,number);
01270       return string;
01271     }
01272     inline std::FILE *fopen(const char *const path,const char *const mode) {
01273       if(!path || !mode) throw CImgArgumentException("cimg::fopen() : Can't open file '%s' with mode '%s'",path,mode);
01274       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; else {
01275         std::FILE *dest=std::fopen(path,mode);
01276         if(!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened %s",
01277                                         path,mode[0]=='r'?"for reading":(mode[0]=='w'?"for writing":""),path);
01278         return dest;
01279       }
01280     }
01281     inline int fclose(std::FILE *file) {
01282       warn(!file,"cimg::fclose() : Can't close (null) file");
01283       if (!file || file==stdin || file==stdout) return 0;
01284       const int errn=std::fclose(file);
01285       warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn);
01286       return errn;
01287     }
01288     template<typename T> inline int fread(T *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
01289       if (!ptr || size<=0 || nmemb<=0 || !stream)
01290         throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
01291                                     nmemb,size,stream,ptr);
01292       const unsigned int errn = (unsigned int)std::fread((void*)ptr,size,nmemb,stream);
01293       cimg::warn(errn!=nmemb,"cimg::fread() : File reading problems, only %u/%u elements read",errn,nmemb);
01294       return errn;
01295     }
01296     inline int fwrite(const void *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
01297       if (!ptr || size<=0 || nmemb<=0 || !stream)
01298         throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
01299                                     nmemb,size,stream,ptr);
01300       const unsigned int errn = (unsigned int)std::fwrite(ptr,size,nmemb,stream);
01301       if(errn!=nmemb)
01302         throw CImgIOException("cimg::fwrite() : File writing problems, only %u/%u elements written",errn,nmemb);
01303       return errn;
01304     }
01305     
01306     // Exchange the values of variables \p a and \p b
01307     template<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; }
01308     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2) {
01309       cimg::swap(a1,b1); cimg::swap(a2,b2); 
01310     }
01311     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3) {
01312       cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); 
01313     }
01314     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4) {
01315       cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); 
01316     }
01317     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) {
01318       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); 
01319     }
01320     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) {
01321       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
01322     }
01323     
01324     template<typename T> inline T& endian_swap(T& a) {  
01325       if (sizeof(a)!=1) {
01326         unsigned char *pb=(unsigned char*)&a, *pe=pb+sizeof(a);
01327         for (int i=0; i<(int)sizeof(a)/2; i++) cimg::swap(*(pb++),*(--pe));
01328       }
01329       return a;
01330     }
01331 
01332     template<typename T> inline void endian_swap(T *const buffer,const unsigned int size) {
01333       T *ptr = buffer;
01334       for (unsigned int i=0; i<size; i++) cimg::endian_swap(*(ptr++));
01335     }
01336 
01337     inline const char* option(const char *const name,const unsigned int argc,char **argv,const char *const defaut,
01338                               const char *const usage=NULL) {
01339       static bool first=true, visu=false;
01340       const char *res = NULL;
01341       if (first) { first=false; visu = cimg::option("-h",argc,argv,(const char*)NULL)!=NULL; }
01342       if (!name && visu) {
01343         std::fprintf(stderr,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
01344         if (usage) std::fprintf(stderr," : %s",usage);
01345         std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__);
01346       }
01347       if (name) {
01348         if (argc>0) {
01349           unsigned int k=0,i;
01350           while (k<argc && cimg::strcmp(argv[k],name)) k++;
01351           i=k;
01352           res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
01353         } else res = defaut;
01354         if (visu && usage) std::fprintf(stderr,"    %s%-8s%s = %-12s : %s%s%s\n",
01355                                         cimg::t_bold,name,cimg::t_normal,res?res:"NULL",cimg::t_purple,usage,cimg::t_normal);
01356       }
01357       return res;
01358     }
01359 
01360     inline bool option(const char *const name,const unsigned int argc,char **argv,
01361                        const bool defaut,const char *const usage=NULL) {
01362       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01363       const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
01364       cimg::option(name,0,NULL,res?"true":"false",usage);
01365       return res;
01366     }
01367 
01368     inline int option(const char *const name,const unsigned int argc,char **argv,
01369                       const int defaut,const char *const usage=NULL) {
01370       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01371       const int res = s?std::atoi(s):defaut;
01372       char tmp[256];
01373       std::sprintf(tmp,"%d",res);
01374       cimg::option(name,0,NULL,tmp,usage);
01375       return res;
01376     }
01377 
01378     inline char option(const char *const name,const unsigned int argc,char **argv,
01379                        const char defaut,const char *const usage=NULL) {
01380       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01381       const char res = s?s[0]:defaut;
01382       char tmp[8];
01383       tmp[0] = res;
01384       tmp[1] ='\0';
01385       cimg::option(name,0,NULL,tmp,usage);
01386       return res;
01387     }
01388 
01389     inline double option(const char *const name,const unsigned int argc,char **argv,
01390                          const double defaut,const char *const usage=NULL) {
01391       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01392       const double res = s?cimg::atof(s):defaut;
01393       char tmp[256];
01394       std::sprintf(tmp,"%g",res);
01395       cimg::option(name,0,NULL,tmp,usage);
01396       return res;
01397     }
01398     
01400     inline const bool endian() { const int x=1; return ((unsigned char*)&x)[0]?false:true; }
01401 
01403     inline void info() {
01404       std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n",
01405                    cimg::t_red,cimg_version,cimg::t_normal,__DATE__,__TIME__);
01406       std::fprintf(stderr,"  > Architecture   : %s%-12s%s %s(cimg_OS=%d)\n%s",
01407                    cimg::t_bold,
01408                    cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknown"),
01409                    cimg::t_normal,cimg::t_purple,cimg_OS,cimg::t_normal);
01410       std::fprintf(stderr,"  > Display type   : %s%-12s%s %s(cimg_display_type=%d)%s\n",
01411                    cimg::t_bold,cimg_display_type==0?"No":
01412                    (cimg_display_type==1?"X11":
01413                     (cimg_display_type==2?"WindowsGDI":
01414                      "Unknown")),
01415                    cimg::t_normal,cimg::t_purple,cimg_display_type,cimg::t_normal);
01416 #ifdef cimg_color_terminal
01417       std::fprintf(stderr,"  > Color terminal : %s%-12s%s %s(cimg_color_terminal defined)%s\n",
01418                    cimg::t_bold,"Yes",cimg::t_normal,cimg::t_purple,cimg::t_normal);
01419 #else
01420       std::fprintf(stderr,"  > Color terminal : %-12s (cimg_color_terminal undefined)\n","No");
01421 #endif
01422       std::fprintf(stderr,"  > Debug messages : %s%-12s%s %s(cimg_debug=%d)%s\n",cimg::t_bold,
01423                    cimg_debug==2?"High":(cimg_debug==1?"Yes":"No"),
01424                    cimg::t_normal,cimg::t_purple,cimg_debug,cimg::t_normal);
01425       std::fprintf(stderr,"\n");
01426     }
01427     
01429     inline long time() {
01430 #if cimg_OS==1
01431       struct timeval st_time;
01432       gettimeofday(&st_time,NULL);
01433       return (long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
01434 #elif cimg_OS==2
01435       static SYSTEMTIME st_time;
01436       GetSystemTime(&st_time);
01437       return (long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
01438 #else 
01439       return 0;
01440 #endif
01441     }
01442 
01444 
01449     inline void sleep(const int milliseconds) {
01450 #if cimg_OS==1
01451       struct timespec tv;
01452       tv.tv_sec = milliseconds/1000;
01453       tv.tv_nsec = (milliseconds%1000)*1000000;
01454       nanosleep(&tv,NULL);
01455 #elif cimg_OS==2
01456       Sleep(milliseconds);
01457 #endif
01458     }
01459 
01461 
01466     inline long wait(const int milliseconds=20,long reference_time=-1) {
01467       static long latest_time = cimg::time();
01468       if (reference_time>=0) latest_time = reference_time;
01469       const long current_time = cimg::time(), time_diff = milliseconds + latest_time - current_time;
01470       if (time_diff>0) { cimg::sleep(time_diff); return (latest_time = current_time + time_diff); }
01471       else return (latest_time = current_time);
01472     }
01473 
01475     template<typename T> inline const T rol(const T& a,const unsigned int n=1) { return (a<<n)|(a>>((sizeof(T)<<3)-n)); }
01477     template<typename T> inline const T ror(const T& a,const unsigned int n=1) { return (a>>n)|(a<<((sizeof(T)<<3)-n)); }
01478 
01479 #if ( !defined(_MSC_VER) || _MSC_VER>1200 )
01480 
01481     template<typename T> inline const T abs(const T& a) { return a>=0?a:-a; }
01482     inline const double abs(const double& a) { return std::fabs(a); }
01483     inline const float abs(const float& a)   { return (float)std::fabs((double)a); }
01484     inline const int abs(const int& a)       { return std::abs(a); }
01485     
01487     template<typename T> inline const T& min(const T& a,const T& b) { return a<=b?a:b; }
01489     template<typename T> inline const T& min(const T& a,const T& b,const T& c) { return cimg::min(cimg::min(a,b),c); }
01491     template<typename T> inline const T& min(const T& a,const T& b,const T& c,const T& d) { return cimg::min(cimg::min(a,b,c),d); }
01493     template<typename T> inline const T& max(const T& a,const T& b) { return a>=b?a:b; }
01495     template<typename T> inline const T& max(const T& a,const T& b,const T& c) { return cimg::max(cimg::max(a,b),c); }
01497     template<typename T> inline const T& max(const T& a,const T& b,const T& c,const T& d) { return cimg::max(cimg::max(a,b,c),d); }
01499     template<typename T> inline char sign(const T& x) { return (x<0)?-1:(x==0?0:1); }
01500 #else
01501     // Special versions due to object reference bug in VisualC++ 6.0.
01502     template<typename T> inline const T abs(const T a) { return a>=0?a:-a; }
01503     template<typename T> inline const T min(const T a,const T b) { return a<=b?a:b; }
01504     template<typename T> inline const T min(const T a,const T b,const T c) { return cimg::min(cimg::min(a,b),c); }
01505     template<typename T> inline const T min(const T a,const T b,const T c,const T& d) { return cimg::min(cimg::min(a,b,c),d); }
01506     template<typename T> inline const T max(const T a,const T b) { return a>=b?a:b; }
01507     template<typename T> inline const T max(const T a,const T b,const T c) { return cimg::max(cimg::max(a,b),c); }
01508     template<typename T> inline const T max(const T a,const T b,const T c,const T& d) { return cimg::max(cimg::max(a,b,c),d); }
01509     template<typename T> inline char sign(const T x) { return (x<0)?-1:(x==0?0:1); }
01510 #endif
01511 
01513 
01516     inline double mod(const double& x,const double& m) { return x-m*std::floor(x/m); }
01517     inline float  mod(const float& x,const float& m)   { return (float)(x-m*std::floor((double)x/m)); }
01518     inline int    mod(const int x,const int m)         { return x>=0?x%m:(x%m?m+x%m:0); }
01519 
01521 
01526     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)); }
01528     inline double rand() { return (double)std::rand()/RAND_MAX; }
01530     inline double crand() { return 1-2*cimg::rand(); }
01532     inline double grand() {
01533       return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*cimg::rand())))*std::cos((double)(2*PI*cimg::rand())); 
01534     }
01535 
01536     // Return (a^2+b^2)^0.5
01537     inline double pythagore(double a, double b) {
01538       const double absa = cimg::abs(a), absb = cimg::abs(b);
01539       if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
01540       else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
01541     }
01542   }
01543 
01544   /*-------------------------------------------------------
01545     
01546   
01547   
01548   
01549     Definition of the CImgStats structure
01550   
01551   
01552   
01553     
01554     ------------------------------------------------------*/
01556 
01570   struct CImgStats {
01571     double min;                 
01572     double max;                 
01573     double mean;                
01574     double variance;            
01575     int xmin;                   
01576     int ymin;                   
01577     int zmin;                   
01578     int vmin;                   
01579     int lmin;                   
01580     int xmax;                   
01581     int ymax;                   
01582     int zmax;                   
01583     int vmax;                   
01584     int lmax;                   
01585 
01587     CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1),
01588                 xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {}
01590     CImgStats(const CImgStats& stats):min(stats.min),max(stats.max),mean(stats.mean),variance(stats.variance),
01591                                       xmin(stats.xmin),ymin(stats.ymin),zmin(stats.zmin),vmin(stats.vmin),lmin(stats.lmin),
01592                                       xmax(stats.xmax),ymax(stats.ymax),zmax(stats.zmax),vmax(stats.vmax),lmax(stats.lmax) {};
01593 
01595 
01598     template<typename T> CImgStats(const CImg<T>& img,const bool compute_variance=true):mean(0),variance(0),lmin(-1),lmax(-1) {
01599       cimg_test(img,"CImgStats::CImgStats");
01600       T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin;
01601       cimg_map(img,ptr,T) {
01602         const T& a=*ptr;
01603         mean+=(double)a;
01604         if (a<pmin) { pmin=a; ptrmin = ptr; }
01605         if (a>pmax) { pmax=a; ptrmax = ptr; }
01606       }
01607       mean/=img.size();
01608       min=(double)pmin;
01609       max=(double)pmax;
01610       unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data);
01611       const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height;      
01612       vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.width; xmin = offmin%img.width;
01613       vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.width; xmax = offmax%img.width;
01614       if (compute_variance) {
01615         cimg_map(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
01616         variance/=img.size();
01617       }
01618     }
01619 
01621 
01625     template<typename T> CImgStats(const CImgl<T>& list,const bool compute_variance=true):mean(0),variance(0) {
01626       cimgl_test(list,"CImgStats::CImgStats");
01627       T pmin=list[0][0], pmax=pmin, *ptrmin=list[0].data, *ptrmax=ptrmin;
01628       int psize=0;
01629       cimgl_map(list,l) {
01630         cimg_map(list[l],ptr,T) {
01631           const T& a=*ptr;
01632           mean+=(double)a;
01633           if (a<pmin) { pmin=a; ptrmin = ptr; lmin = l; }
01634           if (a>pmax) { pmax=a; ptrmax = ptr; lmax = l; }
01635         }
01636         psize+=list[l].size();
01637       }
01638       mean/=psize;
01639       min=(double)pmin;
01640       max=(double)pmax;
01641       const CImg<T> &imin = list[lmin], &imax = list[lmax];
01642       unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data);
01643       const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height;
01644       vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.width; xmin = offmin%imin.width;
01645       const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height;
01646       vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.width; xmax = offmax%imax.width;
01647       if (compute_variance) {
01648         cimgl_map(list,l) cimg_map(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
01649         variance/=psize;
01650       }
01651     }
01652 
01654     CImgStats& operator=(const CImgStats stats) {
01655       min = stats.min;
01656       max = stats.max;
01657       mean = stats.mean;
01658       variance = stats.variance;
01659       xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin;
01660       xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax;
01661       return *this;
01662     }
01664     const CImgStats& print(const char* title=NULL) const {
01665       if (lmin>=0 && lmax>=0)
01666         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
01667                      "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n",
01668                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
01669                      lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax);
01670       else
01671         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
01672                      "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n",
01673                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
01674                      xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax);
01675       return *this;
01676     }
01677     
01678 #ifdef cimgstats_plugin
01679 #include cimgstats_plugin
01680 #endif
01681 
01682   };
01683 
01684   /*-------------------------------------------------------
01685   
01686 
01687 
01688 
01689     Definition of the CImgDisplay structure
01690 
01691 
01692 
01693 
01694   ------------------------------------------------------*/
01695 
01697 
01705   struct CImgDisplay {
01706 
01707     //------------------------
01708     //
01709     // CImgDisplay variables
01710     //
01711     //------------------------
01712 
01714 
01727     unsigned int width;
01728 
01730 
01743     unsigned int height;
01744 
01746 
01752     volatile unsigned int window_width;
01753 
01755 
01761     volatile unsigned int window_height;
01762 
01764     volatile int window_x;
01765 
01767     volatile int window_y;
01768 
01770 
01780     unsigned int normalization;
01781 
01783 
01794     unsigned int events;
01795 
01797 
01802     const bool fullscreen;
01803 
01805 
01813     volatile int mouse_x;
01814 
01816 
01824     volatile int mouse_y;
01825 
01828 
01843     volatile unsigned int button;
01844 
01846 
01871     volatile unsigned int key;
01872 
01874 
01897     volatile bool closed;
01898 
01900     volatile bool resized;
01901     volatile bool moved;
01902 
01903     // Not documented, internal use only.
01904     double min,max;
01905 
01906     //------------------------
01907     //
01908     // CImgDisplay functions
01909     //
01910     //------------------------
01911 
01913 
01919     const int dimx() const { return (int)width; }
01920 
01922 
01928     const int dimy() const { return (int)height; }
01929 
01930     const int window_dimx() const { return (int)window_width; }
01931     const int window_dimy() const { return (int)window_height; }    
01932 
01933     // operator=(). It is actually defined to avoid its use, and throw a CImgDisplay exception.
01934     CImgDisplay& operator=(const CImgDisplay&) {
01935       throw CImgDisplayException("CImgDisplay()::operator=() : Assignement of CImgDisplay is not allowed. Use pointers instead !");
01936       return *this;
01937     }
01938     
01940 
01942       const CImgDisplay& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; }
01943 
01945 
01954     template<typename T> CImgDisplay& display(const CImgl<T>& list,const char axe='x',const char align='c') { 
01955       return display(list.get_append(axe,align)); 
01956     } 
01957 
01959 
01967     template<typename T> CImgDisplay& resize(const CImg<T>& img,const bool redraw=false,const bool force=true) { 
01968       return resize(img.width,img.height,redraw,force); 
01969     }
01970 
01971     CImgDisplay& resize(const CImgDisplay& disp,const bool redraw=false,const bool force=true) {
01972       return resize(disp.width,disp.height,redraw,force);
01973     }
01974 
01975     CImgDisplay& resize(const bool redraw=false,const bool force=false) {
01976       resize(window_width,window_height,redraw,force);
01977       return *this;
01978     }
01979 
01980     // When no display available
01981     //---------------------------
01982 #if cimg_display_type==0
01983     void nodisplay_available() {
01984       static bool first = true;
01985       if (first) {
01986         cimg::warn(true,"CImgDisplay() : Display has been required but is not available (cimg_display_type=0)");
01987         first = false;
01988       }    
01989     }  
01991 
02000     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
02001                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02002                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
02003       nodisplay_available(); 
02004     }
02005 
02007 
02014     template<typename T> 
02015     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02016                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02017                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
02018       nodisplay_available(); 
02019     }
02020     
02022 
02029     template<typename T> 
02030     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02031                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02032                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
02033       nodisplay_available(); 
02034     }
02035   
02037 
02040     CImgDisplay(const CImgDisplay& win, char *title=NULL):fullscreen(false) { nodisplay_available(); }
02041 
02043     CImgDisplay& resize(const int width, const int height,const bool redraw=false,const bool force=true) {
02044       return *this; 
02045     }
02047     CImgDisplay& move(const int posx,const int posy) { return *this; }
02048 
02050     ~CImgDisplay() {}
02052     template<typename T> void render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {}
02054     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=-1) { return *this; }
02056     CImgDisplay& wait()  { return *this; }
02058     CImgDisplay& show()  { return *this; }
02060     CImgDisplay& close() { return *this; }
02061   
02063     static const int screen_dimx() { return 0; }
02064 
02066     static const int screen_dimy() { return 0; }
02067 
02068     // X11-based display
02069     //------------------
02070 #elif cimg_display_type==1
02071     void *data;
02072     Window window;
02073     XImage *image;
02074  
02075     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
02076                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02077                 const bool fullscreen_flag=false,const bool closed_flag=false):
02078       width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3),
02079       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02080       if (!dimw || !dimh) throw CImgArgumentException("CImgDisplay::CImgDisplay() : null size specified");
02081       new_lowlevel(title);
02082       std::memset(data,0,(cimg::X11attr().nb_bits>16?sizeof(unsigned int):sizeof(unsigned short))*width*height);
02083       pthread_mutex_lock(cimg::X11attr().mutex);
02084       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02085       XFlush(cimg::X11attr().display);
02086       pthread_mutex_unlock(cimg::X11attr().mutex);
02087     }
02088 
02089     template<typename T> 
02090     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02091                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02092                 const bool fullscreen_flag=false,const bool closed_flag=false):
02093       normalization(normalization_type&3),events(events_type&3),
02094       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02095       cimg_test(img,"CImgDisplay::CImgDisplay");
02096       CImg<T> tmp;
02097       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
02098       width  = nimg.width;
02099       height = nimg.height;
02100       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02101       new_lowlevel(title);
02102       display(nimg);
02103     }
02104 
02105     template<typename T> 
02106     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02107                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02108                 const bool fullscreen_flag=false,const bool closed_flag=false):
02109       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
02110       closed(closed_flag),min(0),max(0) {
02111       cimgl_test(list,"CImgDisplay::CImgDisplay");
02112       CImg<T> tmp;
02113       const CImg<T> 
02114         img0 = list.get_append('x'), 
02115         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
02116       width  = img.width; 
02117       height = img.height;
02118       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02119       new_lowlevel(title);
02120       display(img);
02121     }
02122 
02123     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
02124       width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3),
02125       fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) {
02126       new_lowlevel(title);
02127       std::memcpy(data,win.data,(cimg::X11attr().nb_bits>16?sizeof(unsigned int):sizeof(short))*width*height);
02128       pthread_mutex_lock(cimg::X11attr().mutex);
02129       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02130       XFlush(cimg::X11attr().display);
02131       pthread_mutex_unlock(cimg::X11attr().mutex);
02132     }
02133 
02134     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
02135       const unsigned int
02136         dimx=(nwidth>0)?nwidth:(-width*nwidth/100),
02137         dimy=(nheight>0)?nheight:(-height*nheight/100);
02138       if (!dimx || !dimy) return *this;
02139       pthread_mutex_lock(cimg::X11attr().mutex);
02140       if (dimx!=width || dimy!=height) {
02141         if (cimg::X11attr().nb_bits>16) {
02142           unsigned int *ndata = new unsigned int[dimx*dimy];
02143           if (redraw) for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
02144             ndata[x+y*dimx] = ((unsigned int*)data)[x*width/dimx + width*(y*height/dimy)];
02145           else std::memset(ndata,0,sizeof(unsigned int)*dimx*dimy);
02146           data = (void*)ndata;
02147         } else {
02148           unsigned short *ndata = new unsigned short[dimx*dimy];
02149           if (redraw) for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
02150             ndata[x+y*dimx] = ((unsigned short*)data)[x*width/dimx + width*(y*height/dimy)];
02151           else std::memset(ndata,0,sizeof(unsigned short)*dimx*dimy);
02152           data = (void*)ndata;
02153         }
02154         XDestroyImage(image);
02155         image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02156                              cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,dimx,dimy,8,0);
02157       }
02158       width  = dimx;
02159       height = dimy;
02160       if (force && (window_width!=width || window_height!=height)) {
02161         XResizeWindow(cimg::X11attr().display,window,width,height);
02162         window_width = width;
02163         window_height = height;
02164       }
02165       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02166       XFlush(cimg::X11attr().display);
02167       resized = false;
02168       pthread_mutex_unlock(cimg::X11attr().mutex);
02169       return *this;
02170     }
02171   
02172     CImgDisplay& move(const int posx,const int posy) {
02173       pthread_mutex_lock(cimg::X11attr().mutex);
02174       window_x = posx;
02175       window_y = posy;
02176       XMoveWindow(cimg::X11attr().display,window,posx,posy);
02177       XFlush(cimg::X11attr().display);
02178       moved = false;
02179       pthread_mutex_unlock(cimg::X11attr().mutex);
02180       return *this;
02181     }
02182     
02183     ~CImgDisplay() {
02184       unsigned int i;
02185       pthread_mutex_lock(cimg::X11attr().mutex);
02186       for (i=0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; i++) i++;
02187       for (; i<cimg::X11attr().nb_wins-1; i++) cimg::X11attr().wins[i]=cimg::X11attr().wins[i+1];
02188       cimg::X11attr().nb_wins--;
02189       XDestroyWindow(cimg::X11attr().display,window);
02190       XDestroyImage(image);
02191       if (!cimg::X11attr().nb_wins) {
02192         pthread_cancel(*cimg::X11attr().event_thread);
02193         pthread_join(*cimg::X11attr().event_thread,NULL);
02194         XCloseDisplay(cimg::X11attr().display);
02195         cimg::X11attr().display=NULL;
02196         pthread_mutex_unlock(cimg::X11attr().mutex);
02197         pthread_mutex_destroy(cimg::X11attr().mutex);
02198         delete cimg::X11attr().event_thread;
02199         delete cimg::X11attr().mutex;
02200         delete cimg::X11attr().gc;
02201       } else pthread_mutex_unlock(cimg::X11attr().mutex);
02202     }
02203   
02204     void new_lowlevel(const char *title=NULL) {
02205       cimg::warn(fullscreen,"CImgDisplay::new_lowlevel() : Fullscreen mode requested, "
02206                  "but not supported on X11 Displays");
02207       if (!cimg::X11attr().display) { // Open X11 Display if not already done.
02208         cimg::X11attr().nb_wins = 0;
02209         cimg::X11attr().thread_finished = false;
02210         cimg::X11attr().mutex = new pthread_mutex_t;
02211         pthread_mutex_init(cimg::X11attr().mutex,NULL);
02212         pthread_mutex_lock(cimg::X11attr().mutex);
02213         cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02214         if (!cimg::X11attr().display) throw CImgDisplayException("CImgDisplay::new_lowlevel() : Can't open X11 display");
02215         cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
02216         if (cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24)
02217           throw CImgDisplayException("CImgDisplay::new_lowlevel() : %u bits mode is not supported "
02218                                      "(only 16 and 24 bits are supported)",cimg::X11attr().nb_bits);
02219         cimg::X11attr().gc = new GC;
02220         *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02221         Visual *visual = DefaultVisual(cimg::X11attr().display,0);
02222         XVisualInfo vtemplate;
02223         vtemplate.visualid = XVisualIDFromVisual(visual);
02224         int nb_visuals;
02225         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
02226         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().endian = true;
02227         cimg::X11attr().event_thread = new pthread_t;
02228         pthread_create(cimg::X11attr().event_thread,NULL,thread_lowlevel,NULL);
02229       } else pthread_mutex_lock(cimg::X11attr().mutex);
02230       
02231       // Create display window and image data.
02232       window = XCreateSimpleWindow(cimg::X11attr().display,RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02233                                      0,0,width,height,2,0,0x0L);
02234       if (cimg::X11attr().nb_bits>16) data = new unsigned int[width*height]; else data = new unsigned short[width*height];
02235       image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02236                              cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);      
02237       XStoreName(cimg::X11attr().display,window,title?title:"");
02238       if (!closed) {
02239         XEvent event;
02240         XSelectInput(cimg::X11attr().display,window,StructureNotifyMask);
02241         XMapWindow(cimg::X11attr().display,window);
02242         do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event); while (event.type!=MapNotify);
02243         XWindowAttributes attr;
02244         XGetWindowAttributes(cimg::X11attr().display,window,&attr);
02245         window_x = attr.x;
02246         window_y = attr.y;
02247       } else window_x = window_y = 0;
02248       if (events) { 
02249         Atom atom = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False); 
02250         XSetWMProtocols(cimg::X11attr().display, window, &atom, 1); 
02251       }
02252       window_width = width;
02253       window_height = height;
02254       mouse_x = mouse_y = -1;
02255       button = key = 0;
02256       resized = moved = false;
02257       cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
02258       pthread_mutex_unlock(cimg::X11attr().mutex);
02259     }
02260   
02261     void proc_lowlevel(XEvent *pevent) {
02262       const unsigned int buttoncode[3] = { 1,4,2 };
02263       XEvent event=*pevent;
02264       switch (event.type) {
02265       case ClientMessage:
02266         XUnmapWindow(cimg::X11attr().display,window);
02267         mouse_x=mouse_y=-1; 
02268         button=key=0;
02269         closed=true; 
02270         break;
02271      case ConfigureNotify: {
02272         while (::XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event));
02273         const unsigned int
02274           nw = event.xconfigure.width,
02275           nh = event.xconfigure.height;
02276         const int
02277           nx = event.xconfigure.x,
02278           ny = event.xconfigure.y;
02279         if (nw && nh && (nw!=window_width || nh!=window_height)) { 
02280           window_width = nw; 
02281           window_height = nh; 
02282           mouse_x = mouse_y = -1;
02283           XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
02284           resized = true;
02285         }
02286         if (nx!=window_x || ny!=window_y) {
02287           window_x = nx;
02288           window_y = ny;
02289           moved = true;
02290         }
02291       } break;
02292       case Expose:
02293         while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event));
02294         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02295         break;
02296       case ButtonPress:
02297         while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
02298         button |= buttoncode[event.xbutton.button-1];
02299         break;
02300       case ButtonRelease:
02301         while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
02302         button &= ~buttoncode[event.xbutton.button-1];
02303         break;
02304       case KeyPress: {
02305         while (XCheckWindowEvent(cimg::X11attr().display,window,KeyPressMask,&event));
02306         char tmp;
02307         KeySym ksym;
02308         XLookupString(&event.xkey,&tmp,1,&ksym,NULL);
02309         key = (unsigned int)ksym;
02310       }
02311         break;
02312       case KeyRelease:
02313         while (XCheckWindowEvent(cimg::X11attr().display,window,KeyReleaseMask,&event));
02314         key = 0;
02315         break;
02316       case LeaveNotify:
02317         while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event));
02318         mouse_x = mouse_y =-1; 
02319         break;
02320       case MotionNotify:
02321         while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event));
02322         mouse_x = event.xmotion.x; 
02323         mouse_y = event.xmotion.y;
02324         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x=mouse_y=-1; 
02325         break;
02326       }
02327     }
02328   
02329     static void* thread_lowlevel(void *arg) {
02330       XEvent event;
02331       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
02332       for (;;) {
02333         pthread_mutex_lock(cimg::X11attr().mutex);
02334         for (unsigned int i=0; i<cimg::X11attr().nb_wins; i++) {
02335           const unsigned int xevent_type = (cimg::X11attr().wins[i]->events)&3;
02336           const unsigned int emask =
02337             ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
02338             ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
02339             ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
02340           XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask);
02341         }
02342         bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
02343         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
02344                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
02345                                                       KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
02346                                                       KeyReleaseMask,&event);
02347         if (event_flag) {
02348           for (unsigned int i=0; i<cimg::X11attr().nb_wins; i++)
02349             if (!cimg::X11attr().wins[i]->closed && event.xany.window==cimg::X11attr().wins[i]->window)
02350               cimg::X11attr().wins[i]->proc_lowlevel(&event);
02351           cimg::X11attr().thread_finished = true;
02352         }
02353         pthread_mutex_unlock(cimg::X11attr().mutex);
02354         cimg::wait(25);
02355       }
02356       return NULL;
02357     }
02358 
02359     template<typename T> XImage* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
02360       cimg_test(img,"CImgDisplay::render");
02361       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),0,~0);
02362       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),0,~0);
02363       const bool by = (ymin<=ymax);
02364       const unsigned int 
02365         nymin = (by?ymin:ymax),
02366         nymax = (by?(ymax<height?ymax:height-1):(ymin<height?ymin:height-1)),
02367         xymax = (nymax+1)*width;
02368       const T 
02369         *data1 = img.ptr(0,nymin,0,0),
02370         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
02371         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
02372       if (cimg::X11attr().endian) cimg::swap(data1,data3);
02373       pthread_mutex_lock(cimg::X11attr().mutex);
02374       if (!normalization) {
02375         switch (cimg::X11attr().nb_bits) {
02376         case 16: {
02377           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02378             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
02379             XPutPixel(image,xy,0,((R>>3)<<11) | ((G>>2)<<5) | (B>>3));
02380           }
02381         } break;
02382         case 24: {
02383           for (unsigned int xy=nymin*width; xy<xymax; xy++) {       
02384             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
02385             XPutPixel(image,xy,0,(R<<16) | (G<<8) | B);
02386           }
02387         } break;
02388         };
02389       } else {
02390         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
02391         const T nmin = (T)min, delta = (T)max-nmin, mm=delta?delta:(T)1;
02392         switch (cimg::X11attr().nb_bits) {
02393         case 16: {
02394           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02395             const unsigned char
02396               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02397               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02398               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02399             XPutPixel(image,xy,0,((R>>3)<<11) | ((G>>2)<<5) | (B>>3));
02400           }
02401         } break;
02402         case 24: {
02403           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02404             const unsigned char
02405               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02406               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02407               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02408             XPutPixel(image,xy,0,(R<<16) | (G<<8) | B);
02409           } 
02410         } break;
02411         } 
02412       }
02413       pthread_mutex_unlock(cimg::X11attr().mutex);
02414       return image;
02415     }
02416     
02417     template<typename T> CImgDisplay& display(const CImg<T>& pimg,const unsigned int pymin=0,const unsigned int pymax=~0) {
02418       const unsigned int
02419         ymin = pymin<pymax?pymin:pymax,
02420         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
02421       render(pimg,ymin,ymax);
02422       if (!closed) {      
02423         pthread_mutex_lock(cimg::X11attr().mutex);
02424         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,ymin,0,ymin,width,ymax-ymin+1);
02425         XFlush(cimg::X11attr().display);
02426         pthread_mutex_unlock(cimg::X11attr().mutex);
02427       }
02428       return *this;
02429     }
02430   
02431     CImgDisplay& wait() {
02432       if (!closed && events) {
02433         XEvent event;
02434         do {
02435           pthread_mutex_lock(cimg::X11attr().mutex);
02436           const unsigned int 
02437             emask = ExposureMask|StructureNotifyMask|
02438             ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
02439             ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0);
02440           XSelectInput(cimg::X11attr().display,window,emask);
02441           XPeekEvent(cimg::X11attr().display,&event);
02442           cimg::X11attr().thread_finished = false;
02443           pthread_mutex_unlock(cimg::X11attr().mutex);
02444         } while (event.xany.window!=window);
02445         while (!cimg::X11attr().thread_finished) cimg::wait(25);
02446       }
02447       return *this;
02448     }
02449 
02450     CImgDisplay& show() {
02451       if (closed) {
02452         pthread_mutex_lock(cimg::X11attr().mutex);
02453         XEvent event;
02454         XSelectInput(cimg::X11attr().display,window,StructureNotifyMask);
02455         XMapWindow(cimg::X11attr().display,window);
02456         do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event);
02457         while (event.type!=MapNotify);
02458         XWindowAttributes attr;
02459         XGetWindowAttributes(cimg::X11attr().display,window,&attr);
02460         window_x = attr.x;
02461         window_y = attr.y;
02462         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02463         XFlush(cimg::X11attr().display);
02464         closed = false;
02465         pthread_mutex_unlock(cimg::X11attr().mutex);
02466       }
02467       return *this;
02468     }
02469     CImgDisplay& close() {
02470       if (!closed) {
02471         pthread_mutex_lock(cimg::X11attr().mutex);
02472         XUnmapWindow(cimg::X11attr().display,window);
02473         XFlush(cimg::X11attr().display);
02474         closed = true;
02475         window_x = window_y = 0;        
02476         pthread_mutex_unlock(cimg::X11attr().mutex);
02477       }
02478       return *this;
02479     }
02480 
02481     static const int screen_dimx() { 
02482       int res = 0;
02483       if (!cimg::X11attr().display) {
02484         Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02485         if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display");
02486         res = DisplayWidth(disp,DefaultScreen(disp));
02487         XCloseDisplay(disp);
02488       } else res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02489       return res;
02490     }
02491 
02492     static const int screen_dimy() { 
02493       int res = 0;
02494       if (!cimg::X11attr().display) {
02495         Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02496         if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display");
02497         res = DisplayHeight(disp,DefaultScreen(disp));
02498         XCloseDisplay(disp);
02499       } else res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02500       return res;
02501     }
02502 
02503     // Windows-based display
02504     //-----------------------
02505 #elif cimg_display_type==2
02506     CLIENTCREATESTRUCT ccs;
02507     BITMAPINFO bmi;
02508     unsigned int *data;
02509     DEVMODE curr_mode;
02510     HWND window;
02511     HDC hdc;
02512     HANDLE thread;
02513     HANDLE wait_disp;
02514     HANDLE created;
02515     HANDLE mutex;
02516 
02517     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
02518                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02519                 const bool fullscreen_flag=false,const bool closed_flag=false):
02520       width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3),
02521       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02522       if (!dimw || !dimh) throw CImgArgumentException("CImgDisplay::CImgDisplay() : null size specified. ");
02523       new_lowlevel(title);
02524       std::memset(data,0,sizeof(unsigned int)*width*height);
02525       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02526     }
02527 
02528     template<typename T> 
02529     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02530                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02531                 const bool fullscreen_flag=false,const bool closed_flag=false):
02532       normalization(normalization_type&3),events(events_type&3),
02533       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02534       cimg_test(img,"CImgDisplay::CImgDisplay");
02535       CImg<T> tmp;
02536       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
02537       width  = nimg.width;
02538       height = nimg.height;
02539       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02540       new_lowlevel(title);
02541       display(nimg);
02542     }
02543 
02544     template<typename T>
02545     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02546                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02547                 const bool fullscreen_flag=false,const bool closed_flag=false):
02548       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
02549       closed(closed_flag),min(0),max(0) {
02550       cimgl_test(list,"CImgDisplay::CImgDisplay");
02551       CImg<T> tmp;
02552       const CImg<T>
02553         img0 = list.get_append('x'),
02554         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
02555       width  = img.width;
02556       height = img.height;
02557       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02558       new_lowlevel(title);
02559       display(img);
02560     }
02561 
02562     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
02563       width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3),
02564       fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) {
02565       new_lowlevel(title);
02566       std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
02567       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02568     }
02569 
02570     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
02571       const unsigned int
02572         dimx=(nwidth>0)?nwidth:(-nwidth*width/100),
02573         dimy=(nheight>0)?nheight:(-nheight*height/100);
02574       if (!dimx || !dimy) return *this;
02575       if (dimx!=width || dimy!=height) {
02576         unsigned int *ndata = new unsigned int[dimx*dimy];
02577         if (redraw) 
02578           for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
02579             ndata[x+y*dimx] = data[x*width/dimx + width*(y*height/dimy)];
02580         else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
02581         delete[] data;
02582         data = ndata;
02583         bmi.bmiHeader.biWidth=dimx;
02584         bmi.bmiHeader.biHeight=-(int)dimy;
02585       }
02586       width  = dimx;
02587       height = dimy;
02588       if (force && (window_width!=width || window_height!=height)) {
02589         RECT rect; rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02590         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02591         const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
02592         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
02593         window_width  = width;
02594         window_height = height;
02595       }
02596       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02597       resized = false;
02598       return *this;
02599     }
02600     
02601     CImgDisplay& move(const int posx,const int posy) {
02602       RECT rect; rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02603       AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02604       const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
02605       window_x = posx;
02606       window_y = posy;
02607       SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
02608       moved = false;
02609       return *this;
02610     }
02611 
02612     ~CImgDisplay() {
02613       DestroyWindow(window);
02614       if (events) TerminateThread(thread,0);
02615       delete[] data;
02616       if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
02617     }
02618   
02619     void new_lowlevel(const char *title=NULL) {
02620       unsigned long ThreadID;
02621       DEVMODE mode;
02622       unsigned int imode=0,ibest=0,bestbpp=0;
02623       void *arg = (void*)(new void*[2]);
02624       ((void**)arg)[0]=(void*)this;
02625       ((void**)arg)[1]=(void*)title;
02626       if (fullscreen) {
02627         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(NULL,imode,&mode); imode++)
02628           if (mode.dmPelsWidth==width && mode.dmPelsHeight==height && mode.dmBitsPerPel>bestbpp) {
02629             bestbpp = mode.dmBitsPerPel;
02630             ibest=imode; 
02631           }
02632         cimg::warn(!bestbpp,"CImgDisplay::new_lowlevel() : Could not initialize fullscreen mode %ux%u\n",width,height);
02633         if (bestbpp) {
02634           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
02635           EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&curr_mode);
02636           EnumDisplaySettings(NULL,ibest,&mode);
02637           ChangeDisplaySettings(&mode,0);
02638         }
02639         else curr_mode.dmSize = 0;
02640       }
02641       else curr_mode.dmSize = 0;
02642       if (events) {
02643         mutex     = CreateMutex(NULL,FALSE,NULL);
02644         created   = CreateEvent(NULL,FALSE,FALSE,NULL);
02645         wait_disp = CreateEvent(NULL,FALSE,FALSE,NULL);
02646         thread    = CreateThread(NULL,0,thread_lowlevel,arg,0,&ThreadID);
02647         WaitForSingleObject(created,INFINITE);
02648       } else thread_lowlevel(arg);
02649     }
02650   
02651     static LRESULT APIENTRY proc_lowlevel(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
02652       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
02653       MSG st_msg;
02654 
02655       switch(msg) {
02656       case WM_CLOSE:
02657         disp->mouse_x=disp->mouse_y=-1;
02658         disp->key=disp->button=disp->window_x=disp->window_y=0;
02659         disp->closed=true;
02660         ReleaseMutex(disp->mutex);
02661         ShowWindow(disp->window,SW_HIDE);
02662         return 0;
02663       case WM_SIZE: {
02664         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
02665         WaitForSingleObject(disp->mutex,INFINITE);
02666         const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
02667         if (nw && nh && (nw!=disp->width || nh!=disp->height)) { 
02668           disp->window_width  = nw; 
02669           disp->window_height = nh;
02670           disp->mouse_x = disp->mouse_y = -1;
02671           disp->resized = true;
02672         }
02673         ReleaseMutex(disp->mutex);
02674       } break;
02675       case WM_MOVE: {
02676         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
02677         WaitForSingleObject(disp->mutex,INFINITE);
02678         const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
02679         if (nx!=disp->window_x || ny!=disp->window_y) {
02680           disp->window_x = nx;
02681           disp->window_y = ny;
02682           disp->moved = true;
02683         }
02684         ReleaseMutex(disp->mutex);
02685       } break;
02686       case WM_PAINT:
02687         WaitForSingleObject(disp->mutex,INFINITE);
02688         SetDIBitsToDevice(disp->hdc,0,0,disp->width,disp->height,0,0,0,disp->height,disp->data,&(disp->bmi),DIB_RGB_COLORS);
02689         ReleaseMutex(disp->mutex);
02690         break;
02691       }
02692       if (disp->events>=2) switch(msg) {
02693       case WM_KEYDOWN:
02694         while (PeekMessage(&st_msg,window,WM_KEYDOWN,WM_KEYDOWN,PM_REMOVE)); 
02695         disp->key=(int)wParam;
02696         break;
02697       case WM_MOUSEMOVE: {
02698         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE));
02699         disp->mouse_x = LOWORD(lParam);
02700         disp->mouse_y = HIWORD(lParam);
02701         if (disp->mouse_x<0 || disp->mouse_y<0 ||       disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
02702           disp->mouse_x=disp->mouse_y=-1;
02703       }
02704         break;
02705       case WM_LBUTTONDOWN: 
02706         while (PeekMessage(&st_msg,window,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE));
02707         disp->button |= 1; 
02708         break;
02709       case WM_RBUTTONDOWN: 
02710         while (PeekMessage(&st_msg,window,WM_RBUTTONDOWN,WM_RBUTTONDOWN,PM_REMOVE));
02711         disp->button |= 2; 
02712         break;
02713       case WM_MBUTTONDOWN: 
02714         while (PeekMessage(&st_msg,window,WM_MBUTTONDOWN,WM_MBUTTONDOWN,PM_REMOVE));
02715         disp->button |= 4; 
02716         break;
02717       }
02718       if (disp->events>=3) switch(msg) {
02719       case WM_KEYUP:
02720         while (PeekMessage(&st_msg,window,WM_KEYUP,WM_KEYUP,PM_REMOVE));
02721         disp->key=0;
02722         break;
02723       case WM_LBUTTONUP:
02724         while (PeekMessage(&st_msg,window,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE));
02725         disp->button &= ~1; 
02726         break;
02727       case WM_RBUTTONUP:
02728         while (PeekMessage(&st_msg,window,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE)); 
02729         disp->button &= ~2;
02730         break;
02731       case WM_MBUTTONUP:
02732         while (PeekMessage(&st_msg,window,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE)); 
02733         disp->button &= ~4;
02734         break;
02735       }
02736       return DefWindowProc(window,msg,wParam,lParam);
02737     }
02738   
02739     static DWORD WINAPI thread_lowlevel(void* arg) {
02740       CImgDisplay *disp  = (CImgDisplay*)(((void**)arg)[0]);
02741       const char *title = (const char*)(((void**)arg)[1]);
02742       MSG msg;
02743       delete[] (void**)arg;
02744       disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
02745       disp->bmi.bmiHeader.biWidth=disp->width;
02746       disp->bmi.bmiHeader.biHeight=-(int)disp->height;
02747       disp->bmi.bmiHeader.biPlanes=1;
02748       disp->bmi.bmiHeader.biBitCount=32;
02749       disp->bmi.bmiHeader.biCompression=BI_RGB;
02750       disp->bmi.bmiHeader.biSizeImage=0;
02751       disp->bmi.bmiHeader.biXPelsPerMeter=1;
02752       disp->bmi.bmiHeader.biYPelsPerMeter=1;
02753       disp->bmi.bmiHeader.biClrUsed=0;
02754       disp->bmi.bmiHeader.biClrImportant=0;
02755       disp->data = new unsigned int[disp->width*disp->height];
02756       if (!disp->curr_mode.dmSize) { // Normal window
02757         RECT rect;
02758         rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1;
02759         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02760         const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
02761         disp->window = CreateWindow("MDICLIENT",title?title:"",
02762                                     WS_OVERLAPPEDWINDOW | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
02763                                     disp->width + 2*border1, disp->height + border1 + border2,
02764                                     NULL,NULL,NULL,&(disp->ccs));
02765         if (!disp->closed) {
02766           GetWindowRect(disp->window,&rect);    
02767           disp->window_x = rect.left + border1;
02768           disp->window_y = rect.top + border2;
02769         } else disp->window_x = disp->window_y = 0;
02770       } else { // Fullscreen window
02771         disp->window = CreateWindow("MDICLIENT",title?title:"",
02772                                     WS_POPUP | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
02773                                     disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs));
02774         disp->window_x = disp->window_y = 0;
02775       }
02776       SetForegroundWindow(disp->window);
02777       disp->hdc = GetDC(disp->window);
02778       disp->window_width = disp->width;
02779       disp->window_height = disp->height;
02780       disp->mouse_x = disp->mouse_y = -1;
02781       disp->button = disp->key = 0;
02782       disp->resized = disp->moved = false;      
02783       if (disp->events) {
02784         SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
02785         SetWindowLong(disp->window,GWL_WNDPROC,(LONG)proc_lowlevel);
02786         SetEvent(disp->created);
02787         while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); SetEvent(disp->wait_disp); }
02788       }
02789       return 0;
02790     }
02791 
02792     template<typename T> BITMAPINFO* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
02793       cimg_test(img,"CImgDisplay::render");
02794       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),
02795                                       (unsigned int)0,~(unsigned int)0);
02796       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),
02797                                                                 (unsigned int)0,~(unsigned int)0);
02798       const bool by=(ymin<=ymax);
02799       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin);
02800       const T 
02801         *data1 = img.ptr(0,nymin,0,0),
02802         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
02803         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
02804       unsigned int *ximg = data + nymin*width;
02805       WaitForSingleObject(mutex,INFINITE);
02806       if (!normalization) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--)
02807         *(ximg++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
02808       else {
02809         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
02810         const T nmin = (T)min, delta = (T)(max-nmin), mm = delta?delta:(T)1;
02811         for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
02812           const unsigned char
02813             R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02814             G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02815             B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02816           *(ximg++) = (R<<16) | (G<<8) | (B);
02817         }
02818       }
02819       ReleaseMutex(mutex);
02820       return &bmi;
02821     }
02822 
02823     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int pymin=0,const unsigned int pymax=~0) {
02824       cimg_test(img,"CImgDisplay::display");
02825       const unsigned int 
02826         ymin = pymin<pymax?pymin:pymax,
02827         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
02828       render(img,ymin,ymax);
02829       if (!closed) {
02830         WaitForSingleObject(mutex,INFINITE);
02831         SetDIBitsToDevice(hdc,0,ymin,width,ymax-ymin+1,0,0,0,ymax-ymin+1,data+ymin*width,&bmi,DIB_RGB_COLORS);
02832         ReleaseMutex(mutex);
02833       }
02834       return *this;
02835     }
02836   
02837     CImgDisplay& wait() {
02838       if (!closed && events) WaitForSingleObject(wait_disp,INFINITE);
02839       return *this;
02840     }
02841 
02842     CImgDisplay& show() {
02843       if (closed) {
02844         ShowWindow(window,SW_SHOW);     
02845         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02846         RECT rect; 
02847         rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02848         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02849         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
02850         GetWindowRect(window,&rect);
02851         window_x = rect.left + border1;
02852         window_y = rect.top + border2;
02853         closed = false;
02854       }
02855       return *this;
02856     }
02857 
02858     CImgDisplay& close() {
02859       if (!closed) {
02860         ShowWindow(window,SW_HIDE);
02861         closed = true;
02862         window_x = window_y = 0;
02863       }
02864       return *this;
02865     }
02866 
02867     static const int screen_dimx() { 
02868       DEVMODE mode;
02869       mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0;
02870       EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode);
02871       return mode.dmPelsWidth;      
02872     }
02873 
02874     static const int screen_dimy() {
02875       DEVMODE mode;
02876       mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0;
02877       EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode);
02878       return mode.dmPelsHeight;      
02879     }
02880 
02881 #endif
02882 
02883 #ifdef cimgdisplay_plugin
02884 #include cimgdisplay_plugin
02885 #endif
02886     
02887   };
02888 
02889   /*-------------------------------------------------------
02890 
02891 
02892 
02893   
02894     Definition of the CImg<T> structure
02895         
02896         
02897         
02898         
02899   ------------------------------------------------------*/
02900 
02902 
02973   template<typename T> struct CImg {
02974     
02976 
02984     unsigned int width;       
02985     
02987 
02995     unsigned int height;
02996     
02998 
03006     unsigned int depth;
03007     
03009 
03017     unsigned int dim;
03018     
03020 
03028     T *data;
03029 
03030     //------------------------------------------
03031     //------------------------------------------
03032     //
03034 
03035     //------------------------------------------
03036     //------------------------------------------
03037   
03039 
03049     explicit CImg(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1):
03050       width(dx),height(dy),depth(dz),dim(dv) {
03051       const unsigned int siz = size();
03052       if (siz) data = new T[siz]; else { data=NULL; width=height=depth=dim=0; }
03053     }
03054 
03057 
03064     explicit CImg(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val):
03065       width(dx),height(dy),depth(dz),dim(dv) {
03066       const unsigned int siz = size();
03067       if (siz) { data = new T[siz]; fill(val); } else { data=NULL; width=height=depth=dim=0; }
03068     }
03069 
03071 
03076     template<typename t> CImg(const CImg<t>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
03077       const unsigned int siz = size();
03078       if (siz) {
03079         data = new T[siz];
03080         const t *ptrs = img.data + siz;
03081         cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs);
03082       } else data = NULL;
03083     }
03084 
03085     CImg(const CImg<T>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
03086       const unsigned siz = size();
03087       if (siz) {
03088         data = new T[width*height*depth*dim];
03089         std::memcpy(data,img.data,siz*sizeof(T));
03090       } else data = NULL;
03091     }
03092 
03093 
03095 
03110     template<typename t> CImg(const CImg<t>& img,const bool pixel_copy):width(0),height(0),depth(0),dim(0),data(NULL) {
03111       if (pixel_copy) CImg<T>(img).swap(*this);
03112       CImg<T>(img.width,img.height,img.depth,img.dim).swap(*this);
03113     }
03114 
03116 
03122     CImg(const char *const filename):width(0),height(0),depth(0),dim(0),data(NULL) { load(filename).swap(*this); }
03123 
03125 
03135     template<typename t> CImg(const t *const data_buffer,
03136                               const unsigned int dx,const unsigned int dy=1,
03137                               const unsigned int dz=1,const unsigned int dv=1,
03138                               const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
03139       const unsigned int siz = size();
03140       if (data_buffer && siz) {
03141         data = new T[siz];
03142         if (multiplexed) {
03143           const t *ptrs = data_buffer;
03144           T *ptrd = data;
03145           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
03146         } else { const t *ptrs = data_buffer+siz; cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)); }
03147       } else { width=height=depth=dim=0; data = NULL; }
03148     }
03149     // Add template overloading if VC>7.1 (optimized version)
03150 #if !defined(_MSC_VER) && _MSC_VER>1300
03151     CImg(const T *const data_buffer,
03152          const unsigned int dx,const unsigned int dy=1,
03153          const unsigned int dz=1,const unsigned int dv=1,
03154          const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
03155       const unsigned int siz = size();
03156       if (data_buffer && siz) {
03157         data = new T[siz];
03158         if (multiplexed) {
03159           const T *ptrs = data_buffer;
03160           T *ptrd = data;
03161           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
03162         } else std::memcpy(data,data_buffer,siz*sizeof(T));
03163       } else { width=height=depth=dim=0; data = NULL; }
03164     }
03165 #endif
03166     
03168 
03171     ~CImg() { if (data) delete[] data; }
03172     
03174 
03180     CImg& empty() { return CImg<T>().swap(*this); }
03181 
03183     //-----------------------------------------------------
03184     //-----------------------------------------------------
03185     //
03187 
03188     //-----------------------------------------------------
03189     //-----------------------------------------------------
03190   
03192 
03198     static const char* pixel_type() { T val; return cimg::get_type(val); }
03199 
03201 
03205     const unsigned int size() const { return width*height*depth*dim; }  
03206 
03208 
03215     const int dimx() const { return (int)width; }  
03216 
03218 
03225     const int dimy() const { return (int)height; }
03226   
03228 
03234     const int dimz() const { return (int)depth; }
03235   
03237 
03243     const int dimv() const { return (int)dim; }
03244   
03246     // with respect to the pixel data pointer \ref data.
03255     const long offset(const int x=0, const int y=0, const int z=0, const int v=0) const { 
03256       return x+width*(y+height*(z+depth*v)); }
03257   
03259 
03268     T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
03269       const long off = offset(x,y,z,v);
03270 #if cimg_debug>1
03271       if (off<0 || off>=size()) {
03272         cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%d) which is"
03273                    "outside the data of the image (%u,%u,%u,%u) (size=%u)",
03274                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
03275         return data;
03276       }
03277 #endif
03278       return data+off;
03279     }
03280 
03282 
03289     T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const {
03290       const int off = offset(x,y,z,v);
03291 #if cimg_debug>1
03292       if (!data || off>=(int)size()) {
03293         cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) "
03294                    "outside the image range (%u,%u,%u,%u) (size=%u)",
03295                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());                     
03296         return *data;
03297       }
03298 #endif
03299       return data[off];
03300     }
03301     
03303 
03307     T& operator[](const unsigned long off) const {
03308 #if cimg_debug>1
03309       if (!data || off>=size()) {
03310         cimg::warn(true,
03311                    "CImg<%s>::operator[] : Trying to get a pixel at offset=%d, outside the range of the image (%u,%u,%u,%u) (size=%u)",
03312                    pixel_type(),off,width,height,depth,dim,size());                     
03313         return *data;
03314       }
03315 #endif
03316       return data[off];
03317     }
03318 
03320 
03327     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 {
03328       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
03329     }
03330 
03332 
03339     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 {
03340       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
03341     }
03343 
03350     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 {
03351       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
03352     }
03353 
03355 
03362     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 {
03363       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
03364     }
03365 
03367 
03373     const T& neumann_pix4d(const int x,const int y=0,const int z=0,const int v=0) const {
03374       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03375                      y<0?0:(y>=dimy()?dimy()-1:y),
03376                      z<0?0:(z>=dimz()?dimz()-1:z),
03377                      v<0?0:(v>=dimv()?dimv()-1:v));
03378     }
03380 
03386     const T& neumann_pix3d(const int x,const int y=0,const int z=0,const int v=0) const {
03387       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03388                      y<0?0:(y>=dimy()?dimy()-1:y),
03389                      z<0?0:(z>=dimz()?dimz()-1:z),v);
03390     }
03391 
03393 
03399     const T& neumann_pix2d(const int x,const int y=0,const int z=0,const int v=0) const {
03400       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03401                      y<0?0:(y>=dimy()?dimy()-1:y),z,v);
03402     }
03404 
03410     const T& neumann_pix1d(const int x,const int y=0,const int z=0,const int v=0) const {
03411       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
03412     }
03413     
03415 
03421     double linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const {
03422       double valx0,valx1,valy0,valy1,valz0,valz1;
03423       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy),
03424         fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv);
03425       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy,  z = (unsigned int)fz, v = (unsigned int)fv;
03426       const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
03427       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;
03428       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03429       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03430       valy0 = (1-dy)*valx0 + (dy)*valx1;
03431       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
03432       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
03433       valy1 = (1-dy)*valx0 + (dy)*valx1;
03434       valz0 = (1-dz)*valy0 + (dz)*valy1;
03435       valx0 = (1-dx)*(*this)(x,y,z,nv)  + (dx)*(*this)(nx,y,z,nv);
03436       valx1 = (1-dx)*(*this)(x,ny,z,nv) + (dx)*(*this)(nx,ny,z,nv);
03437       valy0 = (1-dy)*valx0 + (dy)*valx1;
03438       valx0 = (1-dx)*(*this)(x,y,nz,nv)  + (dx)*(*this)(nx,y,nz,nv);
03439       valx1 = (1-dx)*(*this)(x,ny,nz,nv) + (dx)*(*this)(nx,ny,nz,nv);
03440       valy1 = (1-dy)*valx0 + (dy)*valx1;
03441       valz1 = (1-dz)*valy0 + (dz)*valy1;
03442       return (1-dv)*valz0 + (dv)*valz1;
03443     }
03444 
03446 
03452     double linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const {
03453       double valx0,valx1,valy0,valy1;
03454       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);
03455       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz;
03456       const float dx = fx-x, dy = fy-y, dz = fz-z;
03457       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z;
03458       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03459       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03460       valy0 = (1-dy)*valx0 + (dy)*valx1;
03461       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
03462       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
03463       valy1 = (1-dy)*valx0 + (dy)*valx1;
03464       return (1-dz)*valy0 + (dz)*valy1;
03465     }
03466 
03468 
03474     double linear_pix2d(const float ffx,const float ffy=0,const int z=0,int v=0) const {
03475       double valx0,valx1;
03476       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy);
03477       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy;
03478       const float dx = fx-x, dy = fy-y;
03479       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y;
03480       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03481       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03482       return (1-dy)*valx0 + (dy)*valx1;
03483     }
03484 
03486 
03492     double linear_pix1d(const float ffx,const int y=0,const int z=0,int v=0) const {
03493       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx);
03494       const unsigned int x = (unsigned int)fx;
03495       const float dx = fx-x;
03496       const unsigned int nx = dx>0?x+1:x;
03497       return (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03498     }
03499 
03501 
03507     double cubic_pix2d(const float pfx,const float pfy=0,const int z=0,int v=0) const {
03508       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy);
03509       const unsigned int 
03510         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,
03511         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;
03512       const float dx = fx-x, dy = fy-y;
03513       const T& 
03514         a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v),
03515         e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v),
03516         i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v),
03517         m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v);
03518       const double 
03519         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,
03520         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,
03521         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,
03522         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;
03523       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;
03524     }
03525 
03527 
03533     double cubic_pix1d(const float pfx,const int y=0,const int z=0,int v=0) const {
03534       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx);
03535       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;
03536       const float dx = fx-x;
03537       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);
03538       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;
03539     }
03540     
03542 
03548     const CImg& print(const char *title=NULL,const unsigned int print_flag=1) const {
03549       std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p",
03550                    title?title:"CImg",(void*)this,
03551                    width,height,depth,dim,pixel_type(),(void*)data);
03552       if (size()==0 || !data) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; }
03553       if (print_flag>=1) { 
03554         CImgStats st(*this);
03555         std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)",
03556                      st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax); 
03557       }     
03558       if (print_flag>=2 || size()<=16) {
03559         std::fprintf(stderr," }\n%s = [ ",title?title:"data");
03560         cimg_mapXYZV(*this,x,y,z,k) 
03561           std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k),
03562                        ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]\n":(((x+1)%width==0)?" ; ":" ")));
03563       } else std::fprintf(stderr," }\n");
03564       return *this;
03565     }
03566 
03568 
03573     const CImg& print(const unsigned int print_flag) const { return print(NULL,print_flag); }
03574   
03576     //--------------------------------------------------
03577     //--------------------------------------------------
03578     //
03580 
03581     //--------------------------------------------------
03582     //--------------------------------------------------
03583   
03585 
03589     template<typename t> CImg<T>& operator=(const CImg<t>& img) { 
03590       const unsigned int sizes = img.size(), sized = size();
03591       if (sizes!=sized) return CImg<T>(img).swap(*this); 
03592       const t* ptrs = img.data + sized;
03593       for (T *ptrd = data+sized; ptrd>data; ) *(--ptrd) = (T)*(--ptrs);
03594       width = img.width; height = img.height; depth = img.depth; dim = img.dim;
03595       return *this;
03596     }
03597     
03598     CImg& operator=(const CImg& img) {
03599       if (&img==this) return *this;
03600       const unsigned int sizes = img.size(), sized = size();
03601       if (sizes!=sized) return CImg<T>(img).swap(*this); 
03602       std::memcpy(data,img.data,sizeof(T)*sized);
03603       width = img.width; height = img.height; depth = img.depth; dim = img.dim;
03604       return *this;
03605     }
03606       
03608 
03611     CImg& operator=(const T& val) { return fill(val); }
03612 
03614 
03617     CImg& operator=(const T *buf) {
03618       if (buf) std::memcpy(data,buf,size()*sizeof(T));
03619       else throw CImgArgumentException("CImg<T>::operator=() : Given array pointer 'ptr' is NULL");
03620       return *this; 
03621     }
03622        
03624 
03627     CImg& operator+=(const T& val) { cimg_map(*this,ptr,T) (*ptr)+=val; return *this; }
03628 
03630     CImg& operator++() { return (*this)+=1; }
03631 
03633 
03636     CImg& operator-=(const T& val) { cimg_map(*this,ptr,T) (*ptr)-=val; return *this; }
03637 
03639     CImg& operator--() { return (*this)-=1; }
03640 
03642 
03645     CImg& operator%=(const T& val) { cimg_map(*this,ptr,T) (*ptr)%=val; return *this; }
03646 
03648 
03651     CImg& operator&=(const T& val) { cimg_map(*this,ptr,T) (*ptr)&=val; return *this; }
03652 
03654     CImg& operator|=(const T& val) { cimg_map(*this,ptr,T) (*ptr)|=val; return *this; }
03655 
03657     CImg& operator^=(const T& val) { cimg_map(*this,ptr,T) (*ptr)^=val; return *this; }
03658 
03660     CImg operator+(const T& val) const { return CImg<T>(*this)+=val; }
03661 
03663     CImg operator-(const T& val) const { return CImg<T>(*this)-=val; }
03664 
03666     CImg operator%(const T& val) const { return CImg<T>(*this)%=val; }  
03667 
03669     CImg operator&(const T& val) const { return CImg<T>(*this)&=val; }
03670 
03672     CImg operator|(const T& val) const { return CImg<T>(*this)|=val; }
03673 
03675     CImg operator^(const T& val) const { return CImg<T>(*this)^=val; }
03676 
03678     CImg operator!() const {
03679       CImg<T> res(*this,false);
03680       const T *ptrs = ptr() + size();
03681       cimg_map(res,ptrd,T) *ptrd=!(*(--ptrs));
03682       return res;
03683     }
03684 
03686     CImg operator~() const {
03687       CImg<T> res(*this,false);
03688       const T *ptrs = ptr() + size();
03689       cimg_map(res,ptrd,T) *ptrd=~(*(--ptrs));
03690       return res;
03691     }
03692     
03694     template<typename t> CImg& operator+=(const CImg<t>& img) {
03695       const unsigned int smin = cimg::min(size(),img.size());
03696       t *ptrs = img.data+smin;
03697       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs))));
03698       return *this;
03699     }
03701     template<typename t> CImg& operator-=(const CImg<t>& img) {
03702       const unsigned int smin = cimg::min(size(),img.size());
03703       t *ptrs = img.data+smin;
03704       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs))));
03705       return *this;
03706     }
03708     CImg& operator%=(const CImg& img) {
03709       const unsigned int smin = cimg::min(size(),img.size());
03710       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)%=*(--ptrs));
03711       return *this;
03712     }
03714     CImg& operator&=(const CImg& img) {
03715       const unsigned int smin = cimg::min(size(),img.size());
03716       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)&=*(--ptrs));
03717       return *this;
03718     }
03720     CImg& operator|=(const CImg& img) {
03721       const unsigned int smin = cimg::min(size(),img.size());
03722       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)|=*(--ptrs));
03723       return *this;
03724     }
03726     CImg& operator^=(const CImg& img) {
03727       const unsigned int smin = cimg::min(size(),img.size());
03728       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)^=*(--ptrs));
03729       return *this;
03730     }
03731 
03733     template<typename t> CImg operator+(const CImg<t>& img)  const { return CImg<T>(*this)+=img; }
03734 
03736     template<typename t> CImg operator-(const CImg<t>& img)  const { return CImg<T>(*this)-=img; }
03737 
03739     CImg operator%(const CImg& img) const { return CImg<T>(*this)%=img; }
03740 
03742     CImg operator&(const CImg& img) const { return CImg<T>(*this)&=img; } 
03743 
03745     CImg operator|(const CImg& img) const { return CImg<T>(*this)|=img; }
03746 
03748     CImg operator^(const CImg& img) const { return CImg<T>(*this)^=img; }  
03749 
03751     CImg& operator*=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)*val); return *this; }
03752 
03754     CImg& operator/=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)/val); return *this; }
03755 
03757     CImg operator*(const double val) const { return CImg<T>(*this)*=val; }
03758 
03760     CImg operator/(const double val) const { return CImg<T>(*this)/=val; }
03761 
03763     friend CImg operator+(const T& val, const CImg& img) { return CImg<T>(img)+=val; }
03764 
03766     friend CImg operator*(const double val,const CImg &img) { return CImg<T>(img)*=val; }
03767 
03769     friend CImg operator-(const T& val, const CImg& img) { return CImg<T>(img.width,img.height,img.depth,img.dim,val)-=img; }
03770 
03772     template<typename t> const bool operator==(const CImg<t>& img) const {
03773       const unsigned int siz = size();
03774       bool vequal = true;
03775       if (siz!=img.size()) return false;
03776       t *ptrs=img.data+siz;
03777       for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs))));
03778       return vequal;
03779     }
03781     template<typename t> const bool operator!=(const CImg<t>& img) const { return !((*this)==img); }
03782 
03784     //--------------------------------------------------
03785     //--------------------------------------------------
03786     //
03788 
03789     //--------------------------------------------------
03790     //--------------------------------------------------
03791      
03793 
03797     template<typename t> CImg& mul(const CImg<t>& img) {
03798       t *ptrs = img.data;
03799       T *ptrf = data + cimg::min(size(),img.size());
03800       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd*(*(ptrs++)));
03801       return *this;
03802     }
03803 
03805 
03811     template<typename t> CImg get_mul(const CImg<t>& img) const { return CImg<T>(*this).mul(img); }
03812   
03814 
03818     template<typename t> CImg& div(const CImg<t>& img) {
03819       t *ptrs = img.data;
03820       T *ptrf = data + cimg::min(size(),img.size());
03821       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd/(*(ptrs++)));
03822       return *this;
03823     }
03824 
03826 
03832     template<typename t> CImg get_div(const CImg<t>& img) const { return CImg<T>(*this).div(img); }
03833   
03835 
03839     template<typename t> CImg& max(const CImg<t>& img) {
03840       t *ptrs = img.data;
03841       T *ptrf = data + cimg::min(size(),img.size());
03842       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::max((T)(*(ptrs++)),*ptrd);
03843       return *this;
03844     }
03846 
03850     template<typename t> CImg get_max(const CImg<t>& img) const { return CImg<T>(*this).max(img); }
03851   
03853 
03857     template<typename t> CImg& min(const CImg<t>& img) {
03858       t *ptrs = img.data;
03859       T *ptrf = data + cimg::min(size(),img.size());
03860       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::min((T)(*(ptrs++)),*ptrd);
03861       return *this;
03862     }
03864 
03868     template<typename t> CImg get_min(const CImg<t>& img) const { return CImg<T>(*this).min(img); }
03869 
03871 
03874     CImg& sqrt() {
03875       cimg_map(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr));
03876       return *this;
03877     }
03878 
03880 
03883     CImg get_sqrt() const { return CImg<T>(*this).sqrt(); }
03884   
03886 
03889     CImg& log() {
03890       cimg_map(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr));
03891       return *this;
03892     }
03893 
03895 
03898     CImg get_log() const { return CImg<T>(*this).log(); }
03899 
03901 
03904     CImg& log10() {
03905       cimg_map(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr));
03906       return *this;
03907     }
03908 
03910 
03913     CImg get_log10() const { return CImg<T>(*this).log10(); }
03914 
03916 
03920     CImg& pow(const double p) {
03921       if (p==0) return fill(1);
03922       if (p==1) return *this;
03923       if (p==2) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val; } return *this; }
03924       if (p==3) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val; } return *this; }
03925       if (p==4) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val*val; } return *this; }
03926       cimg_map(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p);
03927       return *this;
03928     }
03929 
03931 
03935     CImg get_pow(const double p) const { return CImg<T>(*this).pow(p); }
03936   
03938 
03941     CImg& abs() {
03942       cimg_map(*this,ptr,T) (*ptr)=cimg::abs(*ptr);
03943       return *this;
03944     }
03945 
03947 
03950     CImg get_abs() const { return CImg<T>(*this).abs(); }
03951   
03953 
03956     CImg& cos() {
03957       cimg_map(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr));
03958       return *this;
03959     }
03960 
03962 
03965     CImg get_cos() const { return CImg<T>(*this).cos(); }
03966  
03968 
03971     CImg& sin() {
03972       cimg_map(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr));
03973       return *this;
03974     }
03975 
03977 
03980     CImg get_sin() const { return CImg<T>(*this).sin(); }
03981   
03983 
03986     CImg& tan() {
03987       cimg_map(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr));
03988       return *this;
03989     }
03990 
03992 
03995     CImg get_tan() const { return CImg<T>(*this).tan(); }
03996   
03997 
03999     //------------------------------------------
04000     //------------------------------------------
04001     //
04003 
04004     //------------------------------------------
04005     //------------------------------------------
04006     
04008 
04013     CImg& fill(const T& val) {
04014       cimg_test(*this,"CImg<T>::fill");      
04015       if (val!=0 && sizeof(T)!=1) cimg_map(*this,ptr,T) *ptr=val; 
04016       else std::memset(data,(int)val,size()*sizeof(T));
04017       return *this;
04018     }
04019 
04021 
04025     CImg& fill(const T& val0,const T& val1) {
04026       cimg_test(*this,"CImg<T>::fill");
04027       T *ptr, *ptr_end = data+size();
04028       for (ptr=data; ptr<ptr_end-1; ) { *(ptr++)=val0; *(ptr++)=val1; }
04029       if (ptr!=ptr_end) *(ptr++)=val0;
04030       return *this;
04031     }
04032     
04034 
04039     CImg& fill(const T& val0,const T& val1,const T& val2) {
04040       cimg_test(*this,"CImg<T>::fill");
04041       T *ptr, *ptr_end = data+size();
04042       for (ptr=data; ptr<ptr_end-2; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; }     
04043       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1;
04044       return *this;
04045     }
04046     
04048 
04054     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3) {
04055       cimg_test(*this,"CImg<T>::fill");
04056       T *ptr, *ptr_end = data+size();
04057       for (ptr=data; ptr<ptr_end-3; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; }
04058       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04059       return *this;
04060     }
04061 
04063 
04070     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4) {
04071       cimg_test(*this,"CImg<T>::fill");
04072       T *ptr, *ptr_end = data+size();
04073       for (ptr=data; ptr<ptr_end-4; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; }
04074       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04075       if (ptr!=ptr_end) *(ptr++)=val3;
04076       return *this;
04077     }
04078     
04080 
04088     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5) {
04089       cimg_test(*this,"CImg<T>::fill");
04090       T *ptr, *ptr_end = data+size(); 
04091       for (ptr=data; ptr<ptr_end-5; ) {
04092         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04093       }
04094       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04095       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4;
04096       return *this;
04097     }
04098 
04100 
04109     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04110                const T& val4,const T& val5,const T& val6) {
04111       cimg_test(*this,"CImg<T>::fill");
04112       T *ptr, *ptr_end = data+size(); 
04113       for (ptr=data; ptr<ptr_end-6; ) {
04114         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6;
04115       }
04116       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04117       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04118       return *this;
04119     }
04120 
04122 
04132     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04133                const T& val4,const T& val5,const T& val6,const T& val7) {
04134       cimg_test(*this,"CImg<T>::fill");
04135       T *ptr, *ptr_end = data+size();
04136       for (ptr=data; ptr<ptr_end-7; ) {
04137         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3;
04138         *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7;
04139       }
04140       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04141       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04142       if (ptr!=ptr_end) *(ptr++)=val6;
04143       return *this;
04144     }
04145 
04147 
04158     CImg& fill(const T& val0,const T& val1,const T& val2,
04159                const T& val3,const T& val4,const T& val5,
04160                const T& val6,const T& val7,const T& val8) {
04161       cimg_test(*this,"CImg<T>::fill");
04162       T *ptr, *ptr_end = data+size();
04163       for (ptr=data; ptr<ptr_end-8; ) {
04164         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; 
04165         *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04166         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8;
04167       }
04168       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04169       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04170       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7;
04171       return *this;
04172     }
04173 
04175 
04187     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,
04188                const T& val5,const T& val6,const T& val7,const T& val8,const T& val9) {
04189       cimg_test(*this,"CImg<T>::fill");
04190       T *ptr, *ptr_end = data+size();
04191       for (ptr=data; ptr<ptr_end-9; ) {
04192         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4;
04193         *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9;
04194       }
04195       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04196       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04197       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04198       return *this;
04199     }
04200 
04202 
04216     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04217                const T& val4,const T& val5,const T& val6,const T& val7,
04218                const T& val8,const T& val9,const T& val10,const T& val11) {
04219       cimg_test(*this,"CImg<T>::fill");
04220       T *ptr, *ptr_end = data+size();
04221       for (ptr=data; ptr<ptr_end-11; ) {
04222         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04223         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
04224       }
04225       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04226       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04227       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04228       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10;
04229       return *this;
04230     }
04232 
04250     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04251                const T& val4,const T& val5,const T& val6,const T& val7,
04252                const T& val8,const T& val9,const T& val10,const T& val11,
04253                const T& val12,const T& val13,const T& val14,const T& val15) {
04254       cimg_test(*this,"CImg<T>::fill");
04255       T *ptr, *ptr_end = data+size();
04256       for (ptr=data; ptr<ptr_end-15; ) {
04257         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04258         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
04259         *(ptr++)=val12; *(ptr++)=val13; *(ptr++)=val14; *(ptr++)=val15;
04260       }
04261       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04262       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04263       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04264       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10; if (ptr!=ptr_end) *(ptr++)=val11;
04265       if (ptr!=ptr_end) *(ptr++)=val12; if (ptr!=ptr_end) *(ptr++)=val13; if (ptr!=ptr_end) *(ptr++)=val14;
04266       return *this;
04267     }
04268   
04270 
04275     CImg& normalize(const T& a,const T& b) {
04276       cimg_test(*this,"CImg<T>::normalize");
04277       const CImgStats st(*this,false);
04278       if (st.min==st.max) fill(0);
04279       else cimg_map(*this,ptr,T) *ptr=(T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a);
04280       return *this;
04281     }
04282 
04284 
04289     CImg get_normalize(const T& a,const T& b) const { return CImg<T>(*this).normalize(a,b); }
04290   
04292 
04297     CImg& cut(const T& a, const T& b) {
04298       cimg_test(*this,"CImg<T>::cut");
04299       cimg_map(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
04300       return *this;
04301     }
04302 
04304 
04309     CImg get_cut(const T& a, const T& b) const { return CImg<T>(*this).cut(a,b); }
04310 
04312 
04316     CImg& quantify(const unsigned int n=256) {
04317       cimg_test(*this,"CImg<T>::quantify");
04318       const CImgStats st(*this,false);
04319       const double range = st.max-st.min;
04320       cimg_map(*this,ptr,T) *ptr = (T)(st.min + range*(int)((*ptr-st.min)*(int)n/range)/n);
04321       return *this;
04322     }
04323 
04325 
04329     CImg get_quantify(const unsigned int n=256) const { return CImg<T>(*this).quantify(n); }
04330 
04332 
04336     CImg& threshold(const T& thres) {
04337       cimg_test(*this,"CImg<T>::threshold");
04338       cimg_map(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1;
04339       return *this;
04340     }
04341 
04343 
04347     CImg get_threshold(const T& thres) const { return CImg<T>(*this).threshold(thres); }
04348   
04350 
04359     CImg get_rotate(const float angle,const unsigned int cond=2) const {
04360       cimg_test(*this,"CImg<T>::get_rotate");
04361       CImg dest;
04362       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
04363         ca=(float)std::cos(rad), sa=(float)std::sin(rad);
04364     
04365       if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
04366         const int iangle = (int)nangle/90;
04367         switch (iangle) {
04368         case 1: {
04369           dest = CImg<T>(height,width,depth,dim); 
04370           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,height-1-x,z,v); 
04371         } break; 
04372         case 2: {
04373           dest = CImg<T>(width,height,depth,dim);
04374           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v); 
04375         } break;
04376         case 3: {
04377           dest = CImg<T>(height,width,depth,dim); 
04378           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-y,x,z,v); 
04379         } break;
04380         default: 
04381           return *this;        
04382         }
04383       } else { // generic version
04384         const float 
04385           ux  = (float)(cimg::abs(width*ca)),  uy  = (float)(cimg::abs(width*sa)),
04386           vx  = (float)(cimg::abs(height*sa)), vy  = (float)(cimg::abs(height*ca)),
04387           w2  = 0.5f*width,           h2  = 0.5f*height,
04388           dw2 = 0.5f*(ux+vx),         dh2 = 0.5f*(uy+vy);
04389         dest = CImg<T>((int)(ux+vx), (int)(uy+vy),depth,dim);
04390 
04391         switch (cond) {
04392         case 0: { 
04393           cimg_mapXY(dest,x,y)
04394             cimg_mapZV(*this,z,v) 
04395             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);
04396         } break;
04397         case 1: {
04398           cimg_mapXY(dest,x,y)
04399             cimg_mapZV(*this,z,v) 
04400             dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width),
04401                                     cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height),z,v);
04402         } break;
04403         default: {
04404           cimg_mapXY(dest,x,y) {
04405             const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
04406             const int ix = (int)X, iy = (int)Y;
04407             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
04408             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
04409           }
04410         } break; 
04411         }
04412       }
04413       return dest;
04414     }
04415   
04417 
04425     CImg& rotate(const float angle,const unsigned int cond=2) { return get_rotate(angle,cond).swap(*this); }
04426   
04428 
04439     CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) const {
04440       cimg_test(*this,"CImg<T>::get_rotate");
04441       CImg dest(*this,false);
04442       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
04443         ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom;
04444     
04445       if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
04446         const int iangle = (int)nangle/90;
04447         switch (iangle) {
04448         case 1: {
04449           dest.fill(0);
04450           const unsigned int
04451             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
04452             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
04453             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
04454             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
04455           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
04456             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
04457         } break;
04458         case 2: {
04459           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v); 
04460         } break;
04461         case 3: {
04462           dest.fill(0);
04463           const unsigned int
04464             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
04465             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
04466             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
04467             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
04468           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
04469             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
04470         } break;
04471         default: 
04472           return *this;        
04473         }
04474       } else 
04475         switch (cond) { // generic version
04476         case 0: { 
04477           cimg_mapXY(dest,x,y)
04478             cimg_mapZV(*this,z,v) 
04479             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);
04480         } break;
04481         case 1: {
04482           cimg_mapXY(dest,x,y)
04483             cimg_mapZV(*this,z,v) 
04484             dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width),
04485                                     cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height),z,v);
04486         } break;
04487         default: {
04488           cimg_mapXY(dest,x,y) {
04489             const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
04490             const int ix = (int)X, iy = (int)Y;
04491             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
04492             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
04493           }
04494         } break; 
04495         }
04496       return dest;
04497     }
04498   
04500 
04512     CImg& rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) {
04513       return get_rotate(angle,cx,cy,zoom,cond).swap(*this);
04514     }
04515  
04517 
04531     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 {
04532       cimg_test(*this,"CImg<T>::get_resize");
04533       const unsigned int 
04534         dx = pdx<0?-pdx*width/100:pdx,
04535         dy = pdy<0?-pdy*height/100:pdy,
04536         dz = pdz<0?-pdz*depth/100:pdz, 
04537         dv = pdv<0?-pdv*dim/100:pdv;
04538       CImg res(dx?dx:1,dy?dy:1,dz?dz:1,dv?dv:1);
04539       if (width==res.width && height==res.height && depth==res.depth && dim==res.dim) return *this;
04540       switch (interp) {
04541       case 0: { // Zero filling
04542         res.fill(0).draw_image(*this,0,0,0,0);
04543       } break;
04544       case 1: { // Bloc interpolation
04545         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
04546         float cx,cy,cz,ck=0;
04547         cimg_mapV(res,k) { cz = 0; 
04548         cimg_mapZ(res,z) { cy = 0; 
04549         cimg_mapY(res,y) { cx = 0; 
04550         cimg_mapX(res,x) { res(x,y,z,k) = (*this)((unsigned int)cx,(unsigned int)cy,(unsigned int)cz,(unsigned int)ck); cx+=sx;
04551         } cy+=sy;
04552         } cz+=sz;
04553         } ck+=sk;
04554         }
04555       } break;
04556       case 2: { // Mosaic filling
04557         for (unsigned int k=0; k<res.dim; k+=dim)
04558           for (unsigned int z=0; z<res.depth; z+=depth)
04559             for (unsigned int y=0; y<res.height; y+=height)
04560               for (unsigned int x=0; x<res.width; x+=width) res.draw_image(*this,x,y,z,k);
04561       } break;
04562       case 3: { // Linear interpolation
04563         const float
04564           sx = res.width>1?(float)(width-1)/(res.width-1):0,
04565           sy = res.height>1?(float)(height-1)/(res.height-1):0,
04566           sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
04567           sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
04568         float cx,cy,cz,ck = 0;
04569         cimg_mapV(res,k) { cz = 0; 
04570         cimg_mapZ(res,z) { cy = 0;
04571         cimg_mapY(res,y) { cx = 0; 
04572         cimg_mapX(res,x) { res(x,y,z,k) = (T)linear_pix4d(cx,cy,cz,ck); cx+=sx;
04573         } cy+=sy;
04574         } cz+=sz;
04575         } ck+=sk;
04576         }
04577       } break;
04578       case 4: { // Grid filling
04579         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
04580         res.fill(0);
04581         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);
04582       } break;
04583       case 5: { // Cubic interpolation
04584         const float
04585           sx = res.width>1?(float)(width-1)/(res.width-1):0,
04586           sy = res.height>1?(float)(height-1)/(res.height-1):0,
04587           sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
04588           sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
04589         float cx,cy,cz,ck = 0;
04590         cimg_mapV(res,k) { cz = 0;
04591         cimg_mapZ(res,z) { cy = 0;
04592         cimg_mapY(res,y) { cx = 0;
04593         cimg_mapX(res,x) { res(x,y,z,k) = (T)cubic_pix2d(cx,cy,(int)cz,(int)ck); cx+=sx;
04594         } cy+=sy;
04595         } cz+=sz;
04596         } ck+=sk;
04597         }
04598       } break;      
04599       }
04600       return res;
04601     }
04602 
04604 
04615     template<typename t> CImg get_resize(const CImg<t>& src,const unsigned int interp=1) const {
04616       return get_resize(src.width,src.height,src.depth,src.dim,interp); 
04617     }  
04618 
04620 
04631     CImg get_resize(const CImgDisplay& disp,const unsigned int interp=1) const {
04632       return get_resize(disp.width,disp.height,depth,dim,interp);
04633     }
04634 
04636 
04650     CImg& resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) {
04651       const unsigned int
04652         dx = pdx<0?-pdx*width/100 :(pdx==0?1:pdx),
04653         dy = pdy<0?-pdy*height/100:(pdy==0?1:pdy),
04654         dz = pdz<0?-pdz*depth/100 :(pdz==0?1:pdz),
04655         dv = pdv<0?-pdv*dim/100   :(pdv==0?1:pdv);
04656       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
04657       else return get_resize(dx,dy,dz,dv,interp).swap(*this);
04658     }
04659 
04661 
04672     template<typename t> CImg& resize(const CImg<t>& src,const unsigned int interp=1) { 
04673       return resize(src.width,src.height,src.depth,src.dim,interp); 
04674     }
04675 
04677 
04688     CImg& resize(const CImgDisplay& disp,const unsigned int interp=1) {
04689       return resize(disp.width,disp.height,depth,dim,interp);
04690     }
04691 
04693 
04696     CImg get_resize_halfXY() const {
04697       cimg_test(*this,"CImg<T>::get_resize_halfXY");
04698       CImg<float> mask = CImg<float>::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f,
04699                                              0.1231940459f,  0.1935127547f, 0.1231940459f,
04700                                              0.07842776544f, 0.1231940459f, 0.07842776544f);
04701       CImg_3x3(I,float);
04702       CImg dest(width/2,height/2,depth,dim);
04703       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);
04704       return dest;
04705     }
04706 
04708 
04711     CImg& resize_halfXY() {     return get_resize_halfXY().swap(*this); }
04712 
04714 
04726     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
04727                   const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
04728                   const bool border_condition = false) const {
04729       cimg_test(*this,"CImg<T>::get_crop");
04730       const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1;
04731       CImg dest(dx,dy,dz,dv);
04732       if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth ||
04733           v0>=dim || v1>=dim || x1<x0 || y1<y0 || z1<z0 || v1<v0)
04734         switch (border_condition) {
04735         case false: { cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = dirichlet_pix4d(x0+x,y0+y,z0+z,v0+v,0); } break;
04736         default: { cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = neumann_pix4d(x0+x,y0+y,z0+z,v0+v); } break;
04737         } else {
04738           T *psrc = ptr(x0,y0,z0,v0), *pdest = dest.ptr(0,0,0,0);
04739           if (dx!=width)
04740             for (unsigned int k=0; k<dv; k++) {
04741               for (unsigned int z=0; z<dz; z++) {
04742                 for (unsigned int y=0; y<dy; y++) {
04743                   std::memcpy(pdest,psrc,dx*sizeof(T));
04744                   pdest+=dx;
04745                   psrc+=width;
04746                 }
04747                 psrc+=width*(height-dy);
04748               }
04749               psrc+=width*height*(depth-dz);
04750             }
04751           else {
04752             if (dy!=height)         
04753               for (unsigned int k=0; k<dv; k++) {
04754                 for (unsigned int z=0; z<dz; z++) {
04755                   std::memcpy(pdest,psrc,dx*dy*sizeof(T));
04756                   pdest+=dx*dy;
04757                   psrc+=width*height;
04758                 }
04759                 psrc+=width*height*(depth-dz);
04760               }
04761             else {
04762               if (dz!=depth)
04763                 for (unsigned int k=0; k<dv; k++) {
04764                   std::memcpy(pdest,psrc,dx*dy*dz*sizeof(T));
04765                   pdest+=dx*dy*dz;
04766                   psrc+=width*height*depth;
04767                 }
04768               else std::memcpy(pdest,psrc,dx*dy*dz*dv*sizeof(T));
04769             }
04770           }
04771         }
04772       return dest;
04773     }
04774     
04776 
04785     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
04786                   const unsigned int x1,const unsigned int y1,const unsigned int z1,
04787                   const bool border_condition=false) const {
04788       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
04789     }
04790 
04792 
04799     CImg get_crop(const unsigned int x0,const unsigned int y0,
04800                   const unsigned int x1,const unsigned int y1,
04801                   const bool border_condition=false) const {
04802       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
04803     }
04804 
04806 
04811     CImg get_crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) const {
04812       return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition); 
04813     }
04814 
04816 
04827     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
04828                const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
04829                const bool border_condition=false) {
04830       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).swap(*this);
04831     }
04832 
04834 
04843     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
04844                const unsigned int x1,const unsigned int y1,const unsigned int z1,
04845                const bool border_condition=false) {
04846       return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
04847     }
04848 
04850 
04857     CImg& crop(const unsigned int x0,const unsigned int y0,
04858                const unsigned int x1,const unsigned int y1,
04859                const bool border_condition=false) { 
04860       return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition); 
04861     }
04862 
04864 
04869     CImg& crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) { 
04870       return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
04871     }
04872 
04874 
04878     CImg get_channel(const unsigned int v0=0) const { return get_crop(0,0,0,v0,width-1,height-1,depth-1,v0); }
04879 
04881 
04885     CImg get_slice(const unsigned int z0=0) const { return get_crop(0,0,z0,0,width-1,height-1,z0,dim-1); }
04886 
04888 
04893     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); }
04894 
04896     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 {
04897       cimg_test(*this,"CImg<T>::ref_pointset");
04898       if (xmax<xmin || xmax>=width || y0>=height || z0>=depth || v0>=dim)
04899         throw CImgArgumentException("CImg<%s>::ref_pointset() : Cannot return a reference (%u->%u,%u,%u,%u) from a (%u,%u,%u,%u) image",
04900                                     pixel_type(),xmin,xmax,y0,z0,v0,width,height,depth,dim);
04901       return CImgROI<T>(1+xmax-xmin,1,1,1,ptr(xmin,y0,z0,v0));
04902     }
04903 
04905     CImgROI<T> ref_lineset(const unsigned int ymin,const unsigned int ymax,const unsigned int z0=0,const unsigned int v0=0) const {
04906       cimg_test(*this,"CImg<T>::ref_lineset");
04907       if (ymax<ymin || ymax>=height || z0>=depth || v0>=dim)
04908         throw CImgArgumentException("CImg<%s>::ref_lineset() : Cannot return a reference (0->%u,%u->%u,%u,%u) from a (%u,%u,%u,%u) image",
04909                                     pixel_type(),width-1,ymin,ymax,z0,v0,width,height,depth,dim);
04910       return CImgROI<T>(width,1+ymax-ymin,1,1,ptr(0,ymin,z0,v0));
04911     }
04912   
04914     CImgROI<T> ref_planeset(const unsigned int zmin,const unsigned int zmax,const unsigned int v0=0) const {
04915       cimg_test(*this,"CImg<T>::ref_planeset");
04916       if(zmax<zmin || zmax>=depth || v0>=dim)
04917         throw CImgArgumentException("CImg<%s>::ref_planeset() : Cannot return a reference (0->%u,0->%u,%u->%u,%u) from a (%u,%u,%u,%u) image",
04918                                     pixel_type(),width-1,height-1,zmin,zmax,v0,width,height,depth,dim);
04919       return CImgROI<T>(width,height,1+zmax-zmin,1,ptr(0,0,zmin,v0));
04920     }
04921 
04923     CImgROI<T> ref_channelset(const unsigned int vmin,const unsigned int vmax) const {
04924       cimg_test(*this,"CImg<T>::ref_channelset");
04925       if (vmax<vmin || vmax>=dim)
04926         throw CImgArgumentException("CImg<%s>::ref_channelset() : Cannot return a reference (0->%u,0->%u,0->%u,%u->%u) from a (%u,%u,%u,%u) image",
04927                                     pixel_type(),width-1,height-1,depth-1,vmin,vmax,width,height,depth,dim);
04928       return CImgROI<T>(width,height,depth,1+vmax-vmin,ptr(0,0,0,vmin));
04929     }
04930   
04932     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); }
04933 
04935     CImgROI<T> ref_plane(const unsigned int z0,const unsigned int v0=0) const { return ref_lineset(0,height-1,z0,v0); }
04936 
04938     CImgROI<T> ref_channel(const unsigned int v0) const { return ref_planeset(0,depth-1,v0); }
04939 
04941     CImg& channel(const unsigned int v0=0) { return get_channel(v0).swap(*this); }
04942 
04944     CImg& slice(const unsigned int z0=0) { return get_slice(z0).swap(*this); }
04945 
04947     CImg& plane(const unsigned int z0=0, const unsigned int v0=0) { return get_plane(z0,v0).swap(*this); }
04948   
04950     CImg& flip(const char axe='x') {
04951       cimg_test(*this,"CImg<T>::flip");
04952       T *pf,*pb,*buf=NULL;
04953       switch (cimg::uncase(axe)) {
04954       case 'x': {
04955         pf = ptr(); pb = ptr(width-1);
04956         for (unsigned int yzv=0; yzv<height*depth*dim; yzv++) { 
04957           for (unsigned int x=0; x<width/2; x++) { const T val = *pf; *(pf++)=*pb; *(pb--)=val; }
04958           pf+=width-width/2;
04959           pb+=width+width/2;
04960         }
04961       } break;
04962       case 'y': {
04963         buf = new T[width];
04964         pf = ptr(); pb = ptr(0,height-1);
04965         for (unsigned int zv=0; zv<depth*dim; zv++) {
04966           for (unsigned int y=0; y<height/2; y++) {
04967             std::memcpy(buf,pf,width*sizeof(T));
04968             std::memcpy(pf,pb,width*sizeof(T));
04969             std::memcpy(pb,buf,width*sizeof(T));
04970             pf+=width;
04971             pb-=width;
04972           }
04973           pf+=width*(height-height/2);
04974           pb+=width*(height+height/2);
04975         }
04976       } break;
04977       case 'z': {
04978         buf = new T[width*height];
04979         pf = ptr(); pb = ptr(0,0,depth-1);
04980         cimg_mapV(*this,v) {
04981           for (unsigned int z=0; z<depth/2; z++) {
04982             std::memcpy(buf,pf,width*height*sizeof(T));
04983             std::memcpy(pf,pb,width*height*sizeof(T));
04984             std::memcpy(pb,buf,width*height*sizeof(T));
04985             pf+=width*height;
04986             pb-=width*height;
04987           }
04988           pf+=width*height*(depth-depth/2);
04989           pb+=width*height*(depth+depth/2);
04990         }
04991       } break;
04992       case 'v': {
04993         buf = new T[width*height*depth];
04994         pf = ptr(); pb = ptr(0,0,0,dim-1);
04995         for (unsigned int v=0; v<dim/2; v++) {
04996           std::memcpy(buf,pf,width*height*depth*sizeof(T));
04997           std::memcpy(pf,pb,width*height*depth*sizeof(T));
04998           std::memcpy(pb,buf,width*height*depth*sizeof(T));
04999           pf+=width*height*depth;
05000           pb-=width*height*depth;
05001         }
05002       } break;
05003       default:
05004         throw CImgArgumentException("CImg<%s>::flip() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
05005       }
05006       if (buf) delete[] buf;
05007       return *this;
05008     }
05009 
05011     CImg get_flip(const char axe='x') { return CImg<T>(*this).flip(axe); }
05012     
05014     CImg& scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,const int border_condition=0) {
05015       cimg_test(*this,"CImg<T>::scroll");
05016       
05017       if (scrollx) // Scroll along X-axis
05018         switch (border_condition) {
05019         case 0:
05020           if (cimg::abs(scrollx)>=(int)width) return fill(0);
05021           if (scrollx>0) cimg_mapYZV(*this,y,z,k) {
05022             std::memmove(ptr(0,y,z,k),ptr(scrollx,y,z,k),(width-scrollx)*sizeof(T));
05023             std::memset(ptr(width-scrollx,y,z,k),0,scrollx*sizeof(T));
05024           } else cimg_mapYZV(*this,y,z,k) {
05025             std::memmove(ptr(-scrollx,y,z,k),ptr(0,y,z,k),(width+scrollx)*sizeof(T));
05026             std::memset(ptr(0,y,z,k),0,-scrollx*sizeof(T));
05027           }
05028           break;   
05029         case 1:
05030           if (scrollx>0) {
05031             const int nscrollx = (scrollx>=(int)width)?width-1:scrollx;
05032             if (!nscrollx) return *this;
05033             cimg_mapYZV(*this,y,z,k) {
05034               std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
05035               T *ptrd = ptr(width-1,y,z,k);
05036               const T &val = *ptrd;
05037               for (int l=0; l<nscrollx-1; l++) *(--ptrd) = val;
05038             }
05039           } else {
05040             const int nscrollx = (-scrollx>=(int)width)?width-1:-scrollx;
05041             if (!nscrollx) return *this;
05042             cimg_mapYZV(*this,y,z,k) {
05043               std::memmove(ptr(nscrollx,y,z,k),ptr(0,y,z,k),(width-nscrollx)*sizeof(T));
05044               T *ptrd = ptr(0,y,z,k);
05045               const T &val = *ptrd;
05046               for (int l=0; l<nscrollx-1; l++) *(++ptrd) = val;
05047             }
05048           }    
05049           break; 
05050         case 2: {
05051           const int ml = cimg::mod(scrollx,width), nscrollx = (ml<=(int)width/2)?ml:(ml-(int)width);
05052           if (!nscrollx) return *this;
05053           T* buf = new T[cimg::abs(nscrollx)];
05054           if (nscrollx>0) cimg_mapYZV(*this,y,z,k) {
05055             std::memcpy(buf,ptr(0,y,z,k),nscrollx*sizeof(T));
05056             std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
05057             std::memcpy(ptr(width-nscrollx,y,z,k),buf,nscrollx*sizeof(T));
05058           } else cimg_mapYZV(*this,y,z,k) {
05059             std::memcpy(buf,ptr(width+nscrollx,y,z,k),-nscrollx*sizeof(T));
05060             std::memmove(ptr(-nscrollx,y,z,k),ptr(0,y,z,k),(width+nscrollx)*sizeof(T));
05061             std::memcpy(ptr(0,y,z,k),buf,-nscrollx*sizeof(T));
05062           }
05063           delete[] buf;
05064         } break;
05065         }
05066 
05067       if (scrolly) // Scroll along Y-axis
05068         switch (border_condition) {
05069         case 0:
05070           if (cimg::abs(scrolly)>=(int)height) return fill(0);
05071           if (scrolly>0) cimg_mapZV(*this,z,k) {
05072             std::memmove(ptr(0,0,z,k),ptr(0,scrolly,z,k),width*(height-scrolly)*sizeof(T));
05073             std::memset(ptr(0,height-scrolly,z,k),0,width*scrolly*sizeof(T));
05074           } else cimg_mapZV(*this,z,k) {
05075             std::memmove(ptr(0,-scrolly,z,k),ptr(0,0,z,k),width*(height+scrolly)*sizeof(T));
05076             std::memset(ptr(0,0,z,k),0,-scrolly*width*sizeof(T));
05077           }
05078           break;      
05079         case 1:
05080           if (scrolly>0) {
05081             const int nscrolly = (scrolly>=(int)height)?height-1:scrolly;
05082             if (!nscrolly) return *this;
05083             cimg_mapZV(*this,z,k) {
05084               std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
05085               T *ptrd = ptr(0,height-nscrolly,z,k), *ptrs = ptr(0,height-1,z,k);
05086               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
05087             }
05088           } else {
05089             const int nscrolly = (-scrolly>=(int)height)?height-1:-scrolly;
05090             if (!nscrolly) return *this;
05091             cimg_mapZV(*this,z,k) {
05092               std::memmove(ptr(0,nscrolly,z,k),ptr(0,0,z,k),width*(height-nscrolly)*sizeof(T));
05093               T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
05094               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
05095             }
05096           }    
05097           break;  
05098         case 2: {
05099           const int ml = cimg::mod(scrolly,height), nscrolly = (ml<=(int)height/2)?ml:(ml-(int)height);
05100           if (!nscrolly) return *this;
05101           T* buf = new T[width*cimg::abs(nscrolly)];
05102           if (nscrolly>0) cimg_mapZV(*this,z,k) {
05103             std::memcpy(buf,ptr(0,0,z,k),width*nscrolly*sizeof(T));
05104             std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
05105             std::memcpy(ptr(0,height-nscrolly,z,k),buf,width*nscrolly*sizeof(T));
05106           } else cimg_mapZV(*this,z,k) {
05107             std::memcpy(buf,ptr(0,height+nscrolly,z,k),-nscrolly*width*sizeof(T));
05108             std::memmove(ptr(0,-nscrolly,z,k),ptr(0,0,z,k),width*(height+nscrolly)*sizeof(T));
05109             std::memcpy(ptr(0,0,z,k),buf,-nscrolly*width*sizeof(T));
05110           }
05111           delete[] buf;
05112         } break;    
05113         }
05114 
05115       if (scrollz) // Scroll along Z-axis
05116         switch (border_condition) {
05117         case 0:
05118           if (cimg::abs(scrollz)>=(int)depth) return fill(0);
05119           if (scrollz>0) cimg_mapV(*this,k) {
05120             std::memmove(ptr(0,0,0,k),ptr(0,0,scrollz,k),width*height*(depth-scrollz)*sizeof(T));
05121             std::memset(ptr(0,0,depth-scrollz,k),0,width*height*scrollz*sizeof(T));
05122           } else cimg_mapV(*this,k) {
05123             std::memmove(ptr(0,0,-scrollz,k),ptr(0,0,0,k),width*height*(depth+scrollz)*sizeof(T));
05124             std::memset(ptr(0,0,0,k),0,-scrollz*width*height*sizeof(T));
05125           }
05126           break;      
05127         case 1:
05128           if (scrollz>0) {
05129             const int nscrollz = (scrollz>=(int)depth)?depth-1:scrollz;
05130             if (!nscrollz) return *this;
05131             cimg_mapV(*this,k) {
05132               std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
05133               T *ptrd = ptr(0,0,depth-nscrollz,k), *ptrs = ptr(0,0,depth-1,k);
05134               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
05135             }
05136           } else {
05137             const int nscrollz = (-scrollz>=(int)depth)?depth-1:-scrollz;
05138             if (!nscrollz) return *this;
05139             cimg_mapV(*this,k) {
05140               std::memmove(ptr(0,0,nscrollz,k),ptr(0,0,0,k),width*height*(depth-nscrollz)*sizeof(T));
05141               T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
05142               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
05143             }
05144           }    
05145           break;      
05146         case 2: {
05147           const int ml = cimg::mod(scrollz,depth), nscrollz = (ml<=(int)depth/2)?ml:(ml-(int)depth);
05148           if (!nscrollz) return *this;
05149           T* buf = new T[width*height*cimg::abs(nscrollz)];
05150           if (nscrollz>0) cimg_mapV(*this,k) {
05151             std::memcpy(buf,ptr(0,0,0,k),width*height*nscrollz*sizeof(T));
05152             std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
05153             std::memcpy(ptr(0,0,depth-nscrollz,k),buf,width*height*nscrollz*sizeof(T));
05154           } else cimg_mapV(*this,k) {
05155             std::memcpy(buf,ptr(0,0,depth+nscrollz,k),-nscrollz*width*height*sizeof(T));
05156             std::memmove(ptr(0,0,-nscrollz,k),ptr(0,0,0,k),width*height*(depth+nscrollz)*sizeof(T));
05157             std::memcpy(ptr(0,0,0,k),buf,-nscrollz*width*height*sizeof(T));
05158           }
05159           delete[] buf;
05160         } break;    
05161         }
05162 
05163       if (scrollv) // Scroll along V-axis
05164         switch (border_condition) {
05165         case 0:
05166           if (cimg::abs(scrollv)>=(int)dim) return fill(0);
05167           if (scrollv>0) {
05168             std::memmove(data,ptr(0,0,0,scrollv),width*height*depth*(dim-scrollv)*sizeof(T));
05169             std::memset(ptr(0,0,0,dim-scrollv),0,width*height*depth*scrollv*sizeof(T));
05170           } else cimg_mapV(*this,k) {
05171             std::memmove(ptr(0,0,0,-scrollv),data,width*height*depth*(dim+scrollv)*sizeof(T));
05172             std::memset(data,0,-scrollv*width*height*depth*sizeof(T));
05173           }
05174           break;      
05175         case 1:
05176           if (scrollv>0) {
05177             const int nscrollv = (scrollv>=(int)dim)?dim-1:scrollv;
05178             if (!nscrollv) return *this;
05179             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
05180             T *ptrd = ptr(0,0,0,dim-nscrollv), *ptrs = ptr(0,0,0,dim-1);
05181             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }      
05182           } else {
05183             const int nscrollv = (-scrollv>=(int)dim)?dim-1:-scrollv;
05184             if (!nscrollv) return *this;
05185             std::memmove(ptr(0,0,0,nscrollv),data,width*height*depth*(dim-nscrollv)*sizeof(T));
05186             T *ptrd = ptr(0,0,0,1);
05187             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }      
05188           }    
05189           break;      
05190         case 2: {
05191           const int ml = cimg::mod(scrollv,dim), nscrollv = (ml<=(int)dim/2)?ml:(ml-(int)dim);
05192           if (!nscrollv) return *this;
05193           T* buf = new T[width*height*depth*cimg::abs(nscrollv)];
05194           if (nscrollv>0) {
05195             std::memcpy(buf,data,width*height*depth*nscrollv*sizeof(T));
05196             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
05197             std::memcpy(ptr(0,0,0,dim-nscrollv),buf,width*height*depth*nscrollv*sizeof(T));
05198           } else {
05199             std::memcpy(buf,ptr(0,0,0,dim+nscrollv),-nscrollv*width*height*depth*sizeof(T));
05200             std::memmove(ptr(0,0,0,-nscrollv),data,width*height*depth*(dim+nscrollv)*sizeof(T));
05201             std::memcpy(data,buf,-nscrollv*width*height*depth*sizeof(T));
05202           }
05203           delete[] buf;
05204         } break;    
05205         }
05206 
05207       return *this;
05208     }
05209 
05211     CImg get_scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,
05212                     const int border_condition=0) const {
05213       return CImg<T>(*this).scroll(scrollx,scrolly,scrollz,scrollv,border_condition);
05214     }
05215     
05217     CImg get_3dplanes(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const {
05218       cimg_test(*this,"CImg<T>::get_3dplanes");
05219       const unsigned int
05220         x0=(px0>=width)?width-1:px0,
05221         y0=(py0>=height)?height-1:py0,
05222         z0=(pz0>=depth)?depth-1:pz0;
05223       CImg res(width+depth,height+depth,1,dim);
05224       res.fill((*this)[0]);
05225       { cimg_mapXYV(*this,x,y,k) res(x,y,0,k)        = (*this)(x,y,z0,k); }
05226       { cimg_mapYZV(*this,y,z,k) res(width+z,y,0,k)  = (*this)(x0,y,z,k); }
05227       { cimg_mapXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); }
05228       return res;
05229     }
05230 
05232     CImg<float> get_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const {
05233       cimg_test(*this,"CImg<T>::get_histogram");
05234       if (nblevels<1) {
05235         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %u levels",
05236                                     pixel_type(),nblevels);
05237       }
05238       T vmin=val_min,vmax=val_max;
05239       CImg<float> res(nblevels,1,1,1,0);
05240       if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
05241       cimg_map(*this,ptr,T) { const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); if (pos>=0 && pos<(int)nblevels) res[pos]++; }
05242       return res;
05243     }
05244 
05246     CImg& equalize_histogram(const unsigned int nblevels=256) {
05247       cimg_test(*this,"CImg<T>::equalize_histogram");
05248       CImgStats st(*this,false);
05249       CImg<float> hist = get_histogram(nblevels,(T)st.min,(T)st.max);
05250       float cumul=0;
05251       cimg_mapX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
05252       cimg_map(*this,ptr,T) {
05253         unsigned int pos = (unsigned int)((*ptr-st.min)*nblevels/(1+st.max-st.min));
05254         *ptr = (T)(st.min + (st.max-st.min)*hist[pos]/size());
05255       }
05256       return *this;
05257     }
05259     CImg get_equalize_histogram(const unsigned int nblevels=256) const { return CImg<T>(*this).equalize_histogram(nblevels); }
05260 
05262     CImg<float> get_norm_pointwise(int ntype=2) const {
05263       cimg_test(*this,"CImg<T>::get_norm_pointwise");
05264       CImg<float> res(width,height,depth);
05265       switch(ntype) {
05266       case -1:                // Linf norm
05267         {
05268           cimg_mapXYZ(*this,x,y,z) {
05269             float n=0; cimg_mapV(*this,v) {
05270               const double tmp = cimg::abs((double)(*this)(x,y,z,v));
05271               if (tmp>n) n=(float)tmp; res(x,y,z) = n;
05272             }
05273           }
05274         } break;
05275       case 1:               // L1 norm
05276         {
05277           cimg_mapXYZ(*this,x,y,z) {
05278             float n=0; cimg_mapV(*this,v) n+=cimg::abs((float)((*this)(x,y,z,v))); res(x,y,z) = n;
05279           }
05280         } break;
05281       default:              // L2 norm
05282         {
05283           cimg_mapXYZ(*this,x,y,z) {
05284             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);
05285           }
05286         } break;
05287       }
05288       return res;
05289     }
05290 
05292     CImg& norm_pointwise() { return CImg<T>(get_norm_pointwise()).swap(*this); }
05293 
05295     CImg get_orientation_pointwise() const {
05296       cimg_test(*this,"CImg<T>::get_orientation_pointwise");
05297       CImg dest(width,height,depth,dim);
05298       cimg_mapXYZ(dest,x,y,z) {
05299         float n = 0;
05300         cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
05301         n = (float)std::sqrt((double)n);
05302         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;
05303       }
05304       return dest;
05305     }
05306 
05308     CImg& orientation_pointwise() { return get_orientation_pointwise().swap(*this); }
05309 
05311 
05314     CImgl<T> get_split(const char axe,const unsigned int nb=0) const {
05315       cimg_test(*this,"CImg<T>::get_split");
05316       CImgl<T> res;
05317       switch (cimg::uncase(axe)) {
05318       case 'x': {
05319         res = CImgl<T>(nb?nb:width);
05320         cimgl_map(res,l) res[l] = get_crop(l*width/res.size,0,0,0,(l+1)*width/res.size-1,height-1,depth-1,dim-1);
05321         } break;
05322       case 'y': {
05323         res = CImgl<T>(nb?nb:height);
05324         cimgl_map(res,l) res[l] = get_crop(0,l*height/res.size,0,0,width-1,(l+1)*height/res.size-1,depth-1,dim-1);
05325         } break;
05326       case 'z': {
05327         res = CImgl<T>(nb?nb:depth);
05328         cimgl_map(res,l) res[l] = get_crop(0,0,l*depth/res.size,0,width-1,height-1,(l+1)*depth/res.size-1,dim-1);
05329         } break;
05330       case 'v': {
05331         res = CImgl<T>(nb?nb:dim);
05332         cimgl_map(res,l) res[l] = get_crop(0,0,0,l*dim/res.size,width-1,height-1,depth-1,(l+1)*dim/res.size-1);
05333         } break;
05334       default:
05335         throw CImgArgumentException("CImg<%s>::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
05336         break;
05337       }
05338       return res;
05339     }
05340 
05342 
05352     CImgl<T> get_gradientXY(const int scheme=0,const float alpha=0) const {
05353       cimg_test(*this,"CImg<T>::get_gradientXY");
05354       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
05355       CImgl<T> res(2,width,height,depth,dim);
05356       CImg_3x3(I,T);
05357       switch(scheme) {
05358       case -1: { // backward finite differences
05359         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; } 
05360       } break;
05361       case 1: { // forward finite differences
05362         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; }
05363       } break;
05364       case 2: { // using Sobel mask
05365         const float a = 1, b = 2;
05366         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
05367           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
05368           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
05369         }
05370       } break;
05371       case 3: { // using rotation invariant mask
05372         const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1));
05373         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
05374           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
05375           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
05376         }
05377       } break;
05378       case 4: { // using Deriche filter with low standart variation
05379         res[0] = get_deriche(alpha,1,'x');
05380         res[1] = get_deriche(alpha,1,'y');
05381       } break;
05382       default: { // central finite differences
05383         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) { 
05384           res[0](x,y,z,k) = (T)(0.5*(Inc-Ipc));
05385           res[1](x,y,z,k) = (T)(0.5*(Icn-Icp)); 
05386         } 
05387       } break;
05388       }
05389       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
05390       return res;
05391     }
05392 
05394 
05397     CImgl<T> get_gradientXYZ(const int scheme=0,const float alpha=0) const {
05398       cimg_test(*this,"CImg<T>::get_gradientXYZ");
05399       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
05400       CImgl<T> res(3,width,height,depth,dim);
05401       CImg_3x3x3(I,T);
05402       switch(scheme) {
05403       case -1: { // backward finite differences
05404         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) { 
05405           res[0](x,y,z,k) = Iccc-Ipcc;
05406           res[1](x,y,z,k) = Iccc-Icpc;
05407           res[2](x,y,z,k) = Iccc-Iccp; 
05408         }
05409       } break;
05410       case 1: { // forward finite differences
05411         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
05412           res[0](x,y,z,k) = Incc-Iccc; 
05413           res[1](x,y,z,k) = Icnc-Iccc;
05414           res[2](x,y,z,k) = Iccn-Iccc; 
05415         } 
05416       } break;
05417       case 4: { // using Deriche filter with low standart variation
05418         res[0] = get_deriche(alpha,1,'x');
05419         res[1] = get_deriche(alpha,1,'y');
05420         res[2] = get_deriche(alpha,1,'z');
05421       } break;
05422       default: { // central finite differences
05423         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
05424           res[0](x,y,z,k) = (T)(0.5*(Incc-Ipcc));
05425           res[1](x,y,z,k) = (T)(0.5*(Icnc-Icpc)); 
05426           res[2](x,y,z,k) = (T)(0.5*(Iccn-Iccp)); 
05427         } 
05428       } break;
05429       }
05430       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
05431       return res;
05432     }
05433 
05435     //--------------------------------------
05436     //--------------------------------------
05437     //
05439 
05440     //--------------------------------------
05441     //--------------------------------------
05442   
05444     CImg& RGBtoXYZ() {
05445       cimg_test(*this,"CImg<T>::RGBtoXYZ");
05446       if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
05447                                               "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
05448       cimg_mapXYZ(*this,x,y,z) {
05449         const T R = (*this)(x,y,z,0), G = (*this)(x,y,z,1), B = (*this)(x,y,z,2);
05450         (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B);
05451         (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B);
05452         (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B);
05453       }
05454       return *this;
05455     }
05456 
05458     CImg& XYZtoRGB() {
05459       cimg_test(*this,"CImg<T>::XYZtoRGB");
05460       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
05461                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05462       cimg_mapXYZ(*this,x,y,z) {
05463         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
05464         (*this)(x,y,z,0) = (T)(3.240479*X  - 1.537150*Y - 0.498535*Z);
05465         (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z);
05466         (*this)(x,y,z,2) = (T)(0.055648*X  - 0.204043*Y + 1.057311*Z);
05467       }
05468       return *this;
05469     }
05470 
05472 #define cimg_Labf(x)  ((x)>=0.008856?(std::pow(x,1/3.0)):(7.787*(x)+16.0/116.0))
05473 #define cimg_Labfi(x) ((x)>=0.206893?((x)*(x)*(x)):(((x)-16.0/116.0)/7.787))
05474 
05475     CImg& XYZtoLab() {
05476       cimg_test(*this,"CImg<T>::XYZtoLab");
05477       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
05478                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05479       const double
05480         Xn = 0.412453 + 0.357580 + 0.180423,
05481         Yn = 0.212671 + 0.715160 + 0.072169,
05482         Zn = 0.019334 + 0.119193 + 0.950227;
05483       cimg_mapXYZ(*this,x,y,z) {
05484         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
05485         const double
05486           XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
05487           fX = cimg_Labf(XXn), fY = cimg_Labf(YYn), fZ = cimg_Labf(ZZn);
05488         (*this)(x,y,z,0) = (T)(116*fY-16);
05489         (*this)(x,y,z,1) = (T)(500*(fX-fY));
05490         (*this)(x,y,z,2) = (T)(200*(fY-fZ));
05491       }
05492       return *this;
05493     }
05494 
05496     CImg& LabtoXYZ() {
05497       cimg_test(*this,"CImg<T>::LabtoXYZ");
05498       if (dim!=3) throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
05499                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05500       const double
05501         Xn = 0.412453 + 0.357580 + 0.180423,
05502         Yn = 0.212671 + 0.715160 + 0.072169,
05503         Zn = 0.019334 + 0.119193 + 0.950227;
05504       cimg_mapXYZ(*this,x,y,z) {
05505         const T L = (*this)(x,y,z,0), a = (*this)(x,y,z,1), b = (*this)(x,y,z,2);
05506         const double
05507           cY = (L+16)/116.0,
05508           Y = Yn*cimg_Labfi(cY),
05509           pY = std::pow(Y/Yn,1.0/3),
05510           cX = a/500+pY,
05511           X = Xn*cX*cX*cX,
05512           cZ = pY-b/200,
05513           Z = Zn*cZ*cZ*cZ;
05514         (*this)(x,y,z,0) = (T)(X);
05515         (*this)(x,y,z,1) = (T)(Y);
05516         (*this)(x,y,z,2) = (T)(Z);
05517       }
05518       return *this;
05519     }
05520 
05522     CImg& XYZtoxyY() {
05523       cimg_test(*this,"CImg<T>::XYZtoxyY()");
05524       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
05525                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05526       cimg_mapXYZ(*this,x,y,z) {
05527         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2), sum = (X+Y+Z), nsum = sum>0?sum:1;
05528         (*this)(x,y,z,0) = X/nsum;
05529         (*this)(x,y,z,1) = Y/nsum;
05530         (*this)(x,y,z,2) = Y;
05531       }
05532       return *this;
05533     }
05534 
05536     CImg& xyYtoXYZ() {
05537       cimg_test(*this,"CImg<T>::xyYtoXYZ()");
05538       if (dim!=3) throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
05539                                               "should be a (x,y,Y) image (dim=3)",pixel_type(),dim);
05540       cimg_mapXYZ(*this,x,y,z) {
05541         const T px = (*this)(x,y,z,0), py = (*this)(x,y,z,1), Y = (*this)(x,y,z,2), ny = py>0?py:1;
05542         (*this)(x,y,z,0) = (T)(px*Y/ny);
05543         (*this)(x,y,z,1) = Y;
05544         (*this)(x,y,z,2) = (T)((1-px-py)*Y/ny);
05545       }
05546       return *this;
05547     }
05548     
05549     // Other conversions functions
05550     CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); }
05551     CImg& LabtoRGB() { return LabtoXYZ().XYZtoRGB(); }
05552     CImg& RGBtoxyY() { return RGBtoXYZ().XYZtoxyY(); }
05553     CImg& xyYtoRGB() { return xyYtoXYZ().XYZtoRGB(); }
05554 
05555     // equivalent with get_*()
05556     CImg get_RGBtoXYZ() const { return CImg<T>(*this).RGBtoXYZ(); }
05557     CImg get_XYZtoRGB() const { return CImg<T>(*this).XYZtoRGB(); }
05558     CImg get_XYZtoLab() const { return CImg<T>(*this).XYZtoLab(); }
05559     CImg get_LabtoXYZ() const { return CImg<T>(*this).LabtoXYZ(); }
05560     CImg get_XYZtoxyY() const { return CImg<T>(*this).XYZtoxyY(); }
05561     CImg get_xyYtoXYZ() const { return CImg<T>(*this).xyYtoXYZ(); }
05562     CImg get_RGBtoLab() const { return CImg<T>(*this).RGBtoLab(); }
05563     CImg get_LabtoRGB() const { return CImg<T>(*this).LabtoRGB(); }
05564     CImg get_RGBtoxyY() const { return CImg<T>(*this).RGBtoxyY(); }
05565     CImg get_xyYtoRGB() const { return CImg<T>(*this).xyYtoRGB(); }
05566 
05568     //--------------------------------------
05569     //--------------------------------------
05570     //
05572 
05573     //--------------------------------------
05574     //--------------------------------------
05575 
05576     // Should be used only by member functions. Not an user-friendly function.
05577     // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
05578     CImg& draw_scanline(const int x0,const int x1,const int y,const T *const color,const float opacity=1,
05579                        const bool init=false) {
05580       static float nopacity=0, copacity=0;
05581       static unsigned int whz=0;
05582       static const T* col = NULL;
05583       if (init) {
05584         cimg_test(*this,"CImg<T>::draw_scanline");
05585         if (!color) throw CImgArgumentException("CImg<%s>::draw_scanline() : specified color is (null)",pixel_type());
05586         nopacity = cimg::abs(opacity);
05587         copacity = 1-cimg::max(opacity,0.0f); 
05588         whz = width*height*depth;
05589         col = color;
05590       } else {
05591         const int nx0 = cimg::max(x0,0), nx1 = cimg::min(x1,(int)width-1), dx = nx1-nx0;
05592         T *ptrd = ptr(nx0,y,0,0);
05593         if (dx>=0) {
05594           if (opacity>=1) {
05595             int off = whz-dx-1;
05596             if (sizeof(T)!=1) cimg_mapV(*this,k) {
05597               const T& val = *(col++);
05598               for (int x=dx; x>=0; x--) *(ptrd++)=val;
05599               ptrd+=off;
05600             } else cimg_mapV(*this,k) { std::memset(ptrd,(int)*(col++),dx+1); ptrd+=whz; }
05601             col-=dim;
05602           } else {
05603             int off = whz-dx-1;
05604             cimg_mapV(*this,k) {
05605               const T& val = *(col++);
05606               for (int x=dx; x>=0; x--) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ptrd++; }
05607               ptrd+=off;
05608             }
05609             col-=dim;
05610           }
05611         }
05612       }
05613       return *this;
05614     }
05615     
05616     CImg& draw_scanline(const T *const color,const float opacity=1) { return draw_scanline(0,0,0,color,opacity,true); }
05617 
05619 
05627     CImg& draw_point(const int x0,const int y0,const int z0,
05628                      const T *const color,const float opacity=1) {
05629       cimg_test(*this,"CImg<T>::draw_point");
05630       if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : specified color is (null)",pixel_type());
05631       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
05632         const T *col=color;
05633         const unsigned int whz = width*height*depth;
05634         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05635         T *ptrd = ptr(x0,y0,z0,0);
05636         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
05637         else cimg_mapV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
05638       }
05639       return *this;
05640     }
05641 
05643 
05650     CImg& draw_point(const int x0,const int y0,const T *const color,const float opacity=1) { 
05651       return draw_point(x0,y0,0,color,opacity); 
05652     }
05653 
05655 
05665     CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
05666                     const T *const color,const unsigned int pattern=~0L,const float opacity=1) {
05667       cimg_test(*this,"CImg<T>::draw_line"); 
05668       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
05669       const T* col=color;
05670       unsigned int hatch=1;     
05671       int nx0=x0, nx1=x1, ny0=y0, ny1=y1;
05672       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1);
05673       if (nx1<0 || nx0>=dimx()) return *this;
05674       if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; }
05675       if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;}
05676       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
05677       if (ny1<0 || ny0>=dimy()) return *this;
05678       if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; }
05679       if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;}
05680       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), whz = width*height*depth;
05681       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0;
05682       float x = (float)nx0, y = (float)ny0;
05683       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
05684         if (!(~pattern) || (~pattern && pattern&hatch)) {
05685           T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);      
05686           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
05687           col-=dim;
05688         }
05689         x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05690       } else {
05691         const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f);
05692         for (unsigned int t=0; t<=dmax; t++) {
05693           if (!(~pattern) || (~pattern && pattern&hatch)) {
05694             T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05695             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
05696             col-=dim;
05697           }
05698           x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05699         }
05700       }
05701       return *this;
05702     }
05703   
05705 
05717     CImg& draw_line(const int x0,const int y0,const int z0,const int x1,const int y1,const int z1,
05718                     const T *const color,const unsigned int pattern=~0L,const float opacity=1) {
05719       cimg_test(*this,"CImg<T>::draw_line"); 
05720       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
05721       const T* col=color;
05722       unsigned int hatch=1;
05723       int nx0=x0, ny0=y0, nz0=z0, nx1=x1, ny1=y1, nz1=z1;
05724       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05725       if (nx1<0 || nx0>=dimx()) return *this;
05726       if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; nz0-=nx0*(nz1-nz0)/D; nx0=0; }
05727       if (nx1>=dimx()) { const int d=nx1-dimx(), D=nx1-nx0; ny1+=d*(ny0-ny1)/D; nz1+=d*(nz0-nz1)/D; nx1=dimx()-1;}
05728       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05729       if (ny1<0 || ny0>=dimy()) return *this;
05730       if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; nz0-=ny0*(nz1-nz0)/D; ny0=0; }
05731       if (ny1>=dimy()) { const int d=ny1-dimy(), D=ny1-ny0; nx1+=d*(nx0-nx1)/D; nz1+=d*(nz0-nz1)/D; ny1=dimy()-1;}
05732       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05733       if (nz1<0 || nz0>=dimz()) return *this;
05734       if (nz0<0) { const int D=nz1-nz0; nx0-=nz0*(nx1-nx0)/D; ny0-=nz0*(ny1-ny0)/D; nz0=0; }
05735       if (nz1>=dimz()) { const int d=nz1-dimz(), D=nz1-nz0; nx1+=d*(nx0-nx1)/D; ny1+=d*(ny0-ny1)/D; nz1=dimz()-1;}
05736       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),cimg::abs(ny1-ny0),nz1-nz0), whz = width*height*depth;
05737       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, pz = dmax?(nz1-nz0)/(float)dmax:0;
05738       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
05739       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) { 
05740         if (!(~pattern) || (~pattern && pattern&hatch)) {
05741           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
05742           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }        
05743           col-=dim; 
05744         }
05745         x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05746       } else {
05747         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05748         for (unsigned int t=0; t<=dmax; t++) { 
05749           if (!(~pattern) || (~pattern && pattern&hatch)) {
05750             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
05751             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
05752             col-=dim; 
05753           }
05754           x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));        
05755         }
05756       }
05757       return *this;
05758     }
05759 
05761 
05774     template<typename t> CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
05775                                          const CImg<t>& texture,
05776                                          const int tx0,const int ty0,const int tx1,const int ty1,
05777                                          const float opacity=1) {
05778       cimg_test(*this,"CImg<T>::draw_line"); 
05779       cimg_test(texture,"CImg<T>::draw_line");
05780       if (texture.dim<dim)
05781         throw CImgArgumentException("CImg<%s>::draw_line() : texture has %u channel while image has %u channels",texture.dim,dim);
05782       int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1;
05783       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
05784       if (nx1<0 || nx0>=dimx()) return *this;
05785       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; }
05786       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; }
05787       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
05788       if (ny1<0 || ny0>=dimy()) return *this;
05789       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; }
05790       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; }
05791       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), 
05792         whz = width*height*depth, twhz = texture.width*texture.height*texture.depth;
05793       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0,
05794         tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0;
05795       float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0;
05796       if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) { 
05797         T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05798         t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
05799         cimg_mapV(*this,k) { *ptrd = (T)(*ptrs); ptrd+=whz; ptrs+=twhz; }
05800         x+=px; y+=py; tx+=tpx; ty+=tpy;
05801       } else {
05802         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05803         for (unsigned int tt=0; tt<=dmax; tt++) { 
05804           T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05805           t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
05806           cimg_mapV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; }
05807           x+=px; y+=py; tx+=tpx; ty+=tpy;
05808         }
05809       }
05810       return *this;
05811     }
05812 
05814 
05826     CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1,
05827                      const T *const color,
05828                      const float angle=30,const float length=-10,const unsigned int pattern=~0L,const float opacity=1) {
05829       cimg_test(*this,"CImg<T>::draw_arrow");
05830       const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v,
05831         deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
05832         l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
05833       if (sq>0) {
05834         const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg);        
05835         const int 
05836           xl = x1+(int)(l*cl), yl = y1+(int)(l*sl),
05837           xr = x1+(int)(l*cr), yr = y1+(int)(l*sr),
05838           xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2;
05839         draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
05840       } else draw_point(x0,y0,color,opacity);
05841       return *this;
05842     }
05843 
05845 
05854     template<typename t> CImg& draw_image(const CImg<t>& sprite,
05855                                           const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) {
05856       cimg_test(*this,"CImg<T>::draw_image");
05857       cimg_test(sprite,"CImg<T>::draw_image");
05858       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05859       const int 
05860         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05861         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05862         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
05863         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
05864       const t *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
05865         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
05866       const unsigned int
05867         offX = width-lX, soffX = sprite.width-lX,
05868         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05869         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
05870       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05871       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05872       if (lX>0 && lY>0 && lZ>0 && lV>0)
05873         for (int v=0; v<lV; v++) {
05874           for (int z=0; z<lZ; z++) {
05875             for (int y=0; y<lY; y++) {
05876               if (opacity>=1) for (int x=0; x<lX; x++) *(ptrd++) = (T)(*(ptrs++));
05877               else for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
05878               ptrd+=offX; ptrs+=soffX;
05879             }
05880             ptrd+=offY; ptrs+=soffY;
05881           }
05882           ptrd+=offZ; ptrs+=soffZ;
05883         }
05884       return *this;
05885     }
05886 
05887     // Add template overloading for VC++>=7.1
05888 #if ( !defined(_MSC_VER) || _MSC_VER>1300 )
05889     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) {
05890       cimg_test(*this,"CImg<T>::draw_image");
05891       cimg_test(sprite,"CImg<T>::draw_image");
05892       if (this==&sprite) return draw_image(CImg<T>(sprite),x0,y0,z0,v0,opacity);
05893       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05894       const int 
05895         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05896         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05897         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
05898         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
05899       const T *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
05900         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
05901       const unsigned int
05902         offX = width-lX, soffX = sprite.width-lX,
05903         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05904         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ),
05905         slX = lX*sizeof(T);    
05906       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05907       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05908       if (lX>0 && lY>0 && lZ>0 && lV>0)
05909         for (int v=0; v<lV; v++) {
05910           for (int z=0; z<lZ; z++) {
05911             if (opacity>=1) for (int y=0; y<lY; y++) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
05912             else for (int y=0; y<lY; y++) {
05913               for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
05914               ptrd+=offX; ptrs+=soffX;
05915             }
05916             ptrd+=offY; ptrs+=soffY;
05917           }
05918           ptrd+=offZ; ptrs+=soffZ;
05919         }
05920       return *this;
05921     }
05922 #endif
05923 
05925 
05938     template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite,const CImg<tm>& mask,
05939                                                        const int x0=0,const int y0=0,const int z0=0,const int v0=0,
05940                                                        const tm mask_valmax=1,const float opacity=1) {
05941       cimg_test(*this,"CImg<T>::draw_image");
05942       cimg_test(sprite,"CImg<T>::draw_image");
05943       cimg_test(mask,"CImg<T>::draw_image");
05944       if ((void*)this==(void*)&sprite) return draw_image(CImg<T>(sprite),mask,x0,y0,z0,v0);
05945       if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
05946         throw CImgArgumentException("CImg<%s>::draw_image() : mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
05947                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
05948       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05949       const int
05950         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05951         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05952         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),      
05953         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);    
05954       const int coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-
05955         (bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
05956         ssize = mask.dimx()*mask.dimy()*mask.dimz();
05957       const ti *ptrs = sprite.ptr() + coff;
05958       const tm *ptrm = mask.ptr() + coff;
05959       const unsigned int
05960         offX = width-lX, soffX = sprite.width-lX,
05961         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05962         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
05963       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05964       if (lX>0 && lY>0 && lZ>0 && lV>0)
05965         for (int v=0; v<lV; v++) {
05966           ptrm = mask.data + (ptrm - mask.data)%ssize;
05967           for (int z=0; z<lZ; z++) {
05968             for (int y=0; y<lY; y++) {
05969               for (int x=0; x<lX; x++) {
05970                 const float mopacity = *(ptrm++)*opacity,
05971                   nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f);
05972                 *ptrd = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax);
05973                 ptrd++;
05974               }
05975               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
05976             }
05977             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
05978           }
05979           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
05980         }
05981       return *this;
05982     }
05983 
05985 
05998     CImg& draw_rectangle(const int x0,const int y0,const int z0,const int v0,
05999                          const int x1,const int y1,const int z1,const int v1,
06000                          const T& val,float opacity=1) {
06001       cimg_test(*this,"CImg<T>::draw_rectangle");
06002       const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1);
06003       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;
06004       const int 
06005         lX = (1+nx1-nx0) + (nx1>=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0),
06006         lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0),
06007         lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0),
06008         lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0);
06009       const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ);
06010       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06011       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
06012       if (lX>0 && lY>0 && lZ>0 && lV>0)
06013         for (int v=0; v<lV; v++) {
06014           for (int z=0; z<lZ; z++) {
06015             for (int y=0; y<lY; y++) {
06016               if (opacity>=1) {
06017                 if (sizeof(T)!=1) { for (int x=0; x<lX; x++) *(ptrd++) = val; ptrd+=offX; }
06018                 else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
06019               } else { for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ptrd++; } ptrd+=offX; }
06020             }
06021             ptrd+=offY;
06022           }
06023           ptrd+=offZ;
06024         }  
06025       return *this;
06026     }
06027 
06029 
06040     CImg& draw_rectangle(const int x0,const int y0,const int z0,
06041                          const int x1,const int y1,const int z1,
06042                          const T *const color,const float opacity=1) {
06043       if (!color) throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",pixel_type());
06044       cimg_mapV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
06045       return *this;
06046     }
06047 
06049 
06058     CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1,
06059                          const T *const color,const float opacity=1) {
06060       draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
06061       return *this;
06062     }
06063   
06065 
06076     CImg& draw_triangle(const int x0,const int y0,
06077                         const int x1,const int y1,
06078                         const int x2,const int y2,
06079                         const T *const color, const float opacity=1) {
06080       draw_scanline(color,opacity);
06081       int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2;
06082       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
06083       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
06084       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
06085       if (ny0>=dimy() || ny2<0) return *this;
06086       const float 
06087         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
06088         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
06089         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1);
06090       float xleft = (float)nx0, xright = xleft, pleft = (p1<p2)?p1:p2, pright = (p1<p2)?p2:p1;
06091       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; }
06092       const int ya = ny1>dimy()?height:ny1;
06093       for (int y=ny0<0?0:ny0; y<ya; y++) { draw_scanline((int)xleft,(int)xright,y,color,opacity); xleft+=pleft; xright+=pright; }
06094       if (p1<p2) { xleft=(float)nx1;  pleft=p3;  if (ny1<0) xleft-=ny1*pleft; } 
06095       else       { xright=(float)nx1; pright=p3; if (ny1<0) xright-=ny1*pright; }
06096       const int yb = ny2>=dimy()?height-1:ny2;
06097       for (int yy=ny1<0?0:ny1; yy<=yb; yy++) { draw_scanline((int)xleft,(int)xright,yy,color,opacity); xleft+=pleft; xright+=pright; }
06098       return *this;
06099     }
06100   
06102 
06119     template<typename t> CImg& draw_triangle(const int x0,const int y0,
06120                                              const int x1,const int y1,
06121                                              const int x2,const int y2,
06122                                              const CImg<t>& texture,
06123                                              const int tx0,const int ty0,
06124                                              const int tx1,const int ty1,
06125                                              const int tx2,const int ty2,
06126                                              const float opacity=1) {
06127       cimg_test(*this,"CImg<T>::draw_triangle"); 
06128       cimg_test(texture,"CImg<T>::draw_triangle");
06129       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;
06130       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
06131       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
06132       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
06133       if (ny0>=dimy() || ny2<0) return *this;
06134       const float 
06135         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
06136         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
06137         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1),
06138         tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0,
06139         tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0,
06140         tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0,
06141         tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0,
06142         tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0,
06143         tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0;
06144       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06145       float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,
06146         xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft;
06147       if (p1<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; } 
06148       else       { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; }
06149       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft;
06150         txright-=ny0*tpxright; tyright-=ny0*tpyright; }
06151       const int ya = ny1<dimy()?ny1:height;
06152       for (int y=(ny0<0?0:ny0); y<ya; y++) {
06153         const int dx = (int)xright-(int)xleft;
06154         const float
06155           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
06156           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,        
06157           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
06158           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
06159         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
06160         if (xmin<=xmax) {
06161           const int offx=whz-xmax+xmin-1;
06162           T* ptrd = ptr(xmin,y,0,0);
06163           if (opacity>=1) cimg_mapV(*this,k) {
06164             float tx=txi, ty=tyi;
06165             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
06166             ptrd+=offx;
06167           } else cimg_mapV(*this,k) {
06168             float tx=txi, ty=tyi;
06169             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; }
06170             ptrd+=offx;
06171           }
06172         }
06173         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
06174       }
06175 
06176       if (p1<p2) {
06177         xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3;
06178         if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; }
06179       } else { 
06180         xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3;
06181         if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; }
06182       }    
06183       const int yb = ny2>=dimy()?(height-1):ny2;
06184       for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) {
06185         const int dx = (int)xright-(int)xleft;
06186         const float
06187           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
06188           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,        
06189           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
06190           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
06191         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
06192         if (xmin<=xmax) {
06193           const int offx=whz-xmax+xmin-1;
06194           T* ptrd = ptr(xmin,yy,0,0);
06195           if (opacity>=1) cimg_mapV(*this,k) { 
06196             float tx=txi, ty=tyi;
06197             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
06198             ptrd+=offx;
06199           } else cimg_mapV(*this,k) { 
06200             float tx=txi, ty=tyi;
06201             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; }
06202             ptrd+=offx;
06203           }
06204         }
06205         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
06206       }
06207       return *this;
06208     }
06209 
06211 
06222     CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv,
06223                        const T *const color,const unsigned int pattern=0L, const float opacity=1) {
06224       cimg_test(*this,"CImg<T>::draw_ellipse");
06225       draw_scanline(color,opacity);
06226       if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : specified color is (null).",pixel_type());
06227       unsigned int hatch=1;
06228       const float
06229         nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
06230         norm = (float)std::sqrt(ru*ru+rv*rv),
06231         u = norm>0?ru/norm:1,
06232         v = norm>0?rv/norm:0,
06233         rmax = cimg::max(nr1,nr2),
06234         l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2),
06235         l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2),
06236         a = l1*u*u + l2*v*v,
06237         b = u*v*(l1-l2),
06238         c = l1*v*v + l2*u*u;
06239       const int
06240         yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)),
06241         ymin = (y0-yb<0)?0:(y0-yb),
06242         ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb);
06243       int oxmin=0, oxmax=0;
06244       bool first_line = true;
06245       for (int y=ymin; y<=ymax; y++) {
06246         const float Y = (float)(y-y0), delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax), sdelta = (float)((delta>0?std::sqrt(delta):0));
06247         int xmin = (int)(x0-(b*Y+sdelta)/a), xmax = (int)(x0-(b*Y-sdelta)/a);
06248         if (!pattern) draw_scanline(xmin,xmax,y,color,opacity);
06249         else {
06250           if (!(~pattern) || (~pattern && pattern&hatch)) {
06251             if (first_line) { draw_scanline(xmin,xmax,y,color,opacity); first_line = false; }
06252             else {
06253               if (xmin<oxmin) draw_scanline(xmin,oxmin-1,y,color,opacity); 
06254               else draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
06255               if (xmax<oxmax) draw_scanline(xmax,oxmax-1,y,color,opacity); 
06256               else draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity); 
06257             }
06258           }
06259         }
06260         oxmin = xmin; oxmax = xmax;
06261         if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
06262       }
06263       return *this;
06264     }
06265     
06267 
06275     template<typename t> CImg& draw_ellipse(const int x0,const int y0,const CImg<t> &tensor,
06276                                             const T *color,const unsigned int pattern=0L,const float opacity=1) {
06277       CImgl<t> eig = tensor.get_symeigen();
06278       const CImg<t> &val = eig[0], &vec = eig[1];
06279       return draw_ellipse(x0,y0,val(0),val(1),vec(0),vec(1),color,pattern,opacity);
06280     }
06281     
06283 
06291     CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const unsigned int pattern=0L,const float opacity=1) {
06292       return draw_ellipse(x0,y0,r,r,1,0,color,pattern,opacity);
06293     }
06294   
06296 
06307     template<typename t> CImg& draw_text(const char *const text,
06308                                          const int x0,const int y0,
06309                                          const T *const fgcolor,const T *const bgcolor,
06310                                          const CImgl<t>& font,const float opacity=1) {
06311 
06312       cimgl_test(font,"CImg<%s>::draw_text");
06313       if (!text) throw CImgArgumentException("CImg<%s>::draw_text() : NULL string specified as input",pixel_type());
06314       if (!width || !height || !depth || !dim || !data) {
06315         // If needed, pre-compute needed size of the image
06316         int x=0, y=0, w=0;
06317         for (int i=0; i<cimg::strlen(text); i++) {
06318           const unsigned char c = text[i];
06319           switch (c) {
06320           case '\n': y+=font[' '].height; if (x>w) w=x; x=0; break;
06321           case '\t': x+=4*font[' '].width; break;
06322           default: if (c<font.size) x+=font[c].width;
06323           }
06324         }       
06325         if (x!=0) {
06326           if (x>w) w=x;
06327           y+=font[' '].height;
06328         }
06329         (*this) = CImg<T>(x0+w,y0+y,1,font[' '].dim,0);
06330         if (bgcolor) cimg_mapV(*this,k) ref_channel(k).fill(bgcolor[k]);
06331       }
06332 
06333       int x=x0, y=y0;
06334       CImg letter;
06335       for (int i=0; i<cimg::strlen(text); i++) {
06336         const unsigned char c = text[i];
06337         switch (c) {
06338         case '\n': y+=font[' '].height; x=x0; break;
06339         case '\t': x+=4*font[' '].width; break;
06340         default: if (c<font.size) {
06341             letter = font[c];
06342             const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c];
06343             if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) 
06344               if (mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=(T)(letter(p,0,0,k)*fgcolor[k]);
06345             if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++)
06346               if (!mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=bgcolor[k];
06347             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);
06348             x+=letter.width;
06349           }
06350           break;
06351         }
06352       }
06353       return *this;
06354     }
06355 
06356 
06358 
06368     CImg& draw_text(const char *const text,
06369                     const int x0,const int y0,
06370                     const T *const fgcolor=NULL,const T *const bgcolor=NULL,
06371                     const float opacity=1) {
06372       static bool first = true;
06373       static CImgl<T> default_font;
06374       if (first) { default_font = CImgl<T>::get_font7x11(); first = false; }
06375       return draw_text(text,x0,y0,fgcolor,bgcolor,default_font,opacity);
06376     }
06377   
06379 
06389     CImg& draw_text(const int x0,const int y0,
06390                     const T *const fgcolor,const T *const bgcolor,
06391                     const float opacity,const char *format,...) {
06392       char tmp[2048]; 
06393       std::va_list ap;
06394       va_start(ap,format);
06395       std::vsprintf(tmp,format,ap);
06396       va_end(ap);
06397       return draw_text(tmp,x0,y0,fgcolor,bgcolor,opacity);
06398     }
06399     template<typename t> CImg& draw_text(const int x0,const int y0,
06400                                          const T *const fgcolor,const T *const bgcolor,
06401                                          const CImgl<t>& font, const float opacity, const char *format,...) {
06402       char tmp[2048]; std::va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap);
06403       return draw_text(tmp,x0,y0,fgcolor,bgcolor,font);
06404     }
06405   
06407 
06416     template<typename t> 
06417     CImg& draw_quiver(const CImg<t>& flow,const T *const color,const unsigned int sampling=25,const float factor=-20,
06418                       const int quiver_type=0,const float opacity=1) {
06419       cimg_test(*this,"CImg<T>::draw_quiver");
06420       cimg_test(flow,"CImg<T>::draw_quiver");
06421       if (!color) 
06422         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified color is (null)",pixel_type());
06423       if (sampling<=0)
06424         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
06425       if (flow.dim!=2)
06426         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
06427                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
06428       float vmax,fact;
06429       if (factor<=0) {
06430         CImgStats st(flow.get_norm_pointwise(2),false);
06431         vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
06432         fact = -factor;
06433       } else { fact = factor; vmax = 1; }
06434 
06435       for (unsigned int y=sampling/2; y<height; y+=sampling)
06436         for (unsigned int x=sampling/2; x<width; x+=sampling) {
06437           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
06438           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
06439           if (!quiver_type) {
06440             const int xx = x+(int)u, yy = y+(int)v;
06441             draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,~0L,opacity);
06442           } 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);
06443         }
06444       return *this; 
06445     }
06446 
06448 
06457     template<typename t1,typename t2>
06458       CImg& draw_quiver(const CImg<t1>& flow,const CImg<t2>& color,const unsigned int sampling=25,const float factor=-20,
06459                         const int quiver_type=0,const float opacity=1) {
06460       cimg_test(*this,"CImg<T>::draw_quiver"); 
06461       cimg_test(flow,"CImg<T>::draw_quiver");
06462       cimg_test(color,"CImg<T>::draw_quiver");
06463       if (sampling<=0)
06464         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
06465       if (flow.dim!=2)
06466         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
06467                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
06468       if (color.width!=flow.width || color.height!=flow.height)
06469         throw CImgArgumentException("CImg<%s>::draw_quiver() : input color data map=(%u,%u,%u,%u)\
06470  and data flow=(%u,%u,%u,%u) must have same dimension.",
06471                                     color.width,color.height,color.depth,color.data,
06472                                     flow.width,flow.height,flow.depth,flow.data);
06473       float vmax,fact;
06474       if (factor<=0) {
06475         CImgStats st(flow.get_norm_pointwise(2),false);
06476         vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
06477         fact = -factor;
06478       } else { fact = factor; vmax = 1; }
06479 
06480       for (unsigned int y=sampling/2; y<height; y+=sampling)
06481         for (unsigned int x=sampling/2; x<width; x+=sampling) {
06482           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
06483           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
06484           if (!quiver_type) {
06485             const int xx = x+(int)u, yy = y+(int)v;
06486             draw_arrow(x,y,xx,yy,color.get_vector(X,Y).data,45,sampling/5,~0L,opacity);
06487           } 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);
06488         }
06489       return *this; 
06490     }
06491 
06493 
06507     template<typename t>
06508     CImg& draw_graph(const CImg<t>& data,const T *const color,const unsigned int gtype=0,
06509                      const double ymin=0,const double ymax=0,const float opacity=1) {
06510       cimg_test(*this,"CImg<T>::draw_graph");
06511       if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : specified color is (null)",pixel_type());
06512       T *color1 = new T[dim], *color2 = new T[dim];
06513       cimg_mapV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); }
06514       CImgStats st;
06515       if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; }
06516       if (st.min==st.max) { st.min--; st.max++; }
06517       const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min;
06518       const int Y0 = (int)(-cb/ca);
06519       int pY=0;
06520       cimg_mapoff(data,off) {     
06521         const int Y = (int)((data[off]-cb)/ca);
06522         switch (gtype) {
06523         case 0: // plot with segments
06524           if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity);
06525           break;
06526         case 1: { // plot with bars
06527           const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1;
06528           draw_rectangle(X,(int)Y0,nX,Y,color1,opacity);
06529           draw_line(X,Y,X,(int)Y0,color2,~0L,opacity);
06530           draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity);
06531           draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity);
06532           draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity);
06533         } break;
06534         }        
06535         pY=Y;
06536       }
06537       if (gtype==2) { // plot with cubic interpolation
06538         const CImgROI<t> ndata(data.size(),1,1,1,data.ptr());
06539         cimg_mapX(*this,x) {
06540           const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca);
06541           if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity);
06542           pY=Y;
06543         }
06544       }
06545       delete[] color1; delete[] color2;
06546       return *this;     
06547     }
06548 
06550 
06560     CImg& draw_axeX(const double x0,const double x1,const int y,const T *const color,
06561                     const double precision=0,const float opacity=1) {
06562       if (x0==x1) return *this;
06563       if (x0<x1) draw_arrow(0,y,width-1,y,color,30,5,~0L,opacity);
06564       else draw_arrow(width-1,y,0,y,color,30,5,~0L,opacity);
06565       const int yt = (y+14)<dimy()?(y+3):(y-14);
06566       double nprecision=precision;
06567       if (precision<=0) { 
06568         const double nb_pow = std::floor(std::log10(cimg::abs(x1-x0)))-1;
06569         nprecision = std::pow(10.0,nb_pow);
06570         while ((cimg::abs(x1-x0)/nprecision)>(dimx()/40)) nprecision*=2;
06571       }
06572       const double xmin=x0<x1?x0:x1, xmax=x0<x1?x1:x0,
06573         tx0 = cimg::mod(xmin,nprecision)==0?xmin:((xmin+nprecision)-cimg::mod(xmin+nprecision,nprecision)),
06574         tx1 = cimg::mod(xmax,nprecision)==0?xmax:((xmax+nprecision)-cimg::mod(xmax+nprecision,nprecision));
06575       char txt[32];
06576       for (double x=tx0; x<=tx1; x+=nprecision) {
06577         std::sprintf(txt,"%g",x);               
06578         const int xi=(int)((x-x0)*(width-1)/(x1-x0)), xt = xi-(int)std::strlen(txt)*3;
06579         draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
06580           draw_text(txt,xt<0?0:xt,yt,color,NULL,opacity);
06581       }
06582       return *this;
06583     }
06584 
06586 
06596     CImg& draw_axeY(const int x,const double y0,const double y1,const T *const color,
06597                     const double precision=0,const float opacity=1) {
06598       if (y0==y1) return *this;
06599       if (y0<y1) draw_arrow(x,0,x,height-1,color,30,5,~0L,opacity);
06600       else draw_arrow(x,height-1,x,0,color,30,5,~0L,opacity);
06601       double nprecision=precision;
06602       if (precision<=0) {
06603         const double nb_pow = std::floor(std::log10(cimg::abs(y1-y0)))-1;
06604         nprecision = std::pow(10.0,nb_pow);
06605         while ((cimg::abs(y1-y0)/nprecision)>(dimy()/40)) nprecision*=2;
06606       }
06607       const double ymin=y0<y1?y0:y1, ymax=y0<y1?y1:y0,
06608         ty0 = cimg::mod(ymin,nprecision)==0?ymin:((ymin+nprecision)-cimg::mod(ymin+nprecision,nprecision)),
06609         ty1 = cimg::mod(ymax,nprecision)==0?ymax:((ymax+nprecision)-cimg::mod(ymax+nprecision,nprecision));
06610       char txt[32];
06611       for (double y=ty0; y<=ty1; y+=nprecision) {
06612         std::sprintf(txt,"%g",y);
06613         const int yi = (int)((y-y0)*(height-1)/(y1-y0)), xt = x-(int)std::strlen(txt)*7;
06614         draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
06615         if (xt>0) draw_text(txt,xt,yi-5,color,NULL,opacity);
06616         else draw_text(txt,x+3,yi-5,color,NULL,opacity);
06617       }
06618       return *this;
06619     }
06620 
06622 
06634     CImg& draw_axeXY(const double x0,const double x1,const double y0,const double y1,const T *const color,
06635                      const double precisionx=0,const double precisiony=0,const float opacity=1) {
06636       if (x0*x1<=0) {
06637         const int xz = (int)(-x0*(width-1)/(x1-x0));
06638         if (xz>=0 && xz<dimx()) draw_axeY(xz,y0,y1,color,precisiony,opacity);
06639       }
06640       if (y0*y1<=0) {
06641         const int yz = (int)(-y0*(height-1)/(y1-y0));
06642         if (yz>=0 && yz<dimy()) draw_axeX(x0,x1,yz,color,precisionx,opacity);
06643       }
06644       return *this;
06645     }
06646   
06647     // Local class used by function CImg<>::draw_fill()
06648     template<typename T1,typename T2> struct _draw_fill {
06649       const T1 *const color;
06650       const float sigma,opacity;
06651       const CImg<T1> value;
06652       CImg<T2> region;
06653 
06654       _draw_fill(const CImg<T1>& img,const int x,const int y,const int z,
06655                  const T *const pcolor,const float psigma,const float popacity):
06656         color(pcolor),sigma(psigma),opacity(popacity),
06657         value(img.get_vector(x,y,z)), region(CImg<T2>(img.width,img.height,img.depth,1,(T2)false)) {
06658         cimg_test(img,"CImg<T>::draw_fill");
06659         if (!color) throw CImgArgumentException("CImg<%s>::draw_fill() : specified color is (null)",img.pixel_type());
06660       }
06661 
06662            _draw_fill& operator=(const _draw_fill& d) {
06663                         color = d.color;
06664                         sigma = d.sigma;
06665                         opacity = d.opacity;
06666                         value = d.value;
06667                         region = d.region;
06668                 }
06669 
06670       bool comp(const CImg<T1>& A,const CImg<T1>& B) const {
06671         bool res=true;
06672         const T *pA=A.data+A.size();
06673         for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) );
06674         return res;
06675       }
06676 
06677       void fill(CImg<T1>& img,const int x,const int y,const int z) {
06678         if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return;
06679         if (!region(x,y,z) && comp(value,img.get_vector(x,y,z))) {
06680           const T *col=color;
06681           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06682           int xmin,xmax;
06683           if (opacity>=1) cimg_mapV(img,k) img(x,y,z,k)=*(col++);
06684           else cimg_mapV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k));
06685           col-=img.dim;
06686           region(x,y,z) = (T2)true;
06687           for (xmin=x-1; xmin>=0 && comp(value,img.get_vector(xmin,y,z)); xmin--) {
06688             if (opacity>=1) cimg_mapV(img,k) img(xmin,y,z,k) = *(col++);
06689             else cimg_mapV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k)); 
06690             col-=img.dim;
06691             region(xmin,y,z)=(T2)true;
06692           }
06693           for (xmax=x+1; xmax<img.dimx() && comp(value,img.get_vector(xmax,y,z)); xmax++) {
06694             if (opacity>=1) cimg_mapV(img,k) img(xmax,y,z,k) = *(col++);
06695             else cimg_mapV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k));
06696             col-=img.dim;
06697             region(xmax,y,z)=(T2)true; 
06698           }
06699           xmin++; xmax--;
06700           for (; xmin<=xmax; xmin++) { 
06701             fill(img,xmin,y-1,z); 
06702             fill(img,xmin,y+1,z);
06703             fill(img,xmin,y,z-1); 
06704             fill(img,xmin,y,z+1);
06705           }
06706         }
06707       }        
06708     };
06709 
06711 
06722     template<typename t> CImg& draw_fill(const int x,const int y,const int z,
06723                                          const T *const color, CImg<t>& region,const float sigma=0,
06724                                          const float opacity=1) {
06725       _draw_fill<T,t> F(*this,x,y,z,color,sigma,opacity);
06726       F.fill(*this,x,y,z);
06727       region = F.region;
06728       return *this;
06729     }
06730 
06732 
06740     CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) {
06741       CImg<bool> tmp;
06742       return draw_fill(x,y,z,color,tmp,sigma,opacity);
06743     }
06744 
06746 
06753     CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) {      
06754       CImg<bool> tmp;
06755       return draw_fill(x,y,0,color,tmp,sigma,opacity);
06756     }
06757 
06759 
06768     CImg& draw_plasma(const int x0,const int y0,const int x1,const int y1,
06769                       const double alpha=1.0,const double beta=1.0,const float opacity=1) {
06770       cimg_test(*this,"CImg<T>::draw_plasma");
06771       int nx0=x0,nx1=x1,ny0=y0,ny1=y1;
06772       if (nx1<nx0) cimg::swap(nx0,nx1);
06773       if (ny1<ny0) cimg::swap(ny0,ny1);
06774       if (nx0<0) nx0=0;
06775       if (nx1>=dimx()) nx1=width-1;
06776       if (ny0<0) ny0=0;
06777       if (ny1>=dimy()) ny1=height-1;
06778       const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0);
06779       const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta;
06780       cimg_mapV(*this,k) {
06781         if (opacity>=1) {
06782           (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k)));
06783           (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k)));
06784           (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k)));
06785           (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k)));
06786           (*this)(xc,yc,0,k)  = (T)(0.25*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
06787                                           (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand());
06788         } else {
06789           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06790           (*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));
06791           (*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));
06792           (*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));
06793           (*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));
06794           (*this)(xc,yc,0,k)  = (T)(0.25*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
06795                                            (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity
06796                                     + copacity*(*this)(xc,yc,0,k));
06797         }
06798       }
06799       if (xc!=nx0 || yc!=ny0) { 
06800         draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
06801         draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
06802         draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
06803         draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity); 
06804       }
06805       return *this;
06806     }
06807 
06809 
06814     CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) {
06815       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
06816     }
06817   
06819 
06825     CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) {
06826       cimg_test(*this,"CImg<T>::draw_gaussian");
06827       const double sigma2 = 2*sigma*sigma;
06828       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06829       const unsigned int whz = width*height*depth;
06830       const T *col = color;
06831       cimg_mapX(*this,x) {
06832         const float dx = (x-xc);
06833         const double val = std::exp( -dx*dx/sigma2 );
06834         T *ptrd = ptr(x,0,0,0);
06835         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06836         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } 
06837         col-=dim;
06838       }
06839       return *this;
06840     }
06841 
06843 
06850     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const CImg<t>& tensor,
06851                                              const T *const color,const float opacity=1) {
06852       cimg_test(*this,"CImg<T>::draw_gaussian"); 
06853       if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1) 
06854         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 2x2 matrix,"
06855                                     "given is (%u,%u,%u,%u)",
06856                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
06857       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
06858       const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1);
06859       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06860       const unsigned int whz = width*height*depth;
06861       const T *col = color;
06862       cimg_mapXY(*this,x,y) {
06863         const float dx = (x-xc), dy = (y-yc);
06864         const double val = std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
06865         T *ptrd = ptr(x,y,0,0);
06866         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06867         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
06868         col-=dim;
06869       }
06870       return *this;
06871     }
06872 
06874 
06881     CImg& draw_gaussian(const float xc,const float yc,const float sigma,const T *const color,const float opacity=1) {
06882       return draw_gaussian(xc,yc,CImg<float>::diagonal(sigma,sigma),color,opacity);
06883     }
06884     
06886 
06894     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg<t>& tensor,
06895                                              const T *const color,const float opacity=1) {
06896       cimg_test(*this,"CImg<T>::draw_gaussian");
06897       if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
06898         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 3x3 matrix,"
06899                                     "given is (%u,%u,%u,%u)",
06900                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
06901       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
06902       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);
06903       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06904       const unsigned int whz = width*height*depth; 
06905       const T *col = color;
06906       cimg_mapXYZ(*this,x,y,z) {
06907         const float dx = (x-xc), dy = (y-yc), dz = (z-zc);
06908         const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
06909         T *ptrd = ptr(x,y,z,0);
06910         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06911         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
06912         col-=dim;
06913       }
06914       return *this;
06915     }
06916     
06918 
06926     CImg& draw_gaussian(const float xc,const float yc,const float zc,
06927                         const double sigma,const T *const color,const float opacity=1) {
06928       return draw_gaussian(xc,yc,zc,CImg<float>::diagonal(sigma,sigma,sigma),color,opacity);
06929     }
06930     
06932     //---------------------------------------
06933     //---------------------------------------
06934     //
06936 
06937     //---------------------------------------
06938     //---------------------------------------
06939   
06941 
06950     template<typename t> CImg get_correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) const {
06951       cimg_test_scalar(mask,"CImg<T>::get_correlate");
06952       CImg dest(*this,false);
06953       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
06954         // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1)
06955         switch (mask.depth) {
06956         case 3: {
06957           CImg_3x3x3(I,T);
06958           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);
06959           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
06960             const double norm = (double)cimg_squaresum3x3x3(I);
06961             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0;
06962           }
06963         } break;
06964         case 2: {
06965           CImg_2x2x2(I,T);
06966           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);
06967           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
06968             const double norm = (double)cimg_squaresum2x2x2(I);
06969             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0;
06970           }
06971         } break;
06972         default:
06973         case 1:
06974           switch (mask.width) {
06975           case 5: {
06976             CImg_5x5(I,T);
06977             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);
06978             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
06979               const double norm = (double)cimg_squaresum5x5(I);
06980               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0;
06981             }            
06982           } break;          
06983           case 4: {
06984             CImg_4x4(I,T);
06985             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);
06986             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
06987               const double norm = (double)cimg_squaresum4x4(I);
06988               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0;
06989             }            
06990           } break;              
06991           case 3: {
06992             CImg_3x3(I,T);
06993             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);
06994             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
06995               const double norm = (double)cimg_squaresum3x3(I);
06996               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0;
06997             }            
06998           } break;   
06999           case 2: {
07000             CImg_2x2(I,T);
07001             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);
07002             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
07003               const double norm = (double)cimg_squaresum2x2(I);
07004               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0;
07005             }            
07006           } break;  
07007           case 1: dest = mask(0)*(*this); break;
07008           }
07009         }
07010       } else { 
07011         // Generic version for other masks      
07012         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);
07013         cimg_mapV(*this,v) 
07014           if (!weighted_correl) {       // Classical correlation
07015             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07016               double val = 0;
07017               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07018                 val+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07019               dest(x,y,z,v)=(T)val;
07020             }
07021             if (cond) cimg_mapYZV(*this,y,z,v)
07022               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))) {
07023                 double val = 0;
07024                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07025                   val+= neumann_pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07026                 dest(x,y,z,v)=(T)val;
07027               }
07028             else cimg_mapYZV(*this,y,z,v)
07029               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))) {
07030                 double val = 0;
07031                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
07032                   val+= dirichlet_pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
07033                 dest(x,y,z,v)=(T)val;
07034               }
07035           } else {      // Weighted correlation
07036             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07037               double val = 0, norm = 0;
07038               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07039                 const T cval = (*this)(x+xm,y+ym,z+zm,v);
07040                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07041                 norm+= cval*cval;
07042               }
07043               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07044             }
07045             if (cond) cimg_mapYZV(*this,y,z,v)
07046               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))) {
07047                 double val = 0, norm = 0;
07048                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07049                   const T cval = neumann_pix3d(x+xm,y+ym,z+zm,v);
07050                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07051                   norm+=cval*cval;
07052                 }
07053                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07054               }
07055             else cimg_mapYZV(*this,y,z,v)
07056               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))) {
07057                 double val = 0, norm = 0;
07058                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07059                   const T cval = dirichlet_pix3d(x+xm,y+ym,z+zm,v,0);
07060                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07061                   norm+= cval*cval;
07062                 }
07063                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07064               }
07065           }
07066       }
07067       return dest;
07068     }
07070 
07074     template<typename t> CImg& correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) { 
07075       return get_correlate(mask,cond,weighted_correl).swap(*this); 
07076     }
07077   
07079 
07088     template<typename t> CImg get_convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) const {
07089       cimg_test_scalar(mask,"CImg<T>::get_convolve");
07090       CImg dest(*this,false);
07091       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version
07092         switch (mask.depth) {
07093         case 3: {
07094           CImg_3x3x3(I,T);
07095           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);
07096           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
07097             const double norm = (double)cimg_squaresum3x3x3(I);
07098             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):(T)0;
07099           }
07100         } break;
07101         case 2: {
07102           CImg_2x2x2(I,T);
07103           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);
07104           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
07105             const double norm = (double)cimg_squaresum2x2x2(I);
07106             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):(T)0;
07107           }
07108         } break;
07109         default:
07110         case 1:
07111           switch (mask.width) {
07112           case 5: {
07113             CImg_5x5(I,T);
07114             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);
07115             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
07116               const double norm = (double)cimg_squaresum5x5(I);
07117               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv5x5(I,mask)/std::sqrt(norm)):(T)0;
07118             }            
07119           } break;          
07120           case 4: {
07121             CImg_4x4(I,T);
07122             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);
07123             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
07124               const double norm = (double)cimg_squaresum4x4(I);
07125               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv4x4(I,mask)/std::sqrt(norm)):(T)0;
07126             }
07127           } break;              
07128           case 3: {
07129             CImg_3x3(I,T);
07130             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);
07131             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
07132               const double norm = (double)cimg_squaresum3x3(I);
07133               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3(I,mask)/std::sqrt(norm)):(T)0;
07134             }            
07135           } break;   
07136           case 2: {
07137             CImg_2x2(I,T);
07138             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);
07139             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
07140               const double norm = (double)cimg_squaresum2x2(I);
07141               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2(I,mask)/std::sqrt(norm)):(T)0;
07142             } 
07143           } break;  
07144           case 1: dest = mask(0)*(*this); break;
07145           }
07146         }
07147       } else { // generic version
07148           
07149         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);
07150         cimg_mapV(*this,v) 
07151           if (!weighted_convol) {       // Classical convolution
07152             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07153               double val = 0;
07154               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07155                 val+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07156               dest(x,y,z,v)=(T)val;
07157             }
07158             if (cond) cimg_mapYZV(*this,y,z,v)
07159               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))) {
07160                 double val = 0;
07161                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07162                   val+= neumann_pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07163                 dest(x,y,z,v)=(T)val;
07164               }
07165             else cimg_mapYZV(*this,y,z,v)
07166               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))) {
07167                 double val = 0;
07168                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
07169                   val+= dirichlet_pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
07170                 dest(x,y,z,v)=(T)val;
07171               }
07172           } else {      // Weighted convolution
07173             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07174               double val = 0, norm = 0;
07175               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07176                 const T cval = (*this)(x-xm,y-ym,z-zm,v);
07177                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07178                 norm+= cval*cval;
07179               }
07180               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07181             }
07182             if (cond) cimg_mapYZV(*this,y,z,v)
07183               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))) {
07184                 double val = 0, norm = 0;
07185                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07186                   const T cval = neumann_pix3d(x-xm,y-ym,z-zm,v);
07187                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07188                   norm+=cval*cval;
07189                 }
07190                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07191               }
07192             else cimg_mapYZV(*this,y,z,v)
07193               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))) {
07194                 double val = 0, norm = 0;
07195                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++) {
07196                   const T cval = dirichlet_pix3d(x-xm,y-ym,z-zm,v,0);
07197                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07198                   norm+= cval*cval;
07199                 }
07200                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07201               }
07202           }
07203       }
07204       return dest;
07205     }
07206   
07208 
07212     template<typename t> CImg& convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) {
07213       return get_convolve(mask,cond,weighted_convol).swap(*this); 
07214     }
07215 
07217 
07221     CImg& noise(const double sigma=-20,const unsigned int ntype=0) {
07222       cimg_test(*this,"CImg<T>::noise");
07223       T tmp;
07224       double nsigma = sigma, max = (double)cimg::get_type_max(tmp), min = (double)cimg::get_type_min(tmp);
07225       static bool first_time = true;
07226       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
07227       CImgStats st;
07228       if (nsigma==0) return *this;
07229       if (nsigma<0 || ntype==2) st = CImgStats(*this,false);
07230       if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0;
07231       switch (ntype) {
07232       case 0: { // Gaussian noise
07233         cimg_map(*this,ptr,T) {
07234           double val = *ptr+nsigma*cimg::grand(); 
07235           if (val>max) val = max;
07236           if (val<min) val = min;
07237           *ptr = (T)val;
07238         }
07239       } break;
07240       case 1: { // Uniform noise
07241         cimg_map(*this,ptr,T) {
07242           double val = *ptr+nsigma*cimg::crand();
07243           if (val>max) val = max;
07244           if (val<min) val = min;
07245           *ptr = (T)val;
07246         }
07247       } break;
07248       case 2: { // Salt & Pepper noise
07249         if (st.max==st.min) { st.min=0; st.max=255; }
07250         cimg_map(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr=(T)(cimg::rand()<0.5?st.max:st.min);
07251       } break;
07252       }
07253       return *this;
07254     }
07255     
07257 
07262     CImg get_noise(const double sigma=-20,const unsigned int ntype=0) const { return CImg<T>(*this).noise(sigma,ntype); }
07263 
07264 
07265 #define cimg_deriche_map(x0,y0,z0,k0,nb,offset,T) {                           \
07266     ima = ptr(x0,y0,z0,k0);                                                   \
07267     I2 = *ima; ima+=offset; I1 = *ima; ima+=offset;                           \
07268     Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2;                   \
07269     for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset;                          \
07270         Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2;                          \
07271         I2=I1; Y2=Y1; Y1=Y0; }                                                \
07272     ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \
07273     ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1);                            \
07274     for (i=(nb)-3; i>=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset;      \
07275       I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; }                    \
07276   }
07277 
07279 
07283     CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) {
07284       cimg_test(*this,"CImg<T>::deriche");
07285       if (sigma<0 || order<0 || order>2)
07286         throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order);
07287       const float alpha=sigma>0?(1.695f/sigma):20,ea=(float)std::exp(alpha),ema=(float)std::exp(-alpha),em2a=ema*ema,b1=2*ema,b2=-em2a;
07288       float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0;
07289       double *Y,Y0,Y1,Y2;
07290       int i,offset,nb;
07291       T *ima,I1,I2;
07292       switch(order) {
07293       case 1:                 // first derivative
07294         ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0;  a2 = ek*ema; a3 = -ek*ema; parity =-1;\
07295         if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } \
07296         else g0 = sumg0 = sumg1 = 0;
07297         break;
07298       case 2:               // second derivative
07299         ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
07300         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;
07301         if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; }
07302         else g0=sumg0=sumg1=0;
07303         break;
07304       default:              // smoothing
07305         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;
07306         if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; }
07307         else  g0=sumg0=sumg1=0;
07308         break;
07309       }
07310       // filter init
07311       Y = new double[cimg::max(width,height,depth)];
07312       switch(cimg::uncase(axe)) {
07313       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;
07314       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;
07315       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;
07316       default: throw CImgArgumentException("CImg<%s>::deriche() : unknow axe '%c', must be 'x','y' or 'z'",pixel_type(),axe);
07317       }
07318       delete[] Y;
07319       return *this;
07320     }
07322 
07327     CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const {
07328       return CImg<T>(*this).deriche(sigma,order,axe,cond);
07329     }
07330 
07332 
07336     CImg& blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) {
07337       cimg_test(*this,"CImg<T>::blur");
07338       if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
07339       if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
07340       if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
07341       return *this;
07342     }
07343 
07345     CImg& blur(const float sigma=1,const unsigned int cond=1) { return blur(sigma,sigma,sigma,cond); }
07346 
07348 
07351     CImg get_blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) const {
07352       return CImg<T>(*this).blur(sigmax,sigmay,sigmaz,cond); 
07353     }
07354     
07356     CImg get_blur(const float sigma=1,const unsigned int cond=1) const { return CImg<T>(*this).blur(sigma,cond); }
07357 
07359     template<typename t> 
07360     CImg& blur_anisotropic(const CImg<t>& G, const float amplitude=10.0f, const float dl=0.8f,const float da=45.0f,
07361                            const float gauss_prec=2.0f, const bool linear=false) {
07362       
07363       // Check arguments and init variables
07364       cimg_test(*this,"blur_anisotropic");
07365       cimg_test(G,"blur_anisotropic");
07366       if ((G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
07367         throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Input tensor field G has wrong dimensions (%u,%u,%u,%u).",
07368                                 pixel_type(),G.width,G.height,G.depth,G.dim);
07369       
07370       const int dx1 = dimx()-1, dy1 = dimy()-1, dz1 = dimz()-1;
07371       const bool threed = (G.dim>=6);
07372       CImg<t> dest(width,height,depth,dim,0), tmp(dim), W(width,height,depth,threed?3:2);
07373       int N = 0;
07374       
07375       if (threed)
07376         // 3D version of the algorithm
07377         //-----------------------------
07378         for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
07379           const float phir = phi*cimg::PI/180, datmp = da/std::cos(phir), da2 = datmp<1?360:datmp;
07380           for (float theta=0; theta<360; (theta+=da2),N++) {
07381             const float thetar = theta*cimg::PI/180,
07382               vx = (float)std::cos(thetar)*std::cos(phir),
07383               vy = (float)std::sin(thetar)*std::cos(phir),
07384               vz = (float)std::sin(phir);
07385             const t 
07386               *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2),
07387               *pd = G.ptr(0,0,0,3), *pe = G.ptr(0,0,0,4), *pf = G.ptr(0,0,0,5);
07388             t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2);
07389             cimg_mapXYZ(G,xg,yg,zg) {
07390               const t
07391                 a = *(pa++), b = *(pb++), c = *(pc++),
07392                 d = *(pd++), e = *(pe++), f = *(pf++),
07393                 u = a*vx + b*vy + c*vz,
07394                 v = b*vx + d*vy + e*vz,
07395                 w = c*vx + e*vy + f*vz,
07396                 n = dl/std::sqrt(1e-5+u*u+v*v+w*w);
07397               *(pd0++) = u*n;
07398               *(pd1++) = v*n;
07399               *(pd2++) = w*n;
07400             }
07401 
07402             cimg_mapXYZ(*this,x,y,z) {
07403               tmp.fill(0);
07404               const t cu = W(x,y,z,0), cv = W(x,y,z,1), cw = W(x,y,z,2);
07405               const float
07406                 fsigma = (float)(2*std::sqrt((cu*cu+cv*cv+cw*cw)*amplitude)),
07407                 length = gauss_prec*fsigma,
07408                 fsigma2 = 2*fsigma*fsigma;
07409               float l, S=0, pu=cu, pv=cv, pw=cw, X=(float)x, Y=(float)y, Z=z+cw;
07410               if (linear) for (l=0; l<length; l+=dl) {
07411                 const float coef = (float)std::exp(-l*l/fsigma2);
07412                 t u = (t)(W.linear_pix3d(X,Y,Z,0)), v = (t)(W.linear_pix3d(X,Y,Z,1)), w = (t)(W.linear_pix3d(X,Y,Z,2));
07413                 if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; }
07414                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*linear_pix3d(X,Y,Z,k));
07415                 X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S+=coef;
07416               } else for (l=0; l<length; l+=dl) {
07417                 const float 
07418                   coef = (float)std::exp(-l*l/fsigma2),
07419                   Xn = X<0?0:(X>=dx1?dx1:X),
07420                   Yn = Y<0?0:(Y>=dy1?dy1:Y),
07421                   Zn = Z<0?0:(Z>=dz1?dz1:Z);
07422                 const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f), zi = (int)(Zn+0.5f);
07423                 t u = W(xi,yi,zi,0), v = W(xi,yi,zi,1), w = W(xi,yi,zi,2);
07424                 if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; }
07425                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,zi,k));
07426                 X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S+=coef;
07427               }
07428               if (S>0) cimg_mapV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
07429               else cimg_mapV(dest,k) dest(x,y,z,k)+=(t)((*this)(x,y,z,k));
07430             }
07431           }
07432         } else
07433           // 2D version of the algorithm
07434           //-----------------------------
07435           for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),N++) {
07436             const float thetar = theta*cimg::PI/180, vx = std::cos(thetar), vy = std::sin(thetar);
07437 
07438             const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2);
07439             t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1);
07440             cimg_mapXY(G,xg,yg) {
07441               const t
07442                 a = *(pa++), b = *(pb++), c = *(pc++), 
07443                 u = a*vx + b*vy, v = b*vx + c*vy,
07444                 n = dl/std::sqrt(1e-5+u*u+v*v);
07445               *(pd0++) = u*n;
07446               *(pd1++) = v*n;
07447             }
07448         
07449             cimg_mapXY(*this,x,y) {
07450               tmp.fill(0);
07451               const t cu = W(x,y,0,0), cv = W(x,y,0,1);
07452               const float
07453                 fsigma = (float)(2*std::sqrt((cu*cu+cv*cv)*amplitude)),
07454                 length = gauss_prec*fsigma,
07455                 fsigma2 = 2*fsigma*fsigma;
07456               float l, S=0, pu=cu, pv=cv, X=(float)x, Y=(float)y;
07457               if (linear) for (l=0; l<length; l+=dl) {
07458                 const float coef = (float)std::exp(-l*l/fsigma2);
07459                 t u = (t)(W.linear_pix2d(X,Y,0,0)), v = (t)(W.linear_pix2d(X,Y,0,1));
07460                 if ((pu*u+pv*v)<0) { u=-u; v=-v; }
07461                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*linear_pix2d(X,Y,0,k));
07462                 X+=(pu=u); Y+=(pv=v); S+=coef;
07463               } else for (l=0; l<length; l+=dl) {
07464                 const float 
07465                   coef = (float)std::exp(-l*l/fsigma2),
07466                   Xn = X<0?0:(X>=dx1?dx1:X),
07467                   Yn = Y<0?0:(Y>=dy1?dy1:Y);
07468                 const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f);
07469                 t u = W(xi,yi,0,0), v = W(xi,yi,0,1);
07470                 if ((pu*u+pv*v)<0) { u=-u; v=-v; }
07471                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,0,k));
07472                 X+=(pu=u); Y+=(pv=v); S+=coef;
07473               }
07474               if (S>0) cimg_mapV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
07475               else cimg_mapV(dest,k) dest(x,y,0,k)+=(t)((*this)(x,y,0,k));
07476             }
07477           }
07478       const float *ptrs = dest.data+dest.size(); cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)/N);
07479       return *this;
07480     }
07481 
07483 
07491     template<typename t>
07492     CImg get_blur_anisotropic(const CImg<t>& G, const float amplitude=10.0f, const float dl=0.8f,const float da=45.0f,
07493                               const float gauss_prec=2.0f, const bool linear=false) const {
07494       return CImg<T>(*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,linear);
07495     }
07496 
07498     CImg& blur_anisotropic(const float amplitude, const float sharpness=1.5f, const float anisotropy=0.7f,
07499                            const float alpha=0.2f,const float sigma=0.8f, const float dl=0.8f,const float da=45.0f,
07500                            const float gauss_prec=2.0f, const bool linear=false) {
07501   
07502       cimg_test(*this,"blur_anisotropic");
07503       const bool threed = (depth>1);
07504       CImg<float> G(width,height,depth,(threed?6:3),0);
07505       const float power1 = 0.5f*sharpness, power2 = (1+anisotropy)/(1e-10+1-anisotropy)*power1;
07506       float nmax = 0;
07507 
07508       if (threed) { // Field for 3D volumes    
07509         CImg<float> val(3),vec(3,3);
07510         CImg_3x3x3(I,float);
07511         CImg<T> blurred = get_blur(alpha);
07512         cimg_mapV(*this,k) cimg_map3x3x3(blurred,x,y,z,k,I) {
07513           const float 
07514             ixf = Incc-Iccc, iyf = Icnc-Iccc, izf = Iccn-Iccc,
07515             ixb = Iccc-Ipcc, iyb = Iccc-Icpc, izb = Iccc-Iccp;
07516           G(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
07517           G(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
07518           G(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
07519           G(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
07520           G(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
07521           G(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
07522         }
07523         G.blur(sigma);
07524         cimg_mapXYZ(*this,x,y,z) {
07525           G.get_tensor(x,y,z).symeigen(val,vec);
07526           const float l1 = val[2], l2 = val[1], l3 = val[0],
07527             ux = vec(2,0), uy = vec(2,1), uz = vec(2,2),
07528             vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
07529             wx = vec(0,0), wy = vec(0,1), wz = vec(0,2),
07530             n1 = (float)(1.0/std::pow(1.0f+l1+l2+l3,power1)),
07531             n2 = (float)(1.0/std::pow(1.0f+l1+l2+l3,power2)),
07532             nm = cimg::max(n1,n2);
07533           G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
07534           G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
07535           G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
07536           G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
07537           G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
07538           G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
07539           if (nm>nmax) nmax = nm;
07540         }
07541       } else { // Field for 2D images
07542         CImg<float> val(2),vec(2,2);
07543         CImg_3x3(I,float);
07544         CImg<T> blurred = get_blur(alpha);
07545         cimg_mapV(*this,k) cimg_map3x3(blurred,x,y,0,k,I) {
07546           const float
07547             ixf = Inc-Icc, iyf = Icn-Icc,
07548             ixb = Icc-Ipc, iyb = Icc-Icp;
07549           G(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
07550           G(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
07551           G(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
07552         }
07553         G.blur(sigma);
07554         cimg_mapXY(*this,x,y) {
07555           G.get_tensor(x,y).symeigen(val,vec);
07556           const float l1 = val[0], l2 = val[1],
07557             ux = vec[0], uy = vec[1],
07558             vx = vec[2], vy = vec[3],
07559             n1 = (float)(1.0/std::pow(1.0f+l1+l2,power1)),
07560             n2 = (float)(1.0/std::pow(1.0f+l1+l2,power2)),
07561             nm = cimg::max(n1,n2);
07562           G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
07563           G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
07564           G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
07565           if (nm>nmax) nmax = nm;
07566         }
07567       }
07568       G/=nmax;
07569       return blur_anisotropic(G,amplitude,dl,da,gauss_prec,linear);
07570     }
07571 
07573 
07583     CImg get_blur_anisotropic(const float amplitude, const float sharpness=1.5f, const float anisotropy=0.7f,
07584                               const float alpha=0.2f, const float sigma=0.8f, const float dl=0.8f,
07585                               const float da=45.0f, const float gauss_prec=2.0f, const bool linear=false) const {
07586   
07587       return CImg<T>(*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,linear);
07588     }
07589 
07591     CImg get_erode(const unsigned int n=1) {
07592       CImg_3x3x3(I,T);
07593       if (n==1) {
07594         CImg dest(*this);
07595         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) 
07596           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) dest(x,y,z,k) = 0;
07597         return dest;
07598       }
07599       CImg img1(*this),img2(*this,false);
07600       CImg *src = &img1, *dest = &img2, *tmp = NULL;
07601       for (unsigned int iter=0; iter<n; iter++) {
07602         *dest = *src;
07603         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I) 
07604           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) (*dest)(x,y,z,k) = 0;
07605         tmp = src;
07606         src = dest;
07607         dest = tmp;
07608       }
07609       return *src;      
07610     }
07611     
07613     CImgl<T> get_FFT(const char axe,const bool inverse=false) const {
07614       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(axe,inverse);      
07615     }
07616 
07618     CImgl<T> get_FFT(const bool inverse=false) const {
07619       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(inverse);      
07620     }
07621 
07623     CImg& erode(const unsigned int n=1) { return get_erode(n).swap(*this); }
07624 
07626     CImg get_dilate(const unsigned int n=1) {
07627       CImgStats stats(*this);
07628       const T tmax = stats.max!=0?(T)stats.max:(T)1;
07629       CImg_3x3x3(I,T);
07630       if (n==1) {
07631         CImg dest(*this);
07632         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) 
07633           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) dest(x,y,z,k) = tmax;
07634         return dest;
07635       }
07636       CImg img1(*this),img2(*this,false);
07637       CImg *src = &img1, *dest = &img2, *tmp = NULL;
07638       for (unsigned int iter=0; iter<n; iter++) {
07639         *dest = *src;
07640         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I) 
07641           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) (*dest)(x,y,z,k) = tmax;
07642         tmp = src;
07643         src = dest;
07644         dest = tmp;
07645       }
07646       return *src;      
07647     }
07649     CImg& dilate(const unsigned int n=1) { return get_dilate(n).swap(*this); }
07650 
07652     //------------------------------------------
07653     //------------------------------------------
07654     //
07656 
07657     //------------------------------------------
07658     //------------------------------------------
07659 
07661     static CImg vector(const T& a1) { return CImg<T>(1,1).fill(a1); }
07662     static CImg vector(const T& a1,const T& a2) { return CImg<T>(1,2).fill(a1,a2); }
07663     static CImg vector(const T& a1,const T& a2,const T& a3) { return CImg<T>(1,3).fill(a1,a2,a3); }
07664     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4) { return CImg<T>(1,4).fill(a1,a2,a3,a4); }
07665     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5) { return CImg<T>(1,5).fill(a1,a2,a3,a4,a5); }
07666     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) { return CImg<T>(1,6).fill(a1,a2,a3,a4,a5,a6); }
07667     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07668                        const T& a5,const T& a6,const T& a7) { return CImg<T>(1,7).fill(a1,a2,a3,a4,a5,a6,a7); }
07669     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07670                        const T& a5,const T& a6,const T& a7,const T& a8) { return CImg<T>(1,8).fill(a1,a2,a3,a4,a5,a6,a7,a8); }
07671     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07672                        const T& a5,const T& a6,const T& a7,const T& a8,const T& a9) { return CImg<T>(1,9).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
07673 
07675     static CImg matrix(const T& a1) { return vector(a1); }
07676     static CImg matrix(const T& a1,const T& a2,
07677                        const T& a3,const T& a4) { return CImg<T>(2,2).fill(a1,a2,a3,a4); }
07678     static CImg matrix(const T& a1,const T& a2,const T& a3,
07679                        const T& a4,const T& a5,const T& a6,
07680                        const T& a7,const T& a8,const T& a9) { return CImg<T>(3,3).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
07681     static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4,
07682                        const T& a5,const T& a6,const T& a7,const T& a8,
07683                        const T& a9,const T& a10,const T& a11,const T& a12,
07684                        const T& a13,const T& a14,const T& a15,const T& a16) {
07685       return CImg<T>(4,4).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
07686     }
07687 
07689     static CImg tensor(const T& a1) { return matrix(a1); }
07690     static CImg tensor(const T& a1,const T& a2,const T& a3) { return matrix(a1,a2,a2,a3); }
07691     static CImg tensor(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) {
07692       return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
07693     }
07694 
07696     static CImg diagonal(const T& a1) { return matrix(a1); }
07697     static CImg diagonal(const T& a1,const T& a2) { return matrix(a1,0,0,a2); }
07698     static CImg diagonal(const T& a1,const T& a2,const T& a3) { return matrix(a1,0,0,0,a2,0,0,0,a3); }
07699     static CImg diagonal(const T& a1,const T& a2,const T& a3,const T& a4) { return matrix(a1,0,0,0,0,a2,0,0,0,0,a3,0,0,0,0,a4); }
07701     template<typename t> CImg operator*(const CImg<t>& img) const {
07702       cimg_test_matrix(*this,"CImg<T>::operator*");
07703       cimg_test_matrix(img,"CImg<T>::operator*");
07704       if (width!=img.height) 
07705         throw CImgArgumentException("CImg<%s>::operator*() : can't multiply a matrix *this = (%ux%u) by a matrix (%ux%u)",
07706                                     pixel_type(),width,height,img.width,img.height);
07707       CImg res(img.width,height);
07708       double val;
07709       cimg_mapXY(res,i,j) { val=0; cimg_mapX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = (T)val; }
07710       return res;
07711     }
07713     template<typename t> CImg& operator*=(const CImg<t>& img) { return ((*this)*img).swap(*this); }
07714   
07716     CImg get_vector(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
07717       CImg dest(dim);
07718       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
07719       return dest;
07720     }
07721   
07723     CImg get_matrix(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
07724       const int n = (int)std::sqrt((double)dim);
07725       CImg dest(n,n);
07726       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
07727       return dest;
07728     }
07729   
07731     CImg get_tensor(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {      
07732       if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
07733                                 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
07734       if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
07735       return tensor((*this)(x,y,z,0));
07736     }
07737 
07739     CImg& set_vector(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07740       return draw_point(x,y,z,vec.data,1);
07741     }
07743     CImg& set_matrix(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07744       return set_vector(mat,x,y,z);
07745     }
07747     CImg& set_tensor(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07748       if (ten.height==2) {
07749         (*this)(x,y,z,0)=ten[0];
07750         (*this)(x,y,z,1)=ten[1];
07751         (*this)(x,y,z,2)=ten[3];
07752       }
07753       else {
07754         (*this)(x,y,z,0)=ten[0];
07755         (*this)(x,y,z,1)=ten[1];
07756         (*this)(x,y,z,2)=ten[2];
07757         (*this)(x,y,z,3)=ten[4];
07758         (*this)(x,y,z,4)=ten[5];
07759         (*this)(x,y,z,5)=ten[8];
07760       }
07761       return *this;
07762     }
07764     CImg& identity_matrix(const unsigned int N) { return get_identity_matrix(N).swap(*this); }
07765       
07767     static CImg get_identity_matrix(const unsigned int N) {
07768       CImg<T> res(N,N,1,1,0);
07769       cimg_mapX(res,x) res(x,x)=1;
07770       return res;
07771     }
07772   
07774     CImg get_transpose() const {
07775       CImg<T> res(height,width,depth,dim);
07776       cimg_mapXYZV(*this,x,y,z,v) res(y,x,z,v) = (*this)(x,y,z,v);      
07777       return res;
07778     }
07779     
07781     CImg& transpose() {
07782       if (width==1) { width=height; height=1; return *this; }
07783       if (height==1) { height=width; width=1; return *this; }
07784       if (width==height) {
07785         cimg_mapYZV(*this,y,z,v) for (int x=y; x<(int)width; x++) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v));
07786         return *this;
07787       }
07788       return (*this)=get_transpose();
07789     }
07790 
07792     CImg get_diagonal() const {
07793       cimg_test(*this,"CImg<T>::get_diagonal");
07794       CImg res(size(),size(),1,1,0);
07795       cimg_mapoff(*this,off) res(off,off)=(*this)(off);
07796       return res;
07797     }
07799     CImg& diagonal() { return get_diagonal().swap(*this); }
07800 
07802     CImg& inverse() {
07803       cimg_test_square(*this,"CImg<T>::inverse");
07804       switch (width) {
07805       case 2: {
07806         const double 
07807           a = data[0], c = data[1],
07808           b = data[2], d = data[3],
07809           dete = det();
07810         if (dete) { 
07811           data[0] = (T)(d/dete);  data[1] = (T)(-c/dete);
07812           data[2] = (T)(-b/dete), data[3] = (T)(a/dete); 
07813         } else {
07814           cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07815           fill(0);
07816         }
07817       } break;
07818       case 3: {
07819         const double
07820           a = data[0], d = data[1], g = data[2],
07821           b = data[3], e = data[4], h = data[5],
07822           c = data[6], f = data[7], i = data[8],
07823           dete = det();
07824         if (dete) {
07825           data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
07826           data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
07827           data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
07828         } else {
07829           cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07830           fill(0);
07831         }
07832       } break;
07833       default: {
07834         CImg<T> U(width,width),S(1,width),V(width,width);
07835         SVD(U,S,V,false);
07836         U.transpose();
07837         cimg_mapY(S,k) if (S[k]!=0) S[k]=1/S[k];
07838         else cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07839         S.diagonal();
07840         *this = V*S*U;
07841       } break;
07842       }
07843       return *this;
07844     }
07845 
07847     CImg get_inverse() const { return CImg<T>(*this).inverse(); }
07848 
07850     double trace() const {
07851       cimg_test_square(*this,"CImg<T>::trace");
07852       double res=0;
07853       cimg_mapX(*this,k) res+=(*this)(k,k);
07854       return res;
07855     }
07857     double dot(const CImg& img) const {
07858       cimg_test(*this,"CImg<T>::dot"); cimg_test(img,"CImg<T>::dot");
07859       const unsigned long nb = cimg::min(size(),img.size());
07860       double res=0;
07861       for (unsigned long off=0; off<nb; off++) res+=data[off]*img[off];
07862       return res;
07863     }
07864         
07866     CImg& cross(const CImg& img) {
07867       if (width!=1 || height<3 || img.width!=1 || img.height<3)
07868         throw CImgInstanceException("CImg<%s>::cross() : cannot get cross product between two matrices (%u,%u) and (%u,%u)",
07869                                     pixel_type(),width,height,img.width,img.height);
07870       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
07871       (*this)[0] = y*img[2]-z*img[1];
07872       (*this)[1] = z*img[0]-x*img[2];
07873       (*this)[2] = x*img[1]-y*img[0];
07874       return *this;
07875     }
07877     CImg get_cross(const CImg& img) const { return CImg<T>(*this).cross(img); }
07878 
07880     double det() const {
07881       cimg_test_square(*this,"CImg<T>::det");
07882       switch (width) {
07883       case 1: return (*this)(0,0);
07884       case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
07885       case 3: 
07886         {
07887           const double
07888             a = data[0], d = data[1], g = data[2],
07889             b = data[3], e = data[4], h = data[5],
07890             c = data[6], f = data[7], i = data[8];
07891           return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
07892         }
07893       }
07894       return 0;
07895     }
07897     double norm(const int ntype=2) const {
07898       cimg_test(*this,"CImg<T>::norm");
07899       double res = 0;
07900       switch (ntype) {
07901       case -1: {
07902         cimg_mapoff(*this,off) {
07903           const double tmp = cimg::abs((double)data[off]);
07904           if (tmp>res) res = tmp;
07905         }
07906         return res; 
07907       } break;
07908       case 1 : { 
07909         cimg_mapoff(*this,off) res+=cimg::abs((double)data[off]); 
07910         return res;
07911       } break;
07912       default: { return std::sqrt(dot(*this)); }
07913       }
07914       return 0;
07915     }
07917     double sum() const {
07918       cimg_test(*this,"CImg<T>::sum");          
07919       double res=0;
07920       cimg_map(*this,ptr,T) res+=*ptr;
07921       return res;
07922     }
07923 
07925     template<typename t> const CImg& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,const bool sorting=true) const {
07926       cimg_test_matrix(*this,"CImg<T>::SVD");
07927       U = *this;
07928       if (S.size()<width) S = CImg<t>(1,width);
07929       if (V.width<width || V.height<height) V = CImg<t>(width,width);
07930       CImg<t> rv1(width);  
07931       t anorm=0,c,f,g=0,h,s,scale=0;
07932       int l=0,nm=0;
07933      
07934       cimg_mapX(U,i) {
07935         l = i+1; rv1[i] = scale*g; g = s = scale = 0;
07936         if (i<dimy()) {
07937           for (int k=i; k<dimy(); k++) scale+= cimg::abs(U(i,k));
07938           if (scale) {
07939             for (int k=i; k<dimy(); k++) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
07940             f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i)=f-g;
07941             for (int j=l; j<dimx(); j++) {
07942               s = 0; for (int k=i; k<dimy(); k++) s+= U(i,k)*U(j,k);
07943               f = s/h;
07944               { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); }
07945             }
07946             { for (int k=i; k<dimy(); k++) U(i,k)*= scale; }
07947           }
07948         }
07949         S[i]=scale*g;
07950         
07951         g = s = scale = 0;
07952         if (i<dimy() && i!=dimx()-1) {
07953           for (int k=l; k<dimx(); k++) scale += cimg::abs(U(k,i));
07954           if (scale) {
07955             for (int k=l; k<dimx(); k++) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
07956             f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
07957             { for (int k=l; k<dimx(); k++) rv1[k]=U(k,i)/h; }
07958             for (int j=l; j<dimy(); j++) {
07959               s=0; for (int k=l; k<dimx(); k++) s+= U(k,j)*U(k,i);
07960               { for (int k=l; k<dimx(); k++) U(k,j)+= s*rv1[k]; }
07961             }
07962             { for (int k=l; k<dimx(); k++) U(k,i)*= scale; }
07963           }
07964         }
07965         anorm=cimg::max((t)anorm,(cimg::abs(S[i])+cimg::abs(rv1[i])));
07966       }
07967       
07968       { for (int i=dimx()-1; i>=0; i--) {
07969         if (i<dimx()-1) {
07970           if (g) {
07971             { for (int j=l; j<dimx(); j++) V(i,j) =(U(j,i)/U(l,i))/g; }
07972             for (int j=l; j<dimx(); j++) {
07973               s=0; for (int k=l; k<dimx(); k++) s+= U(k,i)*V(j,k);
07974               { for (int k=l; k<dimx(); k++) V(j,k)+= s*V(i,k); }
07975             }
07976           }
07977           for (int j=l; j<dimx(); j++) V(j,i)=V(i,j)=0.0;
07978         }
07979         V(i,i) = 1.0; g = rv1[i]; l = i;
07980       }
07981       }
07982       
07983       { for (int i=cimg::min(dimx(),dimy())-1; i>=0; i--) {
07984         l = i+1; g = S[i];
07985         for (int j=l; j<dimx(); j++) U(j,i) = 0;
07986         if (g) {
07987           g = 1/g;
07988           for (int j=l; j<dimx(); j++) {
07989             s=0; for (int k=l; k<dimy(); k++) s+= U(i,k)*U(j,k);
07990             f = (s/U(i,i))*g;
07991             { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); }
07992           }
07993           { for (int j=i; j<dimy(); j++) U(i,j)*= g; }
07994         } else for (int j=i; j<dimy(); j++) U(i,j)=0;
07995         U(i,i)++;
07996       }
07997       }
07998       
07999       for (int k=dimx()-1; k>=0; k--) {
08000         for (int its=0; its<40; its++) {
08001           bool flag = true;
08002           for (l=k; l>=0; l--) {
08003             nm = l-1;
08004             if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
08005             if ((cimg::abs(S[nm])+anorm)==anorm) break;
08006           }
08007           if (flag) {
08008             c = 0; s = 1;
08009             for (int i=l; i<=k; i++) {
08010               f = s*rv1[i]; rv1[i] = c*rv1[i];
08011               if ((cimg::abs(f)+anorm)==anorm) break;
08012               g = S[i]; h = (t)cimg::pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
08013               cimg_mapY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; }
08014             }
08015           }
08016           const t& z = S[k];
08017           if (l==k) { if (z<0) { S[k] = -z; cimg_mapX(U,j) V(k,j) = -V(k,j); } break; }
08018           cimg::warn(its>=39,"CImg<%s>::SVD() : SVD failed to converge",pixel_type());
08019           nm = k-1; 
08020           t x = S[l], y = S[nm]; 
08021           g = rv1[nm]; h = rv1[k];
08022           f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
08023           g = (t)cimg::pythagore(f,1.0);
08024           f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
08025           c = s = 1;
08026           for (int j=l; j<=nm; j++) {
08027             const int i = j+1;
08028             g = rv1[i]; h = s*g; g = c*g;
08029             t y = S[i];
08030             t z = (t)cimg::pythagore(f,h); 
08031             rv1[j] = z; c = f/z; s = h/z;
08032             f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
08033             cimg_mapX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; }
08034             z = (t)cimg::pythagore(f,h); S[j] = z;
08035             if (z) { z = 1/z; c = f*z; s = h*z; }
08036             f = c*g+s*y; x = c*y-s*g;
08037             { cimg_mapY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; }}
08038           }
08039           rv1[l] = 0; rv1[k]=f; S[k]=x;
08040         }
08041       }
08042       
08043       if (sorting) {
08044         CImg<int> permutations(width);
08045         S.quicksort(permutations,false);
08046         cimg_mapX(permutations,x) {
08047           const int n = permutations(x);
08048           if (x<n) {
08049             cimg_mapY(U,k) cimg::swap(U(x,k),U(n,k));
08050             cimg_mapY(V,l) cimg::swap(V(x,l),V(n,l));
08051           }
08052         }
08053       }
08054       return *this;
08055     }
08056 
08058     template<typename t> const CImg& SVD(CImgl<t>& USV) const {
08059       if (USV.size<3) USV = CImgl<t>(3);
08060       return SVD(USV[0],USV[1],USV[2]);      
08061     }
08062     
08064     CImgl<T> get_SVD(const bool sorting=true) const {
08065       CImgl<T> res(3);
08066       SVD(res[0],res[1],res[2],sorting);
08067       return res;
08068     }
08069         
08071     template<typename t> const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
08072       cimg_test_square(*this,"CImg<T>::eigen");
08073       if (val.size()<width) val = CImg<t>(1,width);
08074       if (vec.size()<width*width) vec = CImg<t>(width,width);
08075       switch(width) {
08076       case 1: { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
08077       case 2: {
08078         const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
08079         double f = e*e-4*(a*d-b*c);
08080         cimg::warn(f<0,"CImg<%s>::eigen() : Complex eigenvalues",pixel_type());
08081         f = std::sqrt(f);
08082         const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
08083         double u, v, n;
08084         val[0]=(t)l2; val[1]=(t)l1;
08085         if (cimg::abs(b)>cimg::abs(a-l2)) { u = 1; v = (l2-a)/b; }
08086         else { if (a-l2!=0) { u = -b/(a-l2); v = 1; } else { u = 0; v = 1; } }
08087         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec(0,0) = (t)u; vec(0,1) = (t)v;
08088         if (cimg::abs(b)>cimg::abs(a-l1)) { u = 1; v = (l1-a)/b; }
08089         else { if (a-l1!=0) { u = -b/(a-l1); v = 1; } else { u = 1; v = 0; } }
08090         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec(1,0) = (t)u; vec(1,1) = (t)v;
08091       } break;
08092       default: 
08093         throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices "
08094                                     "(given is %ux%u)", pixel_type(),width,height);
08095       }
08096       return *this;
08097     }
08098 
08100     CImgl<T> get_eigen() const { CImgl<T> res(2); eigen(res[0],res[1]); return res; }
08101     
08103     template<typename t> const CImg<T>& eigen(CImgl<t>& eig) const {
08104       if (eig.size<2) eig = CImgl<t>(2);
08105       eigen(eig[0],eig[1]);
08106       return *this; 
08107     }
08108     
08110     template<typename t> const CImg<T>& symeigen(CImg<t>& val, CImg<t>& vec) const {
08111       cimg_test_square(*this,"CImg<T>::symeigen");
08112       if (val.size()<width) val = CImg<t>(width);
08113       if (vec.data && vec.size()<width*width) vec = CImg<t>(width,width);
08114       if (width<3) return eigen(val,vec);     
08115       CImg<t> V(width,width);
08116       return SVD(vec,val,V,true);
08117     }
08118 
08120     CImgl<T> get_symeigen() const { CImgl<T> res(2); symeigen(res[0],res[1]); return res; }
08121 
08123     template<typename t> const CImg<T>& symeigen(CImgl<t>& eig) const {
08124       if (eig.size<2) eig = CImgl<t>(2);
08125       symeigen(eig[0],eig[1]);
08126       return *this;
08127     }
08128 
08129     template<typename t> CImg<T>& _quicksort(const int min,const int max,CImg<t>& permutations,const bool increasing) {
08130       if (min<max) {      
08131         const int mid = (min+max)/2;
08132         if (increasing) {
08133           if ((*this)[min]>(*this)[mid]) {
08134             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08135           if ((*this)[mid]>(*this)[max]) {
08136             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
08137           if ((*this)[min]>(*this)[mid]) {
08138             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08139         } else {
08140           if ((*this)[min]<(*this)[mid]) {
08141             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08142           if ((*this)[mid]<(*this)[max]) {
08143             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
08144           if ((*this)[min]<(*this)[mid]) {
08145             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08146         }
08147         if (max-min>=3) {
08148           const T pivot = (*this)[mid];
08149           int i = min, j = max;
08150           if (increasing) {
08151             do {
08152               while ((*this)[i]<pivot) i++; while ((*this)[j]>pivot) j--;
08153               if (i<=j) {
08154                 cimg::swap((*this)[i],(*this)[j]);
08155                 cimg::swap(permutations[i],permutations[j]);
08156                 i++; j--; }
08157             } while (i<=j);
08158           } else {
08159             do {
08160               while ((*this)[i]>pivot) i++; while ((*this)[j]<pivot) j--;
08161               if (i<=j) {
08162                 cimg::swap((*this)[i],(*this)[j]);
08163                 cimg::swap(permutations[i],permutations[j]);
08164                 i++; j--; }
08165             } while (i<=j);
08166           }
08167           if (min<j) _quicksort(min,j,permutations,increasing);
08168           if (i<max) _quicksort(i,max,permutations,increasing);
08169         }
08170       }
08171       return *this;
08172     }
08173 
08175     template<typename t>
08176     CImg<T>& quicksort(CImg<t>& permutations,const bool increasing=true) {
08177       cimg_test(*this,"CImg<T>::quicksort");
08178       if (permutations.size()!=size()) permutations = CImg<t>(size());
08179       cimg_mapoff(permutations,off) permutations[off] = off;
08180       return _quicksort(0,size()-1,permutations,increasing); 
08181     }
08182 
08184     CImg<T>& quicksort(const bool increasing=true) { CImg<T> foo; return quicksort(foo,increasing); }
08185 
08187     template<typename t> CImg<T>& get_quicksort(CImg<t>& permutations,const bool increasing=true) {
08188       return CImg<T>(*this).quicksort(permutations,increasing);
08189     }
08190 
08192     CImg<T>& get_quicksort(const bool increasing=true) { 
08193       return CImg<T>(*this).quicksort(increasing); 
08194     }
08195     
08197     //------------------------------------------
08198     //------------------------------------------
08199     //
08201 
08202     //------------------------------------------
08203     //------------------------------------------
08204   
08206     const CImg& display(CImgDisplay& disp,const unsigned int ymin=0,const unsigned int ymax=~0) const { disp.display(*this,ymin,ymax); return *this; }
08207 
08209     const CImg& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
08210   
08214     const CImg& display(const char* title,const int min_size=128,const int max_size=1024) const {
08215       cimg_test(*this,"CImg<T>::display");
08216       CImgDisplay *disp;
08217       unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3];
08218       print(title);
08219       const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
08220       if (dmin<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); }
08221       const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
08222       if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); }
08223       disp = new CImgDisplay(CImg<unsigned char>(w,h,1,1,0),title,0,3);
08224       XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2;
08225       while (!disp->closed && !disp->key) feature_selection(NULL,1,*disp,XYZ);
08226       delete disp;
08227       return *this;
08228     }
08229 
08231     const CImg& display(const int min_size=128,const int max_size=1024) const { return display("",min_size,max_size); }
08232   
08234     const CImg& feature_selection(int *const selection, const int feature_type,CImgDisplay &disp,
08235                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
08236       cimg_test(*this,"CImg<T>::feature_selection");
08237       if (disp.events<3) 
08238         throw CImgArgumentException("CImg<%s>::feature_selection() : Input display must be able to catch keyboard"
08239                                     "and mouse events (events>=3). Given display has 'events = %s'.",
08240                                     pixel_type(),disp.events);
08241       unsigned char fgcolor[3]={255,255,105}, bgcolor[3]={0,0,0};
08242       if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv()));
08243       int carea=0,area=0,phase=0,
08244         X0=(XYZ?XYZ[0]:width/2)%width, Y0=(XYZ?XYZ[1]:height/2)%height, Z0=(XYZ?XYZ[2]:depth/2)%depth, 
08245         X=-1,Y=-1,Z=-1,oX=-1,oY=-1,oZ=-1,X1=-1,Y1=-1,Z1=-1;
08246       unsigned int hatch=feature_type?0xF0F0F0F0:~0L;
08247       bool feature_selected = false, ytext = false;
08248       CImg<unsigned char> visu, visu0;
08249       char text[1024];
08250     
08251       while (!disp.key && !disp.closed && !feature_selected) {
08252 
08253         // Init visu0 if necessary
08254         if (disp.resized || !visu0.data) { 
08255           if (disp.resized) disp.resize();
08256           if (depth==1) visu0=get_normalize(0,(T)255); else visu0=get_3dplanes(X0,Y0,Z0).get_normalize(0,(T)255);
08257           visu0.resize(disp.width,disp.height,1,cimg::min(3,dimv()));
08258         }
08259         visu = visu0;      
08260         
08261         // Handle motion and selection
08262         const int mx = disp.mouse_x, my = disp.mouse_y, b = disp.button;
08263         if (mx>=0 && my>=0) {
08264           const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
08265           if (mX<dimx() && mY<dimy())   { area=1; X=mX; Y=mY; Z=phase?Z1:Z0; }
08266           if (mX<dimx() && mY>=dimy())  { area=2; X=mX; Y=phase?Y1:Y0; Z=mY-height; }
08267           if (mX>=dimx() && mY<dimy())  { area=3; X=phase?X1:X0; Y=mY; Z=mX-width;  }
08268           if (mX>=dimx() && mY>=dimy()) { X=X0; Y=Y0; Z=Z0; }
08269           if ((!(phase%2) && (b&1)) || (phase%2 && !(b&1))) { 
08270             if (!carea) carea=area;
08271             if (!(phase++)) { X0=X; Y0=Y; Z0=Z; }
08272           }
08273           if (b&2) { if (!phase) { X0=X; Y0=Y; Z0=Z; } else { X1=Y1=Z1=-1; phase=carea=0; }}
08274           if ((b&2 || phase) && depth>1) 
08275             visu0 = get_3dplanes(X,Y,Z).normalize(0,(T)255).resize(disp.width,disp.height,1,cimg::min(3,dimv()));
08276           if (phase) {
08277             if (!feature_type) feature_selected = phase?true:false;
08278             else {
08279               if (depth>1) feature_selected = (phase==3)?true:false;
08280               else feature_selected = (phase==2)?true:false;
08281             }   
08282             if (!feature_selected) {
08283               if (phase<2) { X1=X; Y1=Y; Z1=Z; }
08284               else switch(carea) {
08285               case 1: Z1=Z; break;
08286               case 2: Y1=Y; break;
08287               case 3: X1=X; break;
08288               }
08289             }
08290           }
08291           if (!phase || !feature_type) {
08292             if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y);
08293             cimg_mapV(*this,k) std::sprintf(text+cimg::strlen(text),"%g ",(double)(*this)(X,Y,Z,k));
08294             std::sprintf(text+cimg::strlen(text),"}");
08295             if (!feature_type) { X1=X0; Y1=Y0; Z1=Z0; }
08296           } else
08297             switch (feature_type) {
08298             case 1: {
08299                 const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
08300                 if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm);
08301                 else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm);
08302             } break;
08303             case 2:
08304               if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)",
08305                                         X0<X1?X0:X1,Y0<Y1?Y0:Y1,Z0<Z1?Z0:Z1,
08306                                         X0<X1?X1:X0,Y0<Y1?Y1:Y0,Z0<Z1?Z1:Z0,
08307                                         1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
08308               else  std::sprintf(text,"Box (%d,%d)-(%d,%d), Size=(%d,%d)",
08309                                  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));
08310               break;
08311             case 3:
08312               if (depth>1) std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii=(%d,%d,%d)",
08313                                         X0,Y0,Z0,X1,Y1,Z1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
08314               else  std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii=(%d,%d)",
08315                                  X0,Y0,X1,Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
08316 
08317               break;
08318             }
08319           if (my<12) ytext=true;
08320           if (my>=visu.dimy()-11) ytext=false;
08321           visu.draw_text(text,0,ytext?visu.dimy()-11:0,fgcolor,bgcolor,0.7f);
08322         } else { X=Y=Z=-1; if (phase) disp.button=phase%2; }
08323         
08324         // Draw image + selection on display window
08325         if (X>=0 && Y>=0 && Z>=0) {
08326           hatch=cimg::ror(hatch);
08327           if (feature_type==1 && phase) {
08328             const int d=(depth>1)?depth:0,
08329               x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)),
08330               x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d));
08331             visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch);
08332             if (d) {
08333               const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)),
08334                 zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d));
08335               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);
08336             }
08337           } else switch(feature_type) {
08338           case 2: {
08339             const bool cond=(phase&&feature_type);
08340             const int d=(depth>1)?depth:0,
08341               nX0=cond?X0:X, nY0=cond?Y0:Y, nZ0=cond?Z0:Z,
08342               nX1=cond?X1:X, nY1=cond?Y1:Y, nZ1=cond?Z1:Z,
08343               x0=(nX0<nX1?nX0:nX1)*disp.width/(width+d),
08344               y0=(nY0<nY1?nY0:nY1)*disp.height/(height+d),
08345               x1=((nX0<nX1?nX1:nX0)+1)*disp.width/(width+d)-1,
08346               y1=((nY0<nY1?nY1:nY0)+1)*disp.height/(height+d)-1;
08347             const unsigned int nhatch=phase?hatch:~0L;
08348             visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,nhatch).
08349               draw_line(x1,y0,x1,y1,fgcolor,nhatch).draw_line(x1,y1,x0,y1,fgcolor,nhatch).draw_line(x0,y1,x0,y0,fgcolor,nhatch);
08350             if (d) {
08351               const int
08352                 zx0=(int)((width+(nZ0<nZ1?nZ0:nZ1))*disp.width/(width+d)),
08353                 zy0=(int)((height+(nZ0<nZ1?nZ0:nZ1))*disp.height/(height+d)),
08354                 zx1=(int)((width+(nZ0<nZ1?nZ1:nZ0)+1)*disp.width/(width+d))-1,
08355                 zy1=(int)((height+(nZ0<nZ1?nZ1:nZ0)+1)*disp.height/(height+d))-1;
08356               visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,nhatch).
08357                 draw_line(zx1,y0,zx1,y1,fgcolor,nhatch).draw_line(zx1,y1,zx0,y1,fgcolor,nhatch).draw_line(zx0,y1,zx0,y0,fgcolor,nhatch);
08358               visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,nhatch).
08359                 draw_line(x1,zy0,x1,zy1,fgcolor,nhatch).draw_line(x1,zy1,x0,zy1,fgcolor,nhatch).draw_line(x0,zy1,x0,zy0,fgcolor,nhatch);
08360             }
08361           } break;
08362           case 3: {
08363             const bool cond=(phase&&feature_type);
08364             const int d=(depth>1)?depth:0,
08365               x0=(cond?X0:X)*disp.width/(width+d),
08366               y0=(cond?Y0:Y)*disp.height/(height+d),
08367               x1=(cond?X1:X)*disp.width/(width+d)-1,
08368               y1=(cond?Y1:Y)*disp.height/(height+d)-1;
08369             const unsigned int nhatch=phase?hatch:~0L;
08370             visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f).
08371                          draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch);
08372             if (d) {
08373               const int
08374                 zx0=(int)((width+(cond?Z0:Z))*disp.width/(width+d)),
08375                 zy0=(int)((height+(cond?Z0:Z))*disp.height/(height+d)),
08376                 zx1=(int)((width+(cond?Z1:Z)+1)*disp.width/(width+d))-1,
08377                 zy1=(int)((height+(cond?Z1:Z)+1)*disp.height/(height+d))-1;
08378               visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f).
08379                                    draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch).
08380                                    draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,0L,0.2f).
08381                                    draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,nhatch);
08382             }
08383           } break;
08384           }
08385         }
08386         visu.display(disp).wait(32);
08387         if ((!feature_selected && !phase && oX==X && oY==Y && oZ==Z) || (X<0 || Y<0 || Z<0)) disp.wait();
08388         oX=X; oY=Y; oZ=Z;
08389       }
08390 
08391       // Return result
08392       if (XYZ) { XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; }
08393       if (feature_selected) {
08394         if (feature_type==2) {
08395           if (X0>X1) cimg::swap(X0,X1);
08396           if (Y0>Y1) cimg::swap(Y0,Y1);
08397           if (Z0>Z1) cimg::swap(Z0,Z1);
08398         }
08399         if (selection) {
08400           if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1;
08401           switch(feature_type) {
08402           case 1:
08403           case 2:  selection[3] = X1; selection[4] = Y1; selection[5] = Z1;
08404           default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0;
08405           }
08406         }
08407       } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1;
08408       disp.button=0;
08409       return *this;
08410     }
08411 
08413     const CImg& feature_selection(int *const selection, const int feature_type,
08414                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
08415       unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0);
08416       const unsigned int dmin = cimg::min(w,h), minsiz = 256;
08417       if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
08418       const unsigned int dmax = cimg::max(w,h), maxsiz = 1024;
08419       if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
08420       CImgDisplay disp(w,h,"",0,3);
08421       return feature_selection(selection,feature_type,disp,XYZ,color);
08422     }
08423   
08425     //------------------------------------------
08426     //------------------------------------------
08427     //
08429 
08430     //------------------------------------------
08431     //------------------------------------------
08432 
08434 
08440     static CImg load(const char *filename) {
08441       if (!filename) throw CImgArgumentException("CImg<%s>::load() : Can't load (null) filename",pixel_type());
08442       const char *ext = cimg::filename_split(filename);
08443       if (!cimg::strcasecmp(ext,"asc")) return load_ascii(filename);
08444       if (!cimg::strcasecmp(ext,"dlm")) return load_dlm(filename);
08445       if (!cimg::strcasecmp(ext,"inr")) return load_inr(filename);
08446       if (!cimg::strcasecmp(ext,"hdr")) return load_analyze(filename);
08447       if (!cimg::strcasecmp(ext,"pan")) return load_pandore(filename);
08448       if (!cimg::strcasecmp(ext,"bmp")) return load_bmp(filename);
08449       if (!cimg::strcasecmp(ext,"png")) return load_png(filename);
08450       if (!cimg::strcasecmp(ext,"jpg") ||
08451           !cimg::strcasecmp(ext,"jpeg")) return load_jpeg(filename);
08452       if (!cimg::strcasecmp(ext,"ppm") || 
08453           !cimg::strcasecmp(ext,"pgm") ||
08454           !cimg::strcasecmp(ext,"pnm")) return load_pnm(filename);
08455       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return load_raw(filename);      
08456       return load_convert(filename);
08457     }
08458 
08460     static CImg load_ascii(const char *filename) {
08461       std::FILE *file = cimg::fopen(filename,"rb");
08462       char line[256] = {0};
08463       std::fscanf(file,"%255[^\n]",line);
08464       unsigned int off;
08465           int err=1, dx=0, dy=1, dz=1, dv=1;
08466       std::sscanf(line,"%d %d %d %d",&dx,&dy,&dz,&dv);
08467       if (!dx || !dy || !dz || !dv)
08468         throw CImgIOException("CImg<%s>::load_ascii() : File '%s' does not appear to be a valid ASC file.\n"
08469                               "Specified image dimensions are (%d,%d,%d,%d)",pixel_type(),filename,dx,dy,dz,dv);
08470       CImg dest(dx,dy,dz,dv);
08471       double val;
08472       T *ptr = dest.data;
08473       for (off=0; off<dest.size() && err==1; off++) {
08474         err = std::fscanf(file,"%lf%*[^0-9.eE+-]",&val); 
08475         *(ptr++)=(T)val; 
08476       }
08477       cimg::warn(off<dest.size(),"CImg<%s>::load_ascii() : File '%s', only %u values read, instead of %u",
08478                  pixel_type(),filename,off,dest.size());
08479       cimg::fclose(file);
08480       return dest;
08481     }
08482 
08484     static CImg load_dlm(const char *filename) {
08485       std::FILE *file = cimg::fopen(filename,"r");
08486       unsigned int cdx=0,dx=0,dy=0;
08487       double val;
08488       char c, delimiter[256]={0}, tmp[256];
08489       int err;
08490       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
08491         c=0;
08492         if (err>0) cdx++;
08493         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { dx = cimg::max(cdx,dx); dy++; cdx=0; }
08494       }
08495       if (!dx || !dy) throw CImgIOException("CImg<%s>::load_dlm() : File '%s' does not appear to be a "
08496                                             "valid DLM file (width = %d, height = %d)\n",pixel_type(),filename,dx,dy);
08497       std::rewind(file);
08498       CImg<T> dest(dx,dy,1,1,0);
08499       unsigned int x = 0, y = 0;
08500       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
08501         c=0;
08502         if (err>0) dest(x++,y) = (T)val;
08503         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { x=0; y++; }
08504       }
08505       cimg::fclose(file);
08506       return dest;
08507     }
08508 
08510     static CImg load_pnm(const char *filename) {
08511       std::FILE *file=cimg::fopen(filename,"rb");
08512       char item[1024]={0};
08513       unsigned int ppm_type,width,height,colormax=255;
08514       int err;
08515       
08516       while ((err=std::fscanf(file,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08517       if(std::sscanf(item," P%u",&ppm_type)!=1) 
08518         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',PPM header 'P?' not found",pixel_type(),filename);
08519       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08520       if (std::sscanf(item," %u %u",&width,&height)!=2)
08521         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',WIDTH and HEIGHT not defined",pixel_type(),filename);
08522       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08523       std::fgetc(file);
08524       cimg::warn(std::sscanf(item,"%u",&colormax)!=1,
08525                  "CImg<%s>::load_pnm() : file '%s',COLORMAX not defined",pixel_type(),filename);
08526       
08527       CImg dest;
08528       int rval,gval,bval;
08529 
08530       switch (ppm_type) {
08531       case 2: { // Grey Ascii
08532         dest = CImg<T>(width,height,1,1);
08533         T* rdata = dest.ptr();
08534         cimg_mapoff(dest,off) { std::fscanf(file,"%d",&rval); *(rdata++)=(T)rval; }
08535       } break;
08536       case 3: { // Color Ascii
08537         dest = CImg<T>(width,height,1,3);
08538         T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2);
08539         cimg_mapXY(dest,x,y) { 
08540           std::fscanf(file,"%d %d %d",&rval,&gval,&bval);
08541           *(rdata++)=(T)rval; 
08542           *(gdata++)=(T)gval; 
08543           *(bdata++)=(T)bval; }
08544       } break;
08545       case 5: { // Grey Binary
08546         if (colormax<256) { // 8 bits
08547           CImg<unsigned char> raw(width,height,1,1);
08548           cimg::fread(raw.data,sizeof(unsigned char),width*height,file);
08549           dest = CImg<T>(raw);
08550         } else { // 16 bits
08551           CImg<unsigned short> raw(width,height,1,1);
08552           cimg::fread(raw.data,sizeof(unsigned short),width*height,file);
08553           dest = CImg<T>(raw);
08554         }
08555       } break;
08556       case 6: { // Color Binary
08557         if (colormax<256) { // 8 bits
08558           CImg<unsigned char> raw(width,height,1,3);
08559           cimg::fread(raw.data,sizeof(unsigned char),width*height*3,file);
08560           dest = CImg<T>(raw.data,width,height,1,3,true);
08561         } else { // 16 bits
08562           CImg<unsigned short> raw(width,height,1,3);
08563           cimg::fread(raw.data,sizeof(unsigned short),width*height*3,file);
08564           dest = CImg<T>(raw.data,width,height,1,3,true);
08565         }
08566       } break;
08567       default:
08568         cimg::fclose(file);
08569         throw CImgIOException("CImg<%s>::load_pnm() : file '%s', PPM type 'P%d' not supported",pixel_type(),filename,ppm_type);
08570       }
08571       cimg::fclose(file);
08572       return dest;
08573     }
08574 
08576     static CImg load_bmp(const char *filename) {
08577       unsigned char header[64];
08578       std::FILE *file = cimg::fopen(filename,"rb");
08579       cimg::fread(header,sizeof(unsigned char),54,file);
08580       if (header[0]!='B' || header[1]!='M')
08581         throw CImgIOException("CImg<%s>::load_bmp() : filename '%s' does not appear to be a valid BMP file",
08582                               pixel_type(),filename);
08583       
08584       // Read header and pixel buffer
08585       int
08586         file_size   = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
08587         offset      = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
08588         dx          = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
08589         dy          = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
08590         compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
08591         nb_colors   = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
08592         bpp         = header[0x1C] + (header[0x1D]<<8),
08593         *palette    = NULL;
08594       const int 
08595         dx_bytes   = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
08596         align      = (4-dx_bytes%4)%4,
08597         buf_size   = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
08598 
08599       if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors=0;
08600       if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,sizeof(int),nb_colors,file); }
08601       const int xoffset = offset-54-4*nb_colors;      
08602       if (xoffset>0) std::fseek(file,xoffset,SEEK_CUR);
08603       const unsigned char *buffer  = new unsigned char[buf_size], *ptrs = buffer;
08604       cimg::fread(buffer,sizeof(unsigned char),buf_size,file);
08605       cimg::fclose(file);
08606 
08607       // Decompress buffer (if necessary)
08608       if (compression) return load_convert(filename);
08609       
08610       // Read pixel data
08611       CImg res(dx,cimg::abs(dy),1,3);
08612       switch (bpp) {
08613       case 1: { // Monochrome
08614         for (int y=res.height-1; y>=0; y--) { 
08615           unsigned char mask = 0x80, val = 0;
08616           cimg_mapX(res,x) {
08617             if (mask==0x80) val = *(ptrs++);
08618             const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
08619             res(x,y,2) = (T)*(col++);
08620             res(x,y,1) = (T)*(col++);
08621             res(x,y,0) = (T)*(col++);
08622             mask = cimg::ror(mask);
08623           } ptrs+=align; }
08624       } break;
08625       case 4: { // 16 colors
08626         for (int y=res.height-1; y>=0; y--) { 
08627           unsigned char mask = 0xF0, val = 0;
08628           cimg_mapX(res,x) {
08629             if (mask==0xF0) val = *(ptrs++);
08630             const unsigned char color = (mask<16)?(val&mask):((val&mask)>>4);
08631             unsigned char *col = (unsigned char*)(palette+color);
08632             res(x,y,2) = (T)*(col++);
08633             res(x,y,1) = (T)*(col++);
08634             res(x,y,0) = (T)*(col++);
08635             mask = cimg::ror(mask,4);
08636           } ptrs+=align; }
08637       } break;
08638       case 8: { //  256 colors
08639         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08640           const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
08641           res(x,y,2) = (T)*(col++);
08642           res(x,y,1) = (T)*(col++);
08643           res(x,y,0) = (T)*(col++);
08644         } ptrs+=align; }
08645       } break;
08646       case 16: { // 16 bits colors
08647         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08648           const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
08649           const unsigned short col = c1+(c2<<8);
08650           res(x,y,2) = (T)(col&0x1F);
08651           res(x,y,1) = (T)((col>>5)&0x1F);
08652           res(x,y,0) = (T)((col>>10)&0x1F);
08653         } ptrs+=align; }
08654       } break;  
08655       case 24: { // 24 bits colors
08656         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08657           res(x,y,2) = (T)*(ptrs++);
08658           res(x,y,1) = (T)*(ptrs++);
08659           res(x,y,0) = (T)*(ptrs++);
08660         } ptrs+=align; }
08661       } break;
08662       case 32: { // 32 bits colors
08663         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08664           res(x,y,2) = (T)*(ptrs++);
08665           res(x,y,1) = (T)*(ptrs++);
08666           res(x,y,0) = (T)*(ptrs++);
08667           ptrs++;
08668         } ptrs+=align; }
08669       } break;
08670       }
08671 
08672       if (palette) delete[] palette;
08673       delete[] buffer;
08674       if (dy<0) res.flip('y');
08675       return res;
08676     }
08677     
08679     // Note : Most of this function has been written by Eric Fausett
08680     static CImg load_png(const char *filename) {
08681 #ifndef cimg_use_png
08682       return load_convert(filename);
08683 #else
08684       // Open file and check for PNG validity
08685       unsigned char pngCheck[8];
08686       std::FILE *file = cimg::fopen(filename,"rb");
08687       cimg::fread(pngCheck,sizeof(unsigned char),8,file);
08688       if(png_sig_cmp(pngCheck,0,8)){
08689         cimg::fclose(file);
08690         throw CImgIOException("CImg<%s>::load_png() : filename '%s' does not appear to be a valid PNG file",pixel_type(),filename);
08691       }
08692       
08693       // Setup PNG structures for read
08694       png_voidp user_error_ptr=0;
08695       png_error_ptr user_error_fn=0, user_warning_fn=0;
08696       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,       // Verifies libpng version correct
08697                                                    user_error_ptr, user_error_fn, user_warning_fn);
08698       if(!png_ptr){
08699         cimg::fclose(file);
08700         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'png_ptr' data structure",pixel_type());
08701       }
08702       png_infop info_ptr = png_create_info_struct(png_ptr);
08703       if(!info_ptr){
08704         cimg::fclose(file);
08705         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);                  
08706         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'info_ptr' data structure",pixel_type());
08707       }
08708       png_infop end_info = png_create_info_struct(png_ptr);
08709       if(!end_info){
08710         cimg::fclose(file);
08711         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);                 
08712         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'end_info' data structure",pixel_type());
08713       }
08714       
08715       // Error handling callback for png file reading
08716       if (setjmp(png_jmpbuf(png_ptr))){
08717         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
08718         cimg::fclose(file);
08719         throw CImgIOException("CImg<%s>::load_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
08720       }      
08721       png_init_io(png_ptr, file);      
08722       png_set_sig_bytes(png_ptr, 8);
08723       
08724       // Get PNG Header Info up to data block
08725       png_read_info(png_ptr, info_ptr);      
08726       png_uint_32 width, height;
08727       int bit_depth, color_type, interlace_type;
08728       png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type,
08729                    int_p_NULL, int_p_NULL);
08730       int new_bit_depth = bit_depth;
08731       int new_color_type = color_type;
08732       
08733       // Transforms to unify image data         
08734       if (new_color_type == PNG_COLOR_TYPE_PALETTE){
08735         png_set_palette_to_rgb(png_ptr);
08736         new_color_type -= PNG_COLOR_MASK_PALETTE;
08737         new_bit_depth = 8;
08738       }
08739       if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
08740         png_set_gray_1_2_4_to_8(png_ptr);
08741         new_bit_depth = 8;
08742       }
08743       if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
08744         png_set_tRNS_to_alpha(png_ptr);
08745       if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
08746         png_set_gray_to_rgb(png_ptr);
08747         new_color_type |= PNG_COLOR_MASK_COLOR;
08748       }
08749       if (new_color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);      
08750       png_read_update_info(png_ptr, info_ptr);      
08751       if (!(new_bit_depth==8 || new_bit_depth==16))
08752         throw CImgIOException("CImg<%s>::load_png() : Wrong bit coding 'bit_depth=%u'",pixel_type(),new_bit_depth);
08753       const int byte_depth = new_bit_depth>>3;
08754       
08755       // Allocate Memory for Image Read
08756       png_bytep *imgData = new png_bytep[height];
08757       for (unsigned int row=0; row < height; row++) imgData[row] = new png_byte[byte_depth * 4 * width];
08758       png_read_image(png_ptr, imgData);
08759       png_read_end(png_ptr, end_info);
08760       
08761       // Read pixel data
08762       if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA))
08763         throw CImgIOException("CImg<%s>::load_png() : Wrong color coding new_color_type=%u",pixel_type(),new_color_type);
08764       const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
08765       CImg res(width,height,1,no_alpha_channel?3:4);
08766       const unsigned long off = width*height;
08767       T *ptr1 = res.data, *ptr2 = ptr1+off, *ptr3 = ptr2+off, *ptr4 = ptr3+off;
08768       switch(new_bit_depth){
08769       case 8: {
08770         cimg_mapY(res,y){
08771           const unsigned char *ptrs = imgData[y];
08772           cimg_mapX(res,x){
08773             *(ptr1++) = (T)*(ptrs++);
08774             *(ptr2++) = (T)*(ptrs++);
08775             *(ptr3++) = (T)*(ptrs++);
08776             if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++);
08777           }
08778         }
08779       } break;
08780       case 16: {
08781         cimg_mapY(res,y){
08782           const unsigned short *ptrs = (unsigned short*)(imgData[y]);
08783           cimg_mapX(res,x){
08784             *(ptr1++) = (T)*(ptrs++);
08785             *(ptr2++) = (T)*(ptrs++);
08786             *(ptr3++) = (T)*(ptrs++);
08787             if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++);
08788           }
08789         }
08790       } break;
08791       }
08792       png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
08793       
08794       // Deallocate Image Read Memory
08795       for (unsigned int n=0; n<height; n++) delete[] imgData[n];
08796       delete[] imgData;      
08797       cimg::fclose(file);
08798       return res;      
08799 #endif      
08800     }
08801 
08802 
08804     static CImg load_jpeg(const char *filename) {
08805 #ifndef cimg_use_jpeg
08806       return load_convert(filename);
08807 #else
08808       struct jpeg_decompress_struct cinfo;
08809       struct jpeg_error_mgr jerr;
08810       std::FILE *file = cimg::fopen(filename,"rb");
08811       cinfo.err = jpeg_std_error(&jerr);
08812       jpeg_create_decompress(&cinfo);
08813       jpeg_stdio_src(&cinfo,file);
08814       jpeg_read_header(&cinfo,TRUE);
08815       jpeg_start_decompress(&cinfo);
08816       
08817       if (cinfo.output_components!=3) {
08818         cimg::warn(true,"CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
08819                    pixel_type(),filename);
08820         return load_convert(filename);
08821       }
08822       
08823       const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
08824       unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*3], *buf2 = buf;
08825       JSAMPROW row_pointer[1];
08826       while (cinfo.output_scanline < cinfo.output_height) {
08827         row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
08828         jpeg_read_scanlines(&cinfo,row_pointer,1);
08829       }
08830       jpeg_finish_decompress(&cinfo);
08831       jpeg_destroy_decompress(&cinfo);
08832       cimg::fclose(file);
08833       
08834       CImg<T> dest(cinfo.output_width,cinfo.output_height,1,3);
08835       T *ptr_r = dest.ptr(0,0,0,0),
08836         *ptr_g = dest.ptr(0,0,0,1),
08837         *ptr_b = dest.ptr(0,0,0,2);
08838       cimg_mapXY(dest,x,y) {
08839         *(ptr_r++) = *(buf2++);
08840         *(ptr_g++) = *(buf2++);
08841         *(ptr_b++) = *(buf2++);
08842       }
08843       delete[] buf;
08844       return dest;
08845 #endif
08846     }
08847     
08849     static CImg load_rgba(const char *filename,const unsigned int dimw,const unsigned int dimh) {
08850       std::FILE *file = cimg::fopen(filename,"rb");
08851       unsigned char *buffer = new unsigned char[dimw*dimh*4];
08852       cimg::fread(buffer,sizeof(unsigned char),dimw*dimh*4,file);
08853       cimg::fclose(file);
08854       CImg res = CImg<T>(buffer,dimw,dimh,1,4,true);
08855       delete[] buffer;
08856       return res;      
08857     }
08858 
08860     static CImg load_rgb(const char *filename,const unsigned int dimw,const unsigned int dimh) {
08861       std::FILE *file = cimg::fopen(filename,"rb");
08862       unsigned char *buffer = new unsigned char[dimw*dimh*3];
08863       cimg::fread(buffer,sizeof(unsigned char),dimw*dimh*3,file);
08864       cimg::fclose(file);
08865       CImg res = CImg<T>(buffer,dimw,dimh,1,3,true);
08866       delete[] buffer;
08867       return res;
08868     }
08869     
08871 #define cimg_load_inr_case(Tf,sign,pixsize,Ts)                            \
08872   if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) {      \
08873       Ts *xval, *val = new Ts[fopt[0]*fopt[3]];                           \
08874       cimg_mapYZ(dest,y,z) {                                              \
08875           cimg::fread(val,pixsize/8,fopt[0]*fopt[3],file);                \
08876           if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]);    \
08877           xval = val; cimg_mapX(dest,x) cimg_mapV(dest,k)                 \
08878                           dest(x,y,z,k) = (T)*(xval++);                   \
08879         }                                                                 \
08880       delete[] val;                                                       \
08881       loaded = true;                                                      \
08882     }
08883     
08884     static void _load_inr(std::FILE *file,int out[8],float *voxsize=NULL) {
08885       char item[1024],tmp1[64],tmp2[64];
08886       out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1;
08887       std::fscanf(file,"%63s",item);
08888       if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) 
08889         throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
08890                               "(INRIMAGE-4 identifier not found)",pixel_type());
08891       while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
08892         std::sscanf(item," XDIM%*[^0-9]%d",out);
08893         std::sscanf(item," YDIM%*[^0-9]%d",out+1);
08894         std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
08895         std::sscanf(item," VDIM%*[^0-9]%d",out+3);
08896         std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
08897         if (voxsize) {
08898           std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize);
08899           std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1);
08900           std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2);
08901         }
08902         if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
08903         switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
08904         case 0: break;
08905         case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
08906         case 1:
08907           if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4]=0;
08908           if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4]=1;
08909           if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4]=2;
08910           if (out[4]>=0) break;
08911         default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
08912         }
08913       }
08914       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
08915         throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
08916                               pixel_type(),out[0],out[1],out[2],out[3]);
08917       if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",pixel_type());
08918       if(out[6]<0) throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",pixel_type());
08919       if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",pixel_type());
08920     }
08921     
08922     static CImg load_inr(const char *filename, float *voxsize = NULL) {
08923       std::FILE *file = cimg::fopen(filename,"rb");
08924           int fopt[8], endian=cimg::endian()?1:0;
08925       bool loaded = false;
08926       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
08927       _load_inr(file,fopt,voxsize);
08928       CImg<T> dest = CImg<T>(fopt[0],fopt[1],fopt[2],fopt[3]);
08929       cimg_load_inr_case(0,0,8, unsigned char);
08930       cimg_load_inr_case(0,1,8, char);
08931       cimg_load_inr_case(0,0,16,unsigned short);
08932       cimg_load_inr_case(0,1,16,short);
08933       cimg_load_inr_case(0,0,32,unsigned int);
08934       cimg_load_inr_case(0,1,32,int);
08935       cimg_load_inr_case(1,0,32,float);
08936       cimg_load_inr_case(1,1,32,float);
08937       cimg_load_inr_case(1,0,64,double);
08938       cimg_load_inr_case(1,1,64,double);
08939       if (!loaded) throw CImgIOException("CImg<%s>::load_inr() : File '%s', can't read images of the type specified in the file",
08940                                          pixel_type(),filename);
08941       cimg::fclose(file);
08942       return dest;
08943     }
08944    
08945 #define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype)  \
08946   case nid: {                                                         \
08947     cimg::fread(dims,sizeof(unsigned int),nbdim,file);                \
08948     if (endian) cimg::endian_swap(dims,nbdim);                        \
08949     dest = CImg<T>(nwidth,nheight,ndepth,ndim);                       \
08950     stype *buffer = new stype[dest.size()];                           \
08951     cimg::fread(buffer,sizeof(stype),dest.size(),file);               \
08952     if (endian) cimg::endian_swap(buffer,dest.size());                \
08953     T *ptrd = dest.ptr();                                             \
08954     cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));               \
08955     buffer-=dest.size();                                              \
08956     delete[] buffer;                                                  \
08957    }                                                                  \
08958    break;
08959     
08960     static CImg load_pandore(const char *filename) {
08961       std::FILE *file = cimg::fopen(filename,"rb");
08962       typedef unsigned char uchar;
08963       typedef unsigned short ushort;
08964       typedef unsigned int uint;  
08965       typedef unsigned long ulong; 
08966       CImg dest;
08967       char tmp[16];
08968       cimg::fread(tmp,sizeof(char),12,file);
08969       if (cimg::strncasecmp("PANDORE",tmp,7)) 
08970         throw CImgIOException("CImg<%s>::load_pandore() : File '%s' does not appear to be a valid PANDORE file.\n"
08971                               "(PANDORE identifier not found)",pixel_type(),filename);
08972       unsigned int id,dims[8];
08973       long ptbuf[4];
08974       cimg::fread(&id,sizeof(int),1,file);
08975       const bool endian = (id>255);
08976       if (endian) cimg::endian_swap(id);
08977       cimg::fread(tmp,sizeof(char),20,file);
08978       switch (id) {
08979         cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
08980         cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
08981         cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
08982         cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
08983         cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
08984         cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
08985         cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
08986         cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
08987         cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
08988       case 11: { // Region 1D
08989         cimg::fread(dims,sizeof(unsigned int),3,file);
08990         if (endian) cimg::endian_swap(dims,3);
08991         dest = CImg<T>(dims[1],1,1,1);
08992         if (dims[2]<256) {
08993           unsigned char *buffer = new unsigned char[dest.size()];
08994           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
08995           T *ptrd = dest.ptr();
08996           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
08997           buffer-=dest.size();
08998           delete[] buffer;
08999         } else {
09000           if (dims[2]<65536) {
09001             unsigned short *buffer = new unsigned short[dest.size()];
09002             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
09003             if (endian) cimg::endian_swap(buffer,dest.size());
09004             T *ptrd = dest.ptr();
09005             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09006             buffer-=dest.size();
09007             delete[] buffer;
09008           } else {
09009             unsigned long *buffer = new unsigned long[dest.size()];
09010             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09011             if (endian) cimg::endian_swap(buffer,dest.size());
09012             T *ptrd = dest.ptr();
09013             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09014             buffer-=dest.size();
09015             delete[] buffer;
09016           }
09017         }       
09018       }
09019         break;
09020       case 12: { // Region 2D
09021         cimg::fread(dims,sizeof(unsigned int),4,file);
09022         if (endian) cimg::endian_swap(dims,4);
09023         dest = CImg<T>(dims[2],dims[1],1,1);
09024         if (dims[3]<256) {
09025           unsigned char *buffer = new unsigned char[dest.size()];
09026           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
09027           T *ptrd = dest.ptr();
09028           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09029           buffer-=dest.size();
09030           delete[] buffer;
09031         } else {
09032           if (dims[3]<65536) {
09033             unsigned short *buffer = new unsigned short[dest.size()];
09034             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
09035             if (endian) cimg::endian_swap(buffer,dest.size());
09036             T *ptrd = dest.ptr();
09037             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09038             buffer-=dest.size();
09039             delete[] buffer;
09040           } else {
09041             unsigned long *buffer = new unsigned long[dest.size()];
09042             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09043             if (endian) cimg::endian_swap(buffer,dest.size());
09044             T *ptrd = dest.ptr();
09045             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09046             buffer-=dest.size();
09047             delete[] buffer;
09048           }
09049         }       
09050       }
09051         break;
09052       case 13: { // Region 3D
09053         cimg::fread(dims,sizeof(unsigned int),5,file);
09054         if (endian) cimg::endian_swap(dims,5);
09055         dest = CImg<T>(dims[3],dims[2],dims[1],1);
09056         if (dims[4]<256) {
09057           unsigned char *buffer = new unsigned char[dest.size()];
09058           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
09059           T *ptrd = dest.ptr();
09060           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09061           buffer-=dest.size();
09062           delete[] buffer;
09063         } else {
09064           if (dims[4]<65536) {
09065             unsigned short *buffer = new unsigned short[dest.size()];
09066             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
09067             if (endian) cimg::endian_swap(buffer,dest.size());
09068             T *ptrd = dest.ptr();
09069             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09070             buffer-=dest.size();
09071             delete[] buffer;
09072           } else {
09073             unsigned long *buffer = new unsigned long[dest.size()];
09074             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09075             if (endian) cimg::endian_swap(buffer,dest.size());
09076             T *ptrd = dest.ptr();
09077             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09078             buffer-=dest.size();
09079             delete[] buffer;
09080           }
09081         }       
09082       }
09083         break;
09084         cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
09085         cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
09086         cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
09087         cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
09088         cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
09089         cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
09090         cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
09091         cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
09092         cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
09093         cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
09094         cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
09095         cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
09096         cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
09097         cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
09098         cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
09099         cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
09100         cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
09101         cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);     
09102       case 34: // Points 1D     
09103         cimg::fread(ptbuf,sizeof(long),1,file);
09104         if (endian) cimg::endian_swap(ptbuf,1);
09105         dest = CImg<T>(1); dest[0]=(T)ptbuf[0];
09106         break;
09107       case 35: // Points 2D
09108         cimg::fread(ptbuf,sizeof(long),2,file);
09109         if (endian) cimg::endian_swap(ptbuf,2);
09110         dest = CImg<T>(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0];
09111         break;
09112       case 36: // Points 3D
09113         cimg::fread(ptbuf,sizeof(long),3,file);
09114         if (endian) cimg::endian_swap(ptbuf,3);
09115         dest = CImg<T>(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0];
09116         break;
09117       default:
09118         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', can't read images with ID_type=%d",pixel_type(),filename,id);
09119       }
09120       return dest;
09121     }
09122 
09123 
09125     static CImg load_analyze(const char *filename, float *voxsize = NULL) {
09126       
09127       // Open header and data files
09128       std::FILE *file_header=NULL, *file=NULL;
09129       char body[1024];
09130       const char *ext = cimg::filename_split(filename,body);
09131       if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"img")) {
09132         std::sprintf(body+cimg::strlen(body),".hdr");
09133         file_header = cimg::fopen(body,"rb");
09134         std::sprintf(body+cimg::strlen(body)-3,"img");
09135         file = cimg::fopen(body,"rb");
09136       } else throw CImgIOException("CImg<%s>::load_analyze() : Cannot load filename '%s' as an analyze format",pixel_type(),filename);
09137 
09138       // Read header
09139       bool endian = false;
09140       unsigned int header_size;
09141       cimg::fread(&header_size,sizeof(int),1,file_header);
09142       if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); }
09143       unsigned char *header = new unsigned char[header_size];
09144       cimg::fread(header+sizeof(int),sizeof(char),header_size-sizeof(int),file_header);
09145       cimg::fclose(file_header);
09146       if (endian) {
09147         cimg::endian_swap((short*)(header+40),5);
09148         cimg::endian_swap((short*)(header+70),1);
09149         cimg::endian_swap((short*)(header+72),1);
09150         cimg::endian_swap((float*)(header+76),4);
09151         cimg::endian_swap((float*)(header+112),1);
09152       }
09153       unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1;
09154       cimg::warn(!dim[0],"CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type());
09155       cimg::warn(dim[0]>4,"CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions",
09156                  pixel_type(),dim[0]);
09157       if (dim[0]>=1) dimx = dim[1];
09158       if (dim[0]>=2) dimy = dim[2];
09159       if (dim[0]>=3) dimz = dim[3];
09160       if (dim[0]>=4) dimv = dim[4];
09161       
09162       float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
09163       const unsigned short datatype = *(short*)(header+70);
09164       if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
09165       delete[] header;
09166 
09167       // Read pixel data
09168       CImg dest(dimx,dimy,dimz,dimv);
09169       switch (datatype) {
09170       case 2: {
09171         unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
09172         cimg::fread(buffer,sizeof(unsigned char),dimx*dimy*dimz*dimv,file);
09173         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09174         delete[] buffer;
09175       } break;
09176       case 4: {
09177         short *buffer = new short[dimx*dimy*dimz*dimv];
09178         cimg::fread(buffer,sizeof(short),dimx*dimy*dimz*dimv,file);
09179         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
09180         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09181         delete[] buffer;
09182       } break;
09183       case 8: {
09184         int *buffer = new int[dimx*dimy*dimz*dimv];
09185         cimg::fread(buffer,sizeof(int),dimx*dimy*dimz*dimv,file);
09186         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
09187         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09188         delete[] buffer;
09189       } break;
09190       case 16: {
09191         float *buffer = new float[dimx*dimy*dimz*dimv];
09192         cimg::fread(buffer,sizeof(float),dimx*dimy*dimz*dimv,file);
09193         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
09194         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09195         delete[] buffer;
09196       } break;
09197       case 64: {
09198         double *buffer = new double[dimx*dimy*dimz*dimv];
09199         cimg::fread(buffer,sizeof(double),dimx*dimy*dimz*dimv,file);
09200         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
09201         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09202         delete[] buffer;
09203       } break;
09204       default: throw CImgIOException("CImg<%s>::load_analyze() : Cannot read images width 'datatype = %d'",pixel_type(),datatype);
09205       }
09206       cimg::fclose(file);
09207       return dest;
09208     }
09209 
09211     static CImg load_raw(const char *filename,const char axe='v',const char align='p') { 
09212       return CImgl<T>(filename).get_append(axe,align); 
09213     }
09214 
09218     static CImg load_convert(const char *filename) {
09219       static bool first_time = true;
09220       char command[512], filetmp[512];     
09221       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
09222       std::FILE *file = NULL;
09223       do { 
09224         if (file) std::fclose(file);
09225         std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),std::rand()%10000);
09226         file = std::fopen(filetmp,"rb");
09227       } while (file);
09228       std::sprintf(command,"\"%s\" \"%s\" %s",cimg::convert_path(),filename,filetmp);
09229       cimg::system(command);
09230       file = std::fopen(filetmp,"rb");
09231       if (!file) {
09232         std::fclose(cimg::fopen(filename,"r"));
09233         throw CImgIOException("CImg<%s>::load_convert() : Failed to open image '%s' with 'convert'.\n"
09234                               "Check that you have installed the ImageMagick package in a standart directory.",
09235                               pixel_type(),filename);
09236       } else cimg::fclose(file);
09237       const CImg dest(filetmp);
09238       std::remove(filetmp);
09239       return dest;
09240     }
09241 
09243 
09248     const CImg& save(const char *filename,const int number=-1) const {
09249       cimg_test(*this,"CImg<T>::save");
09250       if (!filename) throw CImgArgumentException("CImg<%s>::save() : Can't save with (null) filename",pixel_type());
09251       const char *ext = cimg::filename_split(filename);
09252       char nfilename[1024];
09253       if (number>=0) filename = cimg::filename_number(filename,number,6,nfilename);
09254       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(filename);
09255       if (!cimg::strcasecmp(ext,"dlm")) return save_dlm(filename);
09256       if (!cimg::strcasecmp(ext,"inr")) return save_inr(filename);
09257       if (!cimg::strcasecmp(ext,"hdr")) return save_analyze(filename);
09258       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(filename);
09259       if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(filename);
09260       if (!cimg::strcasecmp(ext,"png")) return save_png(filename);
09261       if (!cimg::strcasecmp(ext,"jpg") ||
09262           !cimg::strcasecmp(ext,"jpeg")) return save_jpeg(filename);
09263       if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(filename);
09264       if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(filename);
09265       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return save_raw(filename);
09266       if (!cimg::strcasecmp(ext,"pgm") || 
09267           !cimg::strcasecmp(ext,"ppm") || 
09268           !cimg::strcasecmp(ext,"pnm")) return save_pnm(filename);
09269       return save_convert(filename);
09270     }
09271   
09273     const CImg& save_ascii(const char *filename) const {
09274       cimg_test(*this,"CImg<T>::save_ascii");
09275       std::FILE *file = cimg::fopen(filename,"w");
09276       std::fprintf(file,"%u %u %u %u\n",width,height,depth,dim);
09277       const T* ptrs = data;
09278       cimg_mapYZV(*this,y,z,v) {
09279         cimg_mapX(*this,x) std::fprintf(file,"%g ",(double)*(ptrs++));
09280         std::fputc('\n',file);
09281       }
09282       cimg::fclose(file);
09283       return *this;
09284     }
09285 
09287     const CImg& save_dlm(const char *filename) const {
09288       cimg_test(*this,"CImg<T>::save_dlm");
09289       std::FILE *file = cimg::fopen(filename,"w");
09290       const T* ptrs = data;
09291       cimg_mapYZV(*this,y,z,v) {
09292         cimg_mapX(*this,x) std::fprintf(file,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":",");
09293         std::fputc('\n',file);
09294       }
09295       cimg::fclose(file);
09296       return *this;
09297     }
09298 
09300     const CImg& save_pnm(const char *filename) const {
09301       cimg_test(*this,"CImg<T>::save_pnm");
09302       const char *ext = cimg::filename_split(filename);
09303       const CImgStats st(*this,false);
09304 
09305       if (dim>1 && !cimg::strcasecmp(ext,"pgm")) {
09306                         get_norm_pointwise().normalize(0.0f,(float)st.max).save_pnm(filename); 
09307                         return *this; 
09308       }
09309       std::FILE *file = cimg::fopen(filename,"wb");
09310       const T 
09311         *ptrR = ptr(0,0,0,0),
09312         *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR,
09313         *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR;
09314       const unsigned int buf_size = width*height*(dim==1?1:3);
09315 
09316       std::fprintf(file,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n",
09317                    (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535);
09318       
09319       switch(dim) {
09320       case 1: {
09321         if ((st.max)<256) { // Binary PGM 8 bits
09322           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
09323           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
09324           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
09325           delete[] ptrd;
09326         } else {             // Binary PGM 16 bits
09327           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
09328           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
09329           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
09330           delete[] ptrd;
09331         }
09332       } break;
09333       default: {
09334         if ((st.max)<256) { // Binary PPM 8 bits
09335           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
09336           cimg_mapXY(*this,x,y) {
09337             *(xptrd++) = (unsigned char)*(ptrR++);
09338             *(xptrd++) = (unsigned char)*(ptrG++);
09339             *(xptrd++) = (unsigned char)*(ptrB++);
09340           }
09341           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
09342           delete[] ptrd;
09343         } else {             // Binary PPM 16 bits
09344           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
09345           cimg_mapXY(*this,x,y) {
09346             *(xptrd++) = (unsigned short)*(ptrR++);
09347             *(xptrd++) = (unsigned short)*(ptrG++);
09348             *(xptrd++) = (unsigned short)*(ptrB++);
09349           }
09350           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
09351           delete[] ptrd;
09352         }
09353       } break;
09354       }
09355       cimg::fclose(file);
09356       
09357       return *this;
09358     }
09359     
09361     const CImg& save_analyze(const char *filename,const float *const voxsize=NULL) const {
09362       cimg_test(*this,"CImg<T>::save_analyze");
09363       std::FILE *file;
09364       char header[348],hname[1024],iname[1024];
09365       const char *ext = cimg::filename_split(filename);
09366       short datatype=-1;
09367       std::memset(header,0,348);
09368       if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
09369       if (!cimg::strncasecmp(ext,"hdr",3)) { 
09370         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img"); 
09371       }
09372       if (!cimg::strncasecmp(ext,"img",3)) {
09373         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr"); 
09374       }
09375       ((int*)(header))[0] = 348;
09376       std::sprintf(header+4,"CImg");
09377       std::sprintf(header+14," ");
09378       ((short*)(header+36))[0] = 4096;
09379       ((char*)(header+38))[0] = 114;
09380       ((short*)(header+40))[0] = 4;
09381       ((short*)(header+40))[1] = width;
09382       ((short*)(header+40))[2] = height;
09383       ((short*)(header+40))[3] = depth;
09384       ((short*)(header+40))[4] = dim;
09385       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
09386       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
09387       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
09388       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
09389       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
09390       ((short*)(header+70))[0] = datatype;
09391       ((short*)(header+72))[0] = sizeof(T);
09392       ((float*)(header+112))[0] = 1;
09393       ((float*)(header+76))[0] = 0;
09394       if (voxsize) {
09395         ((float*)(header+76))[1] = voxsize[0];
09396         ((float*)(header+76))[2] = voxsize[1];
09397         ((float*)(header+76))[3] = voxsize[2];
09398       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
09399       file = cimg::fopen(hname,"wb");
09400       cimg::fwrite(header,sizeof(char),348,file);
09401       cimg::fclose(file);
09402       file = cimg::fopen(iname,"wb");
09403       cimg::fwrite(data,sizeof(T),size(),file);
09404       cimg::fclose(file);
09405       return *this;
09406     }
09407 
09409     const CImg& save_raw(const char *filename) const {
09410       cimg_test(*this,"CImg<T>::save_raw");      
09411       CImgl<T> shared(1);
09412       shared[0].width = width;
09413       shared[0].height = height;
09414       shared[0].depth = depth;
09415       shared[0].dim = dim;
09416       shared[0].data = data;
09417       shared.save_raw(filename);
09418       shared[0].width = shared[0].height = shared[0].depth = shared[0].dim = 0;
09419       shared[0].data = NULL;
09420       return *this;
09421     }
09422  
09424 
09430     const CImg& save_convert(const char *filename) const {
09431       cimg_test(*this,"CImg<T>::save_convert");
09432       static bool first_time = true;
09433       char command[512],filetmp[512];
09434       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
09435       std::FILE *file = NULL;
09436       do {
09437         if (file) std::fclose(file);
09438         std::sprintf(filetmp,"%s/CImg%.4d.rgba",cimg::temporary_path(),std::rand()%10000);
09439         file = std::fopen(filetmp,"rb");
09440       } while (file);
09441       save_rgba(filetmp);
09442       std::sprintf(command,"\"%s\" -depth 8 -size %ux%u -quality 100%% \"%s\" %s",
09443                    cimg::convert_path(),width,height,filetmp,filename);
09444       cimg::system(command);
09445       file = std::fopen(filename,"rb");
09446       if (!file) throw CImgIOException("CImg<%s>::save_convert() : Failed to save image '%s' with 'convert'.\n"
09447                                        "Check that you have installed the ImageMagick package in a standart directory.",
09448                                        pixel_type(),filename);
09449       if (file) cimg::fclose(file);
09450       std::remove(filetmp);
09451       return *this;
09452     }
09453     
09455     const CImg& save_inr(const char *filename,const float *const voxsize = NULL) const {
09456       cimg_test(*this,"CImg<T>::save_inr");
09457       int inrpixsize=-1;
09458       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
09459       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
09460       if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
09461       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
09462       if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
09463       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
09464       if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
09465       if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
09466       if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
09467       if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",pixel_type(),pixel_type());
09468       std::FILE *file = cimg::fopen(filename,"wb");
09469       char header[257];      
09470       int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
09471       if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
09472       err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm");
09473       std::memset(header+err,'\n',252-err);
09474       std::memcpy(header+252,"##}\n",4);
09475       cimg::fwrite(header,sizeof(char),256,file);
09476       cimg_mapXYZ(*this,x,y,z) cimg_mapV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),inrpixsize,1,file);
09477       cimg::fclose(file);
09478       return *this;
09479     }
09480 
09481 #define cimg_save_pandore_case(sy,sz,sv,stype,id)                           \
09482    if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
09483       unsigned int *iheader = (unsigned int*)(header+12);                   \
09484       nbdims = _save_pandore_header_length((*iheader=id),dims);             \
09485       cimg::fwrite(header,sizeof(unsigned char),36,file);                   \
09486       cimg::fwrite(dims,sizeof(unsigned int),nbdims,file);                  \
09487       if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
09488         unsigned char *buffer = new unsigned char[size()];                  \
09489         T *ptrs = ptr();                                                    \
09490         cimg_mapoff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++));      \
09491         buffer-=size();                                                     \
09492         cimg::fwrite(buffer,sizeof(unsigned char),size(),file);             \
09493         delete[] buffer;                                                    \
09494       }                                                                     \
09495       if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
09496         unsigned long *buffer = new unsigned long[size()];                  \
09497         T *ptrs = ptr();                                                    \
09498         cimg_mapoff(*this,off) *(buffer++)=(long)(*(ptrs++));               \
09499         buffer-=size();                                                     \
09500         cimg::fwrite(buffer,sizeof(long),size(),file);                      \
09501         delete[] buffer;                                                    \
09502       }                                                                     \
09503       if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
09504         float *buffer = new float[size()];                                  \
09505         T *ptrs = ptr();                                                    \
09506         cimg_mapoff(*this,off) *(buffer++)=(float)(*(ptrs++));              \
09507         buffer-=size();                                                     \
09508         cimg::fwrite(buffer,sizeof(float),size(),file);                     \
09509         delete[] buffer;                                                    \
09510       }                                                                     \
09511       saved = true;                                                         \
09512     }
09513 
09514     unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims) const {
09515       unsigned int nbdims=0;
09516       if (id==2 || id==3 || id==4)    { dims[0]=1; dims[1]=width; nbdims=2; }
09517       if (id==5 || id==6 || id==7)    { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; }
09518       if (id==8 || id==9 || id==10)   { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
09519       if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=1; nbdims=4; }
09520       if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=0; nbdims=5; }
09521       if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; }
09522       if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; }
09523       if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
09524       return nbdims;
09525     }    
09526 
09528     const CImg& save_pandore(const char* filename) const {
09529       cimg_test(*this,"CImg<T>::save_pandore");
09530       std::FILE *file = cimg::fopen(filename,"wb");
09531       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
09532                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,
09533                                    '2','0','0','0','/','0','1','/','0','1',
09534                                    0 };
09535       unsigned int nbdims,dims[5];
09536       bool saved=false;
09537       cimg_save_pandore_case(1,1,1,"unsigned char",2);
09538       cimg_save_pandore_case(1,1,1,"char",3);
09539       cimg_save_pandore_case(1,1,1,"short",3);
09540       cimg_save_pandore_case(1,1,1,"unsigned short",3);
09541       cimg_save_pandore_case(1,1,1,"unsigned int",3);
09542       cimg_save_pandore_case(1,1,1,"int",3);
09543       cimg_save_pandore_case(1,1,1,"unsigned long",4);
09544       cimg_save_pandore_case(1,1,1,"long",3);
09545       cimg_save_pandore_case(1,1,1,"float",4);
09546       cimg_save_pandore_case(1,1,1,"double",4);
09547  
09548       cimg_save_pandore_case(0,1,1,"unsigned char",5);
09549       cimg_save_pandore_case(0,1,1,"char",6);
09550       cimg_save_pandore_case(0,1,1,"short",6);
09551       cimg_save_pandore_case(0,1,1,"unsigned short",6);
09552       cimg_save_pandore_case(0,1,1,"unsigned int",6);
09553       cimg_save_pandore_case(0,1,1,"int",6);
09554       cimg_save_pandore_case(0,1,1,"unsigned long",7);
09555       cimg_save_pandore_case(0,1,1,"long",6);
09556       cimg_save_pandore_case(0,1,1,"float",7);
09557       cimg_save_pandore_case(0,1,1,"double",7);
09558 
09559       cimg_save_pandore_case(0,0,1,"unsigned char",8);
09560       cimg_save_pandore_case(0,0,1,"char",9);
09561       cimg_save_pandore_case(0,0,1,"short",9);
09562       cimg_save_pandore_case(0,0,1,"unsigned short",9);
09563       cimg_save_pandore_case(0,0,1,"unsigned int",9);
09564       cimg_save_pandore_case(0,0,1,"int",9);
09565       cimg_save_pandore_case(0,0,1,"unsigned long",10);
09566       cimg_save_pandore_case(0,0,1,"long",9);
09567       cimg_save_pandore_case(0,0,1,"float",10);
09568       cimg_save_pandore_case(0,0,1,"double",10);
09569       
09570       cimg_save_pandore_case(0,1,3,"unsigned char",16);
09571       cimg_save_pandore_case(0,1,3,"char",17);
09572       cimg_save_pandore_case(0,1,3,"short",17);
09573       cimg_save_pandore_case(0,1,3,"unsigned short",17);
09574       cimg_save_pandore_case(0,1,3,"unsigned int",17);
09575       cimg_save_pandore_case(0,1,3,"int",17);
09576       cimg_save_pandore_case(0,1,3,"unsigned long",18);
09577       cimg_save_pandore_case(0,1,3,"long",17);
09578       cimg_save_pandore_case(0,1,3,"float",18);
09579       cimg_save_pandore_case(0,1,3,"double",18);
09580 
09581       cimg_save_pandore_case(0,0,3,"unsigned char",19);
09582       cimg_save_pandore_case(0,0,3,"char",20);
09583       cimg_save_pandore_case(0,0,3,"short",20);
09584       cimg_save_pandore_case(0,0,3,"unsigned short",20);
09585       cimg_save_pandore_case(0,0,3,"unsigned int",20);
09586       cimg_save_pandore_case(0,0,3,"int",20);
09587       cimg_save_pandore_case(0,0,3,"unsigned long",21);
09588       cimg_save_pandore_case(0,0,3,"long",20);
09589       cimg_save_pandore_case(0,0,3,"float",21);
09590       cimg_save_pandore_case(0,0,3,"double",21);
09591      
09592       cimg_save_pandore_case(1,1,0,"unsigned char",22);
09593       cimg_save_pandore_case(1,1,0,"char",23);
09594       cimg_save_pandore_case(1,1,0,"short",23);
09595       cimg_save_pandore_case(1,1,0,"unsigned short",23);
09596       cimg_save_pandore_case(1,1,0,"unsigned int",23);
09597       cimg_save_pandore_case(1,1,0,"int",23);
09598       cimg_save_pandore_case(1,1,0,"unsigned long",25);
09599       cimg_save_pandore_case(1,1,0,"long",23);
09600       cimg_save_pandore_case(1,1,0,"float",25);
09601       cimg_save_pandore_case(1,1,0,"double",25);
09602  
09603       cimg_save_pandore_case(0,1,0,"unsigned char",26);
09604       cimg_save_pandore_case(0,1,0,"char",27);
09605       cimg_save_pandore_case(0,1,0,"short",27);
09606       cimg_save_pandore_case(0,1,0,"unsigned short",27);
09607       cimg_save_pandore_case(0,1,0,"unsigned int",27);
09608       cimg_save_pandore_case(0,1,0,"int",27);
09609       cimg_save_pandore_case(0,1,0,"unsigned long",29);
09610       cimg_save_pandore_case(0,1,0,"long",27);
09611       cimg_save_pandore_case(0,1,0,"float",29);
09612       cimg_save_pandore_case(0,1,0,"double",29);
09613 
09614       cimg_save_pandore_case(0,0,0,"unsigned char",30);
09615       cimg_save_pandore_case(0,0,0,"char",31);
09616       cimg_save_pandore_case(0,0,0,"short",31);
09617       cimg_save_pandore_case(0,0,0,"unsigned short",31);
09618       cimg_save_pandore_case(0,0,0,"unsigned int",31);
09619       cimg_save_pandore_case(0,0,0,"int",31);
09620       cimg_save_pandore_case(0,0,0,"unsigned long",33);
09621       cimg_save_pandore_case(0,0,0,"long",31);
09622       cimg_save_pandore_case(0,0,0,"float",33);
09623       cimg_save_pandore_case(0,0,0,"double",33);
09624 
09625       cimg::fclose(file);
09626       return *this;
09627     }
09628 
09630     const CImg& save_bmp(const char* filename) const {
09631       cimg_test(*this,"CImg<T>::save_bmp");
09632       std::FILE *file = cimg::fopen(filename,"wb");
09633       
09634       unsigned char header[54]={0}, align_buf[4]={0};
09635       const unsigned int 
09636         align     = (4-(3*width)%4)%4,
09637         buf_size  = (3*width+align)*dimy(),
09638         file_size = 54+buf_size;
09639       header[0] = 'B'; header[1] = 'M';
09640       header[0x02]=file_size&0xFF; header[0x03]=(file_size>>8)&0xFF;
09641       header[0x04]=(file_size>>16)&0xFF; header[0x05]=(file_size>>24)&0xFF;
09642       header[0x0A]=0x36;
09643       header[0x0E]=0x28;
09644       header[0x12]=width&0xFF; header[0x13]=(width>>8)&0xFF;
09645       header[0x14]=(width>>16)&0xFF; header[0x15]=(width>>24)&0xFF;
09646       header[0x16]=height&0xFF; header[0x17]=(height>>8)&0xFF;
09647       header[0x18]=(height>>16)&0xFF; header[0x19]=(height>>24)&0xFF;
09648       header[0x1A]=1;  header[0x1B]=0;
09649       header[0x1C]=24; header[0x1D]=0;
09650       header[0x22]=buf_size&0xFF; header[0x23]=(buf_size>>8)&0xFF;
09651       header[0x24]=(buf_size>>16)&0xFF; header[0x25]=(buf_size>>24)&0xFF;
09652       header[0x27]=0x1; header[0x2B]=0x1;
09653       cimg::fwrite(header,sizeof(unsigned char),54,file);
09654 
09655       const T
09656         *pR = ptr(0,height-1,0,0),
09657         *pG = (dim>=2)?ptr(0,height-1,0,1):pR, 
09658         *pB = (dim>=3)?ptr(0,height-1,0,2):pR;
09659 
09660       cimg_mapY(*this,y) {
09661         cimg_mapX(*this,x) {
09662           std::fputc((unsigned char)(*(pB++)),file);
09663           std::fputc((unsigned char)(*(pG++)),file);
09664           std::fputc((unsigned char)(*(pR++)),file);
09665         }
09666         std::fwrite(align_buf,sizeof(unsigned char),align,file);
09667         pR-=2*width; pG-=2*width; pB-=2*width;  
09668       }      
09669       cimg::fclose(file);
09670       return *this;
09671     }
09672     
09674     // Most of this function has been written by Eric Fausett
09689     const CImg& save_png(const char* filename, const bool png16=false) const {
09690       cimg_test(*this,"CImg<T>::save_png");
09691 #ifndef cimg_use_png
09692       return save_convert(filename);
09693 #else
09694       std::FILE *file = cimg::fopen(filename,"wb");
09695       
09696       // Setup PNG structures for write
09697       png_voidp user_error_ptr=0;
09698       png_error_ptr user_error_fn=0, user_warning_fn=0;
09699       png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
09700                                                     user_error_ptr, user_error_fn, user_warning_fn);
09701       if(!png_ptr){
09702         cimg::fclose(file);
09703         throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'png_ptr' data structure",pixel_type());
09704       }
09705       png_infop info_ptr = png_create_info_struct(png_ptr);
09706       if(!info_ptr){
09707         png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
09708         cimg::fclose(file);
09709         throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'info_ptr' data structure",pixel_type());
09710       }
09711       if (setjmp(png_jmpbuf(png_ptr))){
09712         png_destroy_write_struct(&png_ptr, &info_ptr);
09713         cimg::fclose(file);
09714         throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
09715       }
09716       
09717       png_init_io(png_ptr, file);      
09718       png_uint_32 width = dimx();
09719       png_uint_32 height = dimy();
09720       const int bit_depth = png16?16:8;
09721       int color_type;
09722       switch (dimv()) {
09723       case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
09724       case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
09725       case 3: color_type = PNG_COLOR_TYPE_RGB; break;
09726       default: color_type = PNG_COLOR_TYPE_RGB_ALPHA;
09727       }
09728       const int interlace_type = PNG_INTERLACE_NONE;
09729       const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
09730       const int filter_method = PNG_FILTER_TYPE_DEFAULT;
09731       png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,
09732                    compression_type, filter_method);
09733       png_write_info(png_ptr, info_ptr);
09734       const int byte_depth = bit_depth>>3;
09735       const int numChan = dimv()>4?4:dimv();
09736       const int pixel_bit_depth_flag = numChan * (bit_depth-1);
09737       
09738       // Allocate Memory for Image Save and Fill pixel data
09739       png_bytep *imgData = new png_byte*[height];
09740       for(unsigned int row=0; row<height; row++) imgData[row] = new png_byte[byte_depth * numChan * width];
09741       const T *pC0 = ptr(0,0,0,0);
09742       switch(pixel_bit_depth_flag) {
09743       case 7 :  { // Gray 8-bit
09744         cimg_mapY(*this,y) {
09745           unsigned char *ptrs = imgData[y];
09746           cimg_mapX(*this,x) *(ptrs++) = (unsigned char)*(pC0++);
09747         }
09748       } break;
09749       case 14: { // Gray w/ Alpha 8-bit
09750         const T *pC1 = ptr(0,0,0,1);
09751         cimg_mapY(*this,y) {
09752           unsigned char *ptrs = imgData[y];
09753           cimg_mapX(*this,x) {
09754             *(ptrs++) = (unsigned char)*(pC0++);
09755             *(ptrs++) = (unsigned char)*(pC1++);
09756           }
09757         }
09758       } break;
09759       case 21:  { // RGB 8-bit
09760         const T *pC1 = ptr(0,0,0,1);
09761         const T *pC2 = ptr(0,0,0,2);
09762         cimg_mapY(*this,y) {
09763           unsigned char *ptrs = imgData[y];
09764           cimg_mapX(*this,x) {
09765             *(ptrs++) = (unsigned char)*(pC0++);
09766             *(ptrs++) = (unsigned char)*(pC1++);
09767             *(ptrs++) = (unsigned char)*(pC2++);
09768           }
09769         }
09770       } break;
09771       case 28: { // RGB x/ Alpha 8-bit
09772         const T *pC1 = ptr(0,0,0,1);
09773         const T *pC2 = ptr(0,0,0,2);
09774         const T *pC3 = ptr(0,0,0,3);
09775         cimg_mapY(*this,y){
09776           unsigned char *ptrs = imgData[y];
09777           cimg_mapX(*this,x){
09778             *(ptrs++) = (unsigned char)*(pC0++);
09779             *(ptrs++) = (unsigned char)*(pC1++);
09780             *(ptrs++) = (unsigned char)*(pC2++);
09781             *(ptrs++) = (unsigned char)*(pC3++);
09782           }
09783         }
09784       } break;
09785       case 15: { // Gray 16-bit
09786         cimg_mapY(*this,y){
09787           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09788           cimg_mapX(*this,x) *(ptrs++) = (unsigned short)*(pC0++);
09789         }
09790       } break;
09791       case 30: { // Gray w/ Alpha 16-bit
09792         const T *pC1 = ptr(0,0,0,1);
09793         cimg_mapY(*this,y){
09794           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09795           cimg_mapX(*this,x) {
09796             *(ptrs++) = (unsigned short)*(pC0++);
09797             *(ptrs++) = (unsigned short)*(pC1++);
09798           }
09799         }
09800       } break;
09801       case 45: { // RGB 16-bit
09802         const T *pC1 = ptr(0,0,0,1);
09803         const T *pC2 = ptr(0,0,0,2);
09804         cimg_mapY(*this,y) {
09805           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09806           cimg_mapX(*this,x) {
09807             *(ptrs++) = (unsigned short)*(pC0++);
09808             *(ptrs++) = (unsigned short)*(pC1++);
09809             *(ptrs++) = (unsigned short)*(pC2++);
09810           }
09811         }
09812       } break;
09813       case 60: { // RGB x/ Alpha 16-bit
09814         const T *pC1 = ptr(0,0,0,1);
09815         const T *pC2 = ptr(0,0,0,2);
09816         const T *pC3 = ptr(0,0,0,3);
09817         cimg_mapY(*this,y) {
09818           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09819           cimg_mapX(*this,x) {
09820             *(ptrs++) = (unsigned short)*(pC0++);
09821             *(ptrs++) = (unsigned short)*(pC1++);
09822             *(ptrs++) = (unsigned short)*(pC2++);
09823             *(ptrs++) = (unsigned short)*(pC3++);
09824           }
09825         }
09826       } break;
09827       default:
09828         throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
09829         break;
09830       }
09831       png_write_image(png_ptr, imgData);      
09832       png_write_end(png_ptr, info_ptr);      
09833       png_destroy_write_struct(&png_ptr, &info_ptr);
09834       
09835       // Deallocate Image Write Memory
09836       for (unsigned int n=0; n<height; n++) delete[] imgData[n];
09837       delete[] imgData;      
09838       cimg::fclose(file);
09839       return *this;
09840 #endif
09841     }
09842 
09844     const CImg<T>& save_jpeg(const char *filename,const unsigned int quality=100) const {
09845       cimg_test(*this,"CImg<T>::save_jpeg");
09846 #ifndef cimg_use_jpeg
09847       return save_convert(filename);
09848 #else
09849       
09850       unsigned char *buf = new unsigned char[width*height*3], *buf2 = buf;
09851       const T *ptr_r = ptr(0,0,0,0),
09852         *ptr_g = ptr(0,0,0,dim>1?1:0),
09853         *ptr_b = ptr(0,0,0,dim>2?2:0);
09854       cimg_mapXY(*this,x,y) {
09855         *(buf2++) = (unsigned char)*(ptr_r++);
09856         *(buf2++) = (unsigned char)*(ptr_g++);
09857         *(buf2++) = (unsigned char)*(ptr_b++);
09858       }
09859       
09860       struct jpeg_compress_struct cinfo;
09861       struct jpeg_error_mgr jerr;
09862       cinfo.err = jpeg_std_error(&jerr);
09863       jpeg_create_compress(&cinfo);
09864       std::FILE *file = cimg::fopen(filename,"wb");
09865       jpeg_stdio_dest(&cinfo,file);
09866       cinfo.image_width = width;
09867       cinfo.image_height = height;
09868       cinfo.input_components = 3;
09869       cinfo.in_color_space = JCS_RGB;
09870       jpeg_set_defaults(&cinfo);
09871       jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
09872       jpeg_start_compress(&cinfo,TRUE);
09873       
09874       const unsigned int row_stride = width*3;
09875       JSAMPROW row_pointer[1];
09876       while (cinfo.next_scanline < cinfo.image_height) {
09877         row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
09878         jpeg_write_scanlines(&cinfo,row_pointer,1);
09879       }
09880       jpeg_finish_compress(&cinfo);
09881       delete[] buf;
09882       cimg::fclose(file);
09883       jpeg_destroy_compress(&cinfo);
09884       return *this;
09885 #endif
09886     }
09887 
09889     const CImg& save_rgba(const char *filename) const {
09890       cimg_test(*this,"CImg<T>::save_rgba");
09891       std::FILE *file = cimg::fopen(filename,"wb");
09892       const unsigned int wh = width*height;
09893       unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
09894       const T 
09895         *ptr1 = ptr(0,0,0,0),
09896         *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
09897         *ptr3 = dim>2?ptr(0,0,0,2):ptr1,
09898         *ptr4 = dim>3?ptr(0,0,0,3):NULL;
09899       for (unsigned int k=0; k<wh; k++) {
09900         *(nbuffer++) = (unsigned char)(*(ptr1++));
09901         *(nbuffer++) = (unsigned char)(*(ptr2++));
09902         *(nbuffer++) = (unsigned char)(*(ptr3++));
09903         *(nbuffer++) = (unsigned char)(ptr4?(*(ptr4++)):255);
09904       }
09905       cimg::fwrite(buffer,sizeof(unsigned char),4*wh,file);
09906       cimg::fclose(file);
09907       delete[] buffer;
09908       return *this;
09909     }
09910     
09911 
09913     const CImg& save_rgb(const char *filename) const {
09914       cimg_test(*this,"CImg<T>::save_rgb");
09915       std::FILE *file = cimg::fopen(filename,"wb");
09916       const unsigned int wh = width*height;
09917       unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
09918       const T 
09919         *ptr1 = ptr(0,0,0,0),
09920         *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
09921         *ptr3 = dim>2?ptr(0,0,0,2):ptr1;
09922       for (unsigned int k=0; k<wh; k++) {
09923         *(nbuffer++) = (unsigned char)(*(ptr1++));
09924         *(nbuffer++) = (unsigned char)(*(ptr2++));
09925         *(nbuffer++) = (unsigned char)(*(ptr3++));
09926       }
09927       cimg::fwrite(buffer,sizeof(unsigned char),3*wh,file);
09928       cimg::fclose(file);
09929       delete[] buffer;
09930       return *this;
09931     }
09932     
09934     static CImg get_logo40x38() { 
09935       static bool first_time = true;
09936       static CImg<T> res(40,38,1,3);
09937       if (first_time) {
09938         const unsigned char *ptrs = cimg::logo40x38;
09939         T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
09940         for (unsigned int off = 0; off<res.width*res.height;) {
09941           const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
09942           for (unsigned int l=0; l<n; off++,l++) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
09943         }
09944         first_time = false;
09945       }      
09946       return res;
09947     }
09948        
09950     //------------------------------------------
09951     //------------------------------------------
09952     //
09954 
09955     //------------------------------------------
09956     //------------------------------------------
09957     CImg& swap(CImg& img) {
09958       cimg::swap(width,img.width);
09959       cimg::swap(height,img.height);
09960       cimg::swap(depth,img.depth);
09961       cimg::swap(dim,img.dim);
09962       cimg::swap(data,img.data);
09963       return img;
09964     }
09965 
09966 #ifdef cimg_plugin
09967 #include cimg_plugin
09968 #endif
09969     
09971   };
09972 
09973 
09974   /*-------------------------------------------------------
09975     
09976 
09977 
09978 
09979   Definition of the CImgl<> structure
09980 
09981 
09982 
09983 
09984   ------------------------------------------------------*/
09985 
09987   template<typename T> struct CImgl {       
09989 
09992     unsigned int size;
09993     
09995 
09999     CImg<T> *data;                      
10000     
10001     //------------------------------------------
10002     //------------------------------------------
10003     //
10005 
10006     //------------------------------------------
10007     //------------------------------------------
10008     
10010     static const char* pixel_type() { T val; return cimg::get_type(val); }
10011     
10013     CImgl(const unsigned int n=0,const unsigned int width=0,const unsigned int height=1,
10014           const unsigned int depth=1, const unsigned int dim=1):size(n) {
10015       if (n) {
10016         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10017         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim);
10018       } else data = NULL;
10019     }
10020 
10022     CImgl(const unsigned int n,const unsigned int width,const unsigned int height,
10023           const unsigned int depth, const unsigned int dim,const T& val):size(n) {
10024       if (n) {
10025         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10026         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim,val);
10027       } else data = NULL;
10028     }
10029     
10030     // ! Create a list of \p n copy of the input image.
10031     template<typename t> CImgl(const unsigned int n, const CImg<t>& img):size(n) {
10032       if (n) {
10033         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10034         cimgl_map(*this,l) data[l]=img;
10035       } else data = NULL;
10036     }
10037     
10039     template<typename t> CImgl(const CImgl<t>& list):size(list.size) {
10040       if (size) {
10041         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
10042         cimgl_map(*this,l) data[l] = list[l];
10043       } else data = NULL;
10044     }
10045     CImgl(const CImgl<T>& list):size(list.size) {
10046       if (size>0) {
10047         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
10048         cimgl_map(*this,l) data[l] = list[l];
10049       } else data = NULL;
10050     }
10051 
10053     CImgl(const char* filename):size(0),data(NULL) { load(filename).swap(*this); }
10054     
10056     CImgl(const CImg<T>& img):size(0),data(NULL) { CImgl<T>(1,img).swap(*this); }
10057 
10059     CImgl(const CImg<T>& img1,const CImg<T>& img2):size(2) {
10060       data = new CImg<T>[cimg::lblock];
10061       data[0] = img1;
10062       data[1] = img2;
10063     }
10064 
10066     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3):size(3) {
10067       data = new CImg<T>[cimg::lblock];
10068       data[0] = img1;
10069       data[1] = img2;
10070       data[2] = img3;
10071     }
10072 
10074     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3,const CImg<T>& img4):size(4) {
10075       data = new CImg<T>[cimg::lblock];
10076       data[0] = img1;
10077       data[1] = img2;
10078       data[2] = img3;
10079       data[3] = img4;
10080     }
10081     
10083     template<typename t> CImgl& operator=(const CImgl<t>& list) { 
10084       if (list.size>size) return CImgl<T>(list).swap(*this); 
10085       size = list.size;
10086       cimgl_map(*this,l) data[l] = list[l];
10087       return *this;
10088     }
10089 
10090     CImgl& operator=(const CImgl<T>& list) { 
10091       if (&list==this) return *this; 
10092       if (list.size>size) return CImgl<T>(list).swap(*this);
10093       size = list.size;
10094       cimgl_map(*this,l) data[l] = list[l];
10095       return *this;
10096     }
10097     
10099     ~CImgl() { if (data) delete[] data; }
10100     
10102     CImgl& empty() { return CImgl<T>().swap(*this); }
10103     
10105     //------------------------------------------
10106     //------------------------------------------
10107     //
10109 
10110     //------------------------------------------
10111     //------------------------------------------
10112     
10114     template<typename t> CImgl& operator+=(const CImgl<t>& list) {
10115       const unsigned int sizemax = min(size,list.size);
10116       for (unsigned int l=0; l<sizemax; l++) (*this)[l]+=list[l];
10117       return *this;
10118     }
10119     
10121     template<typename t> CImgl& operator-=(const CImgl<t>& list) {
10122       const unsigned int sizemax = min(size,list.size);
10123       for (unsigned int l=0; l<sizemax; l++) (*this)[l]-=list[l];
10124       return *this;
10125     }
10126     
10128     CImgl& operator+=(const T& val) { cimgl_map(*this,l) (*this)[l]+=val; return *this; }
10129     
10131     CImgl& operator-=(const T& val) { cimgl_map(*this,l) (*this)[l]-=val; return *this; }
10132     
10134     CImgl& operator*=(const double val) { cimgl_map(*this,l) (*this)[l]*=val; return *this; }
10135     
10137     CImgl& operator/=(const double val) { cimgl_map(*this,l) (*this)[l]/=val; return *this; }
10138     
10140     CImgl operator+(const T& val) const { return CImgl<T>(*this)+=val;  }
10141     
10143     CImgl operator*(const double val) const { return CImgl<T>(*this)*=val;  }
10144     
10146     CImgl operator-(const T& val) const { return CImgl<T>(*this)-=val;  }
10147     
10149     CImgl operator/(const double val) const { return CImgl<T>(*this)/=val;  }
10150     
10152     CImgl operator+(const CImgl& list) const { return CImgl<T>(*this)+=list; }
10153 
10155     CImgl operator-(const CImgl& list) const { return CImgl<T>(*this)-=list; }
10156     
10158     friend CImgl operator+(const T& val, const CImgl& list) { return CImgl<T>(list)+=val; }
10159     
10161     friend CImgl operator*(const double val, const CImgl& list) { return CImgl<T>(list)*=val; }
10162   
10164     //------------------------------------------
10165     //------------------------------------------
10166     //
10168 
10169     //------------------------------------------
10170     //------------------------------------------
10171     
10173     CImg<T>& operator[](const unsigned int pos) const {
10174 #if cimg_debug>1
10175       if (pos>=size) {
10176         cimg::warn(true,"CImgl<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size);
10177         return *data;
10178       }
10179 #endif
10180       return data[pos];
10181     }
10182     
10184     CImg<T>& operator()(const unsigned int pos) const { return (*this)[pos]; }
10185     
10187     CImgl& insert(const CImg<T>& img,const unsigned int pos) {
10188       if (pos>size) 
10189         throw CImgArgumentException("CImgl<%s>::insert() : Can't insert at position %u into a list with %u elements",
10190                                     pixel_type(),pos,size);
10191       CImg<T> *new_data = (!((++size)%cimg::lblock) || !data)?new CImg<T>[(size/cimg::lblock+1)*cimg::lblock]:NULL;
10192       if (!data) { data=new_data; *data=img; }
10193       else {
10194         if (new_data) {
10195           std::memcpy(new_data,data,sizeof(CImg<T>)*pos);
10196           if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
10197           std::memset(data,0,sizeof(CImg<T>)*(size-1));
10198           delete[] data;
10199           data = new_data;
10200         }
10201         else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
10202         data[pos].data = NULL;
10203         data[pos] = img;
10204       }
10205       return *this;
10206     }
10207     
10209     CImgl& insert(const CImg<T>& img) { return insert(img,size); }
10210     
10212     CImgl& insert(const CImgl<T>& list,const unsigned int pos) { 
10213       if (this!=&list) cimgl_map(list,l) insert(list[l],pos+l);
10214       else insert(CImgl<T>(list),pos);
10215       return *this; 
10216     }
10217     
10219     CImgl& insert(const CImgl<T>& list) { return insert(list,size); }
10220     
10222     CImgl& remove(const unsigned int pos) {
10223       if (pos>=size) { 
10224         cimg::warn(true,"CImgl<%s>::remove() : Can't remove an image from a list (%p,%u), at position %u",
10225                    pixel_type(),data,size,pos);
10226         return *this;
10227       }
10228       CImg<T> tmp; tmp.swap(data[pos]); // the image to remove will be freed
10229       size--;
10230       if (pos!=size) { 
10231         memmove(data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
10232         CImg<T> &tmp = data[size];
10233         tmp.width = tmp.height = tmp.depth = tmp.dim = 0;
10234         tmp.data = NULL;
10235       }
10236       return *this;
10237     }
10238 
10240     CImgl& remove() { 
10241       if (size) return remove(size-1); 
10242       cimg::warn(true,"CImgl<%s>::remove() : List is empty",pixel_type());
10243       return *this;
10244     }
10245 
10247     CImgl& reverse() {
10248       for (unsigned int l=0; l<size/2; l++) (*this)[l].swap((*this)[size-1-l]);
10249       return *this;
10250     }
10251     
10253     CImgl& get_reverse() { return CImgl<T>(*this).reverse(); }
10254 
10256     //------------------------------------------
10257     //------------------------------------------
10258     //
10260 
10261     //------------------------------------------
10262     //------------------------------------------
10263     
10265     CImgl& FFT(const char axe, const bool inverse=false) {
10266       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
10267       CImg<T> &Ir = data[0], &Ii = data[1];
10268       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
10269       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
10270         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
10271                                     pixel_type());
10272       switch (cimg::uncase(axe)) {
10273       case 'x': { // Fourier along X
10274         const unsigned int N = Ir.width, N2 = (N>>1);
10275         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
10276                                                            pixel_type(),N);
10277         for (unsigned int i=0,j=0; i<N2; i++) {
10278           if (j>i) cimg_mapYZV(Ir,y,z,v) { cimg::swap(Ir(i,y,z,v),Ir(j,y,z,v)); cimg::swap(Ii(i,y,z,v),Ii(j,y,z,v));
10279           if (j<N2) { 
10280             const unsigned int ri = N-1-i, rj = N-1-j;
10281             cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v)); 
10282           }}
10283           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10284         }
10285         for (unsigned int delta=2; delta<=N; delta<<=1) {
10286           const unsigned int delta2 = (delta>>1);
10287           for (unsigned int i=0; i<N; i+=delta) {
10288             float wr = 1, wi = 0;
10289             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10290                         ca = (float)std::cos(angle),
10291                         sa = (float)std::sin(angle);
10292             for (unsigned int k=0; k<delta2; k++) {
10293               const unsigned int j = i + k, nj = j + delta2;
10294               cimg_mapYZV(Ir,y,z,k) {
10295                 T &ir = Ir(j,y,z,k), &ii = Ii(j,y,z,k), &nir = Ir(nj,y,z,k), &nii = Ii(nj,y,z,k);              
10296                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10297                 nir = ir - tmpr; nii = ii - tmpi;
10298                 ir += tmpr; ii += tmpi;
10299               }
10300               const float nwr = wr*ca-wi*sa;
10301               wi = wi*ca + wr*sa;
10302               wr = nwr;       
10303             }
10304           }       
10305         }
10306         if (inverse) (*this)/=N;
10307       } break;
10308 
10309       case 'y': { // Fourier along Y
10310         const unsigned int N = Ir.height, N2 = (N>>1);
10311         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
10312                                                            pixel_type(),N);
10313         for (unsigned int i=0,j=0; i<N2; i++) {
10314           if (j>i) cimg_mapXZV(Ir,x,z,v) { cimg::swap(Ir(x,i,z,v),Ir(x,j,z,v)); cimg::swap(Ii(x,i,z,v),Ii(x,j,z,v));
10315           if (j<N2) { 
10316             const unsigned int ri = N-1-i, rj = N-1-j;
10317             cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v)); 
10318           }}
10319           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10320         }
10321         for (unsigned int delta=2; delta<=N; delta<<=1) {
10322           const unsigned int delta2 = (delta>>1);
10323           for (unsigned int i=0; i<N; i+=delta) {
10324             float wr = 1, wi = 0;
10325             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10326                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
10327             for (unsigned int k=0; k<delta2; k++) {
10328               const unsigned int j = i + k, nj = j + delta2;
10329               cimg_mapXZV(Ir,x,z,k) {
10330                 T &ir = Ir(x,j,z,k), &ii = Ii(x,j,z,k), &nir = Ir(x,nj,z,k), &nii = Ii(x,nj,z,k);              
10331                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10332                 nir = ir - tmpr; nii = ii - tmpi;
10333                 ir += tmpr; ii += tmpi;
10334               }
10335               const float nwr = wr*ca-wi*sa;
10336               wi = wi*ca + wr*sa;
10337               wr = nwr;       
10338             }
10339           }       
10340         }
10341         if (inverse) (*this)/=N;
10342       } break;
10343 
10344       case 'z': { // Fourier along Z
10345         const unsigned int N = Ir.depth, N2 = (N>>1);
10346         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
10347                                                            pixel_type(),N);
10348         for (unsigned int i=0,j=0; i<N2; i++) {
10349           if (j>i) cimg_mapXYV(Ir,x,y,v) { cimg::swap(Ir(x,y,i,v),Ir(x,y,j,v)); cimg::swap(Ii(x,y,i,v),Ii(x,y,j,v));
10350           if (j<N2) { 
10351             const unsigned int ri = N-1-i, rj = N-1-j;
10352             cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v)); 
10353           }}
10354           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10355         }
10356         for (unsigned int delta=2; delta<=N; delta<<=1) {
10357           const unsigned int delta2 = (delta>>1);
10358           for (unsigned int i=0; i<N; i+=delta) {
10359             float wr = 1, wi = 0;
10360             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10361                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
10362             for (unsigned int k=0; k<delta2; k++) {
10363               const unsigned int j = i + k, nj = j + delta2;
10364               cimg_mapXYV(Ir,x,y,k) {
10365                 T &ir = Ir(x,y,j,k), &ii = Ii(x,y,j,k), &nir = Ir(x,y,nj,k), &nii = Ii(x,y,nj,k);              
10366                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10367                 nir = ir - tmpr; nii = ii - tmpi;
10368                 ir += tmpr; ii += tmpi;
10369               }
10370               const float nwr = wr*ca-wi*sa;
10371               wi = wi*ca + wr*sa;
10372               wr = nwr;       
10373             }
10374           }       
10375         }
10376         if (inverse) (*this)/=N;
10377       } break;
10378 
10379       default: throw CImgArgumentException("CImg<%s>::FFT() : unknown axe '%c', must be 'x','y' or 'z'");
10380       }
10381       return *this; 
10382     }
10383 
10385     CImgl& FFT(const bool inverse=false) {
10386       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
10387       CImg<T> &Ir = data[0], &Ii = data[1];
10388       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
10389       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
10390         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
10391                                     pixel_type());
10392       if (Ir.depth>1)  FFT('z',inverse);
10393       if (Ir.height>1) FFT('y',inverse);
10394       if (Ir.width>1)  FFT('x',inverse);
10395       return *this;
10396     }
10397     
10399     CImgl get_FFT(const bool inverse=false) const { return CImgl<T>(*this).FFT(inverse); }
10400 
10402     CImgl get_FFT(const char axe,const bool inverse=false) const { return CImgl<T>(*this).FFT(axe,inverse); }
10403         
10405     //------------------------------------------
10406     //------------------------------------------
10407     //
10409 
10410     //------------------------------------------
10411     //------------------------------------------
10412     
10414     const CImgl& print(const char* title=NULL,const int print_flag=1) const { 
10415       char tmp[1024];
10416       std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p }\n",title?title:"CImgl",(void*)this,size,(void*)data);
10417       if (print_flag>0) cimgl_map(*this,l) {
10418         std::sprintf(tmp,"%s[%d]",title?title:"CImgl",l);
10419         data[l].print(tmp,print_flag);
10420       }
10421       return *this;
10422     }
10424 #define cimg_load_raw_case(Ts,Tss)                                               \
10425   if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l<n; l++) {  \
10426       const bool endian = cimg::endian();                               \
10427       j=0; while((i=std::fgetc(file))!='\n') tmp[j++]=(char)i; tmp[j]='\0';  \
10428       std::sscanf(tmp,"%u %u %u %u",&w,&h,&z,&k);                       \
10429       if (w*h*z*k>0) {                                                  \
10430         Tss *buf = new Tss[w*h*z*k]; cimg::fread(buf,sizeof(Tss),w*h*z*k,file);\
10431         if (endian) cimg::endian_swap(buf,w*h*z*k);                     \
10432         CImg<T> idest(w,h,z,k); cimg_mapoff(idest,off)                  \
10433                           idest[off] = (T)(buf[off]); idest.swap(res[l]); \
10434         delete[] buf;                                                   \
10435        }                                                                \
10436       loaded = true;                                                    \
10437     }
10438 
10439     static CImgl load_raw(const char *filename) {
10440       typedef unsigned char uchar;
10441       typedef unsigned short ushort;
10442       typedef unsigned int uint;  
10443       typedef unsigned long ulong; 
10444       std::FILE *file = cimg::fopen(filename,"rb");
10445       char tmp[256],tmp2[256];
10446       int i;
10447       bool loaded = false;
10448       unsigned int n,j,w,h,z,k,err;
10449       j=0; while((i=std::fgetc(file))!='\n' && i!=EOF) tmp[j++]=i; tmp[j]='\0';
10450       err=std::sscanf(tmp,"%u#%255[A-Za-z ]",&n,tmp2);
10451       if (err!=2) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', Unknow .raw header",pixel_type(),filename);
10452       CImgl<T> res(n);
10453       cimg_load_raw_case("unsigned char",uchar);
10454       cimg_load_raw_case("uchar",uchar);
10455       cimg_load_raw_case("char",char);
10456       cimg_load_raw_case("unsigned short",ushort);
10457       cimg_load_raw_case("ushort",ushort);
10458       cimg_load_raw_case("short",short);
10459       cimg_load_raw_case("unsigned int",uint);
10460       cimg_load_raw_case("uint",uint);
10461       cimg_load_raw_case("int",int);
10462       cimg_load_raw_case("unsigned long",ulong);
10463       cimg_load_raw_case("ulong",ulong);
10464       cimg_load_raw_case("long",long);
10465       cimg_load_raw_case("float",float);
10466       cimg_load_raw_case("double",double);
10467       if (!loaded) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', can't read images of %s",pixel_type(),filename,tmp2);
10468       cimg::fclose(file);
10469       return res;
10470     }
10471 
10473     static CImgl load(const char *filename) {
10474       CImgl res;
10475       const char *ext = cimg::filename_split(filename);
10476       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return load_raw(filename); else return CImg<T>(filename);
10477     }
10478 
10479 
10481 
10484     const CImgl& save(const char *filename) const {
10485       cimgl_test(*this,"CImgl<T>::save");
10486       const char *ext = cimg::filename_split(filename);
10487       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return save_raw(filename);
10488       else {
10489         if (size==1) data[0].save(filename,-1);
10490         else cimgl_map(*this,l) data[l].save(filename,l);
10491       }
10492       return *this;
10493     }
10494 
10496 
10501     const CImgl& save_raw(const char *filename) const {
10502       cimgl_test(*this,"CImgl<T>::save_raw");
10503       std::FILE *file = cimg::fopen(filename,"wb");
10504       std::fprintf(file,"%u#%s\n",size,pixel_type());
10505       cimgl_map(*this,l) {
10506         const CImg<T>& img = data[l];
10507         std::fprintf(file,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim);
10508         if (img.data) {
10509           if (cimg::endian()) {
10510             CImg<T> tmp(img);
10511             cimg::endian_swap(tmp.data,tmp.size());
10512             cimg::fwrite(tmp.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
10513           } else cimg::fwrite(img.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
10514         }
10515       }
10516       cimg::fclose(file);
10517       return *this;
10518     }  
10519 
10521 
10526     CImg<T> get_append(const char axe='x',const char align='c') const {
10527       cimgl_test(*this,"CImgl<T>::get_append");
10528       unsigned int dx=0,dy=0,dz=0,dv=0,pos=0;
10529       CImg<T> res;
10530       switch(cimg::uncase(axe)) {
10531       case 'x': {
10532         cimgl_map(*this,l) {
10533           const CImg<T>& img = (*this)[l];
10534           dx += img.width;
10535           dy = cimg::max(dy,img.height);
10536           dz = cimg::max(dz,img.depth);
10537           dv = cimg::max(dv,img.dim);
10538         }
10539         res = CImg<T>(dx,dy,dz,dv,0);
10540         switch (cimg::uncase(align)) {
10541         case 'p' : { cimgl_map(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break;
10542         case 'n' : { cimgl_map(*this,ll) { 
10543               res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width;
10544             }} break;
10545         default  : { cimgl_map(*this,ll) {
10546               res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
10547               pos+=(*this)[ll].width; 
10548             }} break;
10549         }
10550       } break;
10551       case 'y': {
10552         cimgl_map(*this,l) {
10553           const CImg<T>& img = (*this)[l];
10554           dx = cimg::max(dx,img.width);
10555           dy += img.height;
10556           dz = cimg::max(dz,img.depth);
10557           dv = cimg::max(dv,img.dim);
10558         }
10559         res = CImg<T>(dx,dy,dz,dv,0);
10560         switch (cimg::uncase(align)) {
10561         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break;
10562         case 'n': { cimgl_map(*this,ll) { 
10563               res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height;
10564             }} break;
10565         default : { cimgl_map(*this,ll) { 
10566               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
10567               pos+=(*this)[ll].height; 
10568             }} break;
10569         }
10570       } break;
10571       case 'z': {
10572         cimgl_map(*this,l) {
10573           const CImg<T>& img = (*this)[l];
10574           dx = cimg::max(dx,img.width);
10575           dy = cimg::max(dy,img.height);
10576           dz += img.depth;
10577           dv = cimg::max(dv,img.dim);
10578         }
10579         res = CImg<T>(dx,dy,dz,dv,0);
10580         switch (cimg::uncase(align)) {
10581         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break;
10582         case 'n': { cimgl_map(*this,ll) { 
10583               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth;
10584             }} break;
10585         case 'c': { cimgl_map(*this,ll) { 
10586               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2);
10587               pos+=(*this)[ll].depth; 
10588             }} break;
10589         }
10590       } break;
10591       case 'v': {
10592         cimgl_map(*this,l) {
10593           const CImg<T>& img = (*this)[l];
10594           dx = cimg::max(dx,img.width);
10595           dy = cimg::max(dy,img.height);
10596           dz = cimg::max(dz,img.depth);
10597           dv += img.dim;
10598         }
10599         res = CImg<T>(dx,dy,dz,dv,0);
10600         switch (cimg::uncase(align)) {
10601         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break;
10602         case 'n': { cimgl_map(*this,ll) { 
10603               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim;
10604             }} break;
10605         case 'c': { cimgl_map(*this,ll) { 
10606               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos);
10607               pos+=(*this)[ll].dim; 
10608             }} break;
10609         }
10610       } break;
10611       default: throw CImgArgumentException("CImg<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
10612       }
10613       return res;
10614     }
10615 
10616     // Create an auto-cropped font (along the X axis) from a input font \p font.
10617     CImgl<T> get_crop_font(const unsigned int padding=1) const {
10618       CImgl<T> res;
10619       cimgl_map(*this,l) {
10620         const CImg<T>& letter = (*this)[l];
10621         int xmin=letter.width, xmax = 0;
10622         cimg_mapXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
10623         if (xmin>xmax) res.insert(CImg<T>(4*padding,(*this)[' '].height,1,(*this)[' '].dim,0));
10624         else res.insert(letter.get_crop(xmin,0,xmax+padding,letter.height));
10625       }
10626       return res;
10627     }
10628     
10629     CImgl<T>& crop_font(const unsigned int padding=1) {
10630       return get_crop_font(padding).swap(*this);
10631     }
10632 
10634 
10638     static CImgl<T> get_font(const unsigned int *const font,const unsigned int w,const unsigned int h,
10639                              const int padding=1) {
10640       CImgl<T> res = CImgl<T>(256,w,h,1,3).insert(CImgl<T>(256,w,h,1,1));
10641       const unsigned int *ptr = font;
10642       unsigned long m = 0, val = 0;
10643       for (unsigned int y=0; y<h; y++)
10644         for (unsigned int x=0; x<256*w; x++) {
10645           m>>=1; if (!m) { m=0x80000000; val = *(ptr++); }
10646           CImg<T>& img = res[x/w], &mask = res[x/w+256];
10647           unsigned int xm = x%w;
10648           img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
10649         }
10650       if (padding>=0) return res.get_crop_font(padding);
10651       return res;
10652     }
10653 
10654     static CImgl<T> get_font10x13(const bool fixed_size = false) {
10655       static CImgl<T> nfixed, fixed;
10656       if (fixed_size) {
10657         if (!fixed.size) fixed = get_font(cimg::font10x13,10,13,-1);
10658         return fixed;
10659       } 
10660       if (!nfixed.size) nfixed = get_font(cimg::font10x13,10,13,1);
10661       return nfixed;
10662     }
10663 
10664     static CImgl<T> get_font7x11(const bool fixed_size = false) {
10665       static CImgl<T> nfixed, fixed;
10666       if (fixed_size) {
10667         if (!fixed.size) fixed = get_font(cimg::font7x11,7,11,-1);
10668         return fixed;
10669       } 
10670       if (!nfixed.size) nfixed = get_font(cimg::font7x11,7,11,1);
10671       return nfixed;
10672     }
10673     
10675 
10684     const CImgl& display(CImgDisplay& disp,const char axe='x',const char align='c') const { 
10685       get_append(axe,align).display(disp); return *this; 
10686     }
10687 
10689 
10698     const CImgl& display(CImgDisplay* disp,const char axe='x',const char align='c') const { 
10699       if (!disp) throw CImgArgumentException("CImgl<%s>::display() : given display pointer is (null)",pixel_type());
10700       else display(*disp,axe,align);
10701       return *this;
10702     }
10703 
10705 
10718     const CImgl& display(const char* title,const char axe='x',const char align='c',
10719                          const int min_size=128,const int max_size=1024) const {
10720       get_append(axe,align).display(title,min_size,max_size);
10721       return *this;
10722     }
10723 
10725 
10737     const CImgl& display(const char axe='x',const char align='c',
10738                          const int min_size=128,const int max_size=1024) const {
10739       return display("",axe,align,min_size,max_size); 
10740     }
10741 
10743 
10746     const CImgl& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
10747     
10748     // Swap fields of two CImgl instances.
10749     CImgl& swap(CImgl& list) {
10750       cimg::swap(size,list.size);
10751       cimg::swap(data,list.data);
10752       return list;
10753     }
10754 
10755 #ifdef cimgl_plugin
10756 #include cimgl_plugin
10757 #endif
10758    
10760   };
10761 
10762 
10764 
10770   template<typename T> struct CImgROI : public CImg<T> {
10771     CImgROI(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,T *const pdata) {
10772       CImg<T>::width = dx; CImg<T>::height = dy; CImg<T>::depth = dz; CImg<T>::dim = dv; CImg<T>::data = pdata;
10773     }
10774     CImgROI(const CImgROI& roi):CImg<T>() {
10775       CImg<T>::width = roi.width; CImg<T>::height = roi.height; CImg<T>::depth = roi.depth; CImg<T>::dim = roi.dim; 
10776       CImg<T>::data = roi.data;
10777     }
10778     ~CImgROI() { CImg<T>::width=CImg<T>::height=CImg<T>::depth=CImg<T>::dim=0; CImg<T>::data=NULL;}
10779     
10780     template<typename t> CImgROI<T>& operator=(const CImg<t>& img) { 
10781       if (img.width!=CImg<T>::width || img.height!=CImg<T>::height ||
10782           img.depth!=CImg<T>::depth || img.dim!=CImg<T>::dim)
10783         throw CImgArgumentException("CImgROI<%s>::operator=() : Affectation to CImgROI instances must supply "
10784                                     "data with same dimensions",CImg<T>::pixel_type());
10785       const t* ptrs = img.data + CImg<T>::size();
10786       for (T *ptrd = CImg<T>::data+CImg<T>::size(); ptrd>CImg<T>::data; ) *(--ptrd) = (T)*(--ptrs);
10787       return *this;
10788     }
10789 
10790     CImgROI& operator=(const CImg<T>& img) {
10791       if (&img==this) return *this;
10792       if (img.width!=CImg<T>::width || img.height!=CImg<T>::height ||
10793           img.depth!=CImg<T>::depth || img.dim!=CImg<T>::dim)
10794         throw CImgArgumentException("CImgROI<%s>::operator=() : Affectation to CImgROI instances must supply "
10795                                     "data with same dimensions",CImg<T>::pixel_type());
10796       std::memcpy(CImg<T>::data,img.data,sizeof(T)*CImg<T>::size());
10797       return *this;
10798     }
10799     
10800   };
10801 
10802 namespace cimg {
10803   
10805 
10821   template<typename t>
10822   static int dialog(const char *title,const char *msg,
10823                     const char *button1_txt,const char *button2_txt,
10824                     const char *button3_txt,const char *button4_txt,
10825                     const char *button5_txt,const char *button6_txt,
10826                     const CImg<t>& logo) {
10827 #if cimg_display_type!=0
10828     const unsigned char
10829       black[3]={0,0,0}, white[3]={255,255,255}, gray[3]={200,200,200}, gray2[3]={150,150,150};
10830       
10831       // Create buttons and canvas graphics
10832       CImgl<unsigned char> buttons, cbuttons, sbuttons;
10833       const CImgl<unsigned char> tahoma = CImgl<unsigned char>::get_font10x13(false);
10834       if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(button1_txt,0,0,black,gray,tahoma));
10835       if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(button2_txt,0,0,black,gray,tahoma));
10836       if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(button3_txt,0,0,black,gray,tahoma));
10837       if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(button4_txt,0,0,black,gray,tahoma));
10838       if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(button5_txt,0,0,black,gray,tahoma));
10839       if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(button6_txt,0,0,black,gray,tahoma));
10840       }}}}}}
10841       if (!buttons.size) throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
10842       
10843       unsigned int bw=0, bh=0;
10844       cimgl_map(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
10845       bw+=8; bh+=8;
10846       if (bw<64) bw=64;
10847       if (bw>128) bw=128;
10848       if (bh<24) bh=24;
10849       if (bh>48) bh=48;
10850       
10851       CImg<unsigned char> button = CImg<unsigned char>(bw,bh,1,3).
10852         draw_rectangle(0,0,bw-1,bh-1,gray).
10853         draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white).
10854         draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black).
10855         draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
10856       CImg<unsigned char> sbutton = CImg<unsigned char>(bw,bh,1,3).
10857         draw_rectangle(0,0,bw-1,bh-1,gray).
10858         draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black).
10859         draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black).
10860         draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white).
10861         draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black).
10862         draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2).
10863         draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA).
10864         draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA);
10865       CImg<unsigned char> cbutton = CImg<unsigned char>(bw,bh,1,3).
10866         draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray).
10867         draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA).
10868         draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA);
10869 
10870         cimgl_map(buttons,ll) {
10871           cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(buttons[ll],1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2));
10872           sbuttons.insert(CImg<unsigned char>(sbutton).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2));
10873           buttons[ll] = CImg<unsigned char>(button).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2);
10874         }
10875         
10876         CImg<unsigned char> canvas;
10877         if (msg) canvas = CImg<unsigned char>().draw_text(msg,0,0,black,gray,tahoma);
10878         const unsigned int 
10879           bwall = (buttons.size-1)*(12+bw) + bw,
10880           w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
10881           h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
10882           lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
10883           ly = (h-12-bh-logo.height)/2,
10884           tx = lx+logo.width+12,
10885           ty = (h-12-bh-canvas.height)/2,
10886           bx = (w-bwall)/2,
10887           by = h-12-bh;
10888         
10889         if (canvas.data)
10890           canvas = CImg<unsigned char>(w,h,1,3).
10891             draw_rectangle(0,0,w-1,h-1,gray).
10892             draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
10893             draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
10894             draw_image(canvas,tx,ty);
10895         else 
10896           canvas = CImg<unsigned char>(w,h,1,3).
10897             draw_rectangle(0,0,w-1,h-1,gray).
10898             draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
10899             draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
10900         if (logo.data) canvas.draw_image(logo,lx,ly);
10901         
10902         unsigned int xbuttons[6];
10903         cimgl_map(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(buttons[lll],xbuttons[lll],by); }
10904         
10905         // Open window and enter events loop  
10906         CImgDisplay disp(canvas,title?title:"",0,3);
10907         bool stopflag = false, refresh = false;
10908         int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
10909         while (!disp.closed && !stopflag) {
10910           if (refresh) {
10911             if (clicked>=0) CImg<unsigned char>(canvas).draw_image(cbuttons[clicked],xbuttons[clicked],by).display(disp);
10912             else {
10913               if (selected>=0) CImg<unsigned char>(canvas).draw_image(sbuttons[selected],xbuttons[selected],by).display(disp);
10914               else canvas.display(disp);
10915             }
10916             refresh = false;
10917           }
10918           disp.wait(40);
10919           if (disp.resized) disp.resize(disp);
10920           
10921           if (disp.button&1)  {
10922             oclicked = clicked;
10923             clicked = -1;
10924             cimgl_map(buttons,l)
10925               if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
10926                   disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
10927                 clicked = selected = l;
10928                 refresh = true;
10929               }
10930             if (clicked!=oclicked) refresh = true;
10931           } else if (clicked>=0) stopflag = true;
10932           
10933           if (disp.key) {
10934             oselected = selected;
10935             switch (disp.key) {
10936             case cimg::keyESC: selected=-1; stopflag=true; break;
10937             case cimg::keyENTER: if (selected<0) selected=0; stopflag = true; break;
10938             case cimg::keyTAB:
10939             case cimg::keyARROWRIGHT:
10940             case cimg::keyARROWDOWN: selected = (selected+1)%buttons.size; break;
10941             case cimg::keyARROWLEFT:
10942             case cimg::keyARROWUP: selected = (selected+buttons.size-1)%buttons.size; break;
10943             }
10944             disp.key=0;
10945             if (selected!=oselected) refresh = true;
10946           }
10947         }
10948         if (disp.closed) selected = -1;
10949         return selected;
10950 #else
10951         std::fprintf(stderr,"<%s>\n\n%s\n\n",title,msg);
10952         return -1;
10953 #endif
10954   }
10955   
10956   static int dialog(const char *title,const char *msg,const char *button1_txt,const char *button2_txt,
10957                     const char *button3_txt,const char *button4_txt,const char *button5_txt,const char *button6_txt) {
10958     return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
10959                   CImg<unsigned char>::get_logo40x38());
10960   }
10961 }
10962 
10963 }
10964 
10965 // Overcome VisualC++ 6.0 and DMC compilers namespace bug
10966 #if ( defined(_MSC_VER) || defined(__DMC__) ) && defined(std)
10967 #undef std
10968 #endif
10969 
10970 /*--------------------------------------------------------------------------------------
10971 
10972 
10973 
10974   Additional documentation for the generation of the reference page (using doxygen)
10975 
10976 
10977 
10978   -------------------------------------------------------------------------------------*/
10997 //---------------------------------------------------------------------------------------------------------------
10999 
11138 
11139 //--------------------------------------------------------------------------------------------------------------------
11141 
11212 
11213 //--------------------------------------------------------------------------------------------------------------------
11215 
11313 
11314 //----------------------------------------------------------------------------------------------------
11316 
11338 
11339 //----------------------------------------------------------------------------------------------------
11341 
11577 
11578 //----------------------------------------------------------------------------------------------------
11580 
11601 
11602 
11603 //----------------------------------------------------------------------------------------------------
11605 
11611 
11612 
11613 
11614 
11615 //----------------------------------------------------------------------------------------------------
11617 
11634 
11635 //----------------------------------------------------------------------------------------------------
11637 
11723 //----------------------------------------------------------------------------------------------------
11724 #endif
11725 
11726 // Local Variables:
11727 // mode: c++
11728 // End:

Generated on Mon Jul 4 09:51:35 2005 for The CImg Library by  doxygen 1.3.9