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 // PC 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     inline X11info& X11attr() { static X11info val; return val; }
00731 #endif
00732 #ifdef cimg_color_terminal
00733     const char t_normal[9]  = {0x1b,'[','0',';','0',';','0','m','\0'};
00734     const char t_red[11]    = {0x1b,'[','4',';','3','1',';','5','9','m','\0'};
00735     const char t_bold[5]    = {0x1b,'[','1','m','\0'};
00736     const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'};
00737 #else
00738     const char t_normal[1]  = {'\0'};
00739     static const char *t_red = cimg::t_normal, *t_bold = cimg::t_normal, *t_purple = cimg::t_normal;
00740 #endif
00741     
00742 #if cimg_display_type==1
00743     // Keycodes for X11-based graphical systems
00744     const unsigned int keyESC        = XK_Escape;
00745     const unsigned int keyF1         = XK_F1;
00746     const unsigned int keyF2         = XK_F2;
00747     const unsigned int keyF3         = XK_F3;
00748     const unsigned int keyF4         = XK_F4;
00749     const unsigned int keyF5         = XK_F5;
00750     const unsigned int keyF6         = XK_F6;
00751     const unsigned int keyF7         = XK_F7;
00752     const unsigned int keyF8         = XK_F8;
00753     const unsigned int keyF9         = XK_F9;
00754     const unsigned int keyF10        = XK_F10;
00755     const unsigned int keyF11        = XK_F11;
00756     const unsigned int keyF12        = XK_F12;
00757     const unsigned int keyPAUSE      = XK_Pause;
00758     const unsigned int key1          = XK_1;
00759     const unsigned int key2          = XK_2;
00760     const unsigned int key3          = XK_3;
00761     const unsigned int key4          = XK_4;
00762     const unsigned int key5          = XK_5;
00763     const unsigned int key6          = XK_6;
00764     const unsigned int key7          = XK_7;
00765     const unsigned int key8          = XK_8;
00766     const unsigned int key9          = XK_9;
00767     const unsigned int key0          = XK_0;
00768     const unsigned int keyBACKSPACE  = XK_BackSpace;
00769     const unsigned int keyINSERT     = XK_Insert;
00770     const unsigned int keyHOME       = XK_Home;
00771     const unsigned int keyPAGEUP     = XK_Page_Up;
00772     const unsigned int keyTAB        = XK_Tab;
00773     const unsigned int keyQ          = XK_q;
00774     const unsigned int keyW          = XK_w;
00775     const unsigned int keyE          = XK_e;
00776     const unsigned int keyR          = XK_r;
00777     const unsigned int keyT          = XK_t;
00778     const unsigned int keyY          = XK_y;
00779     const unsigned int keyU          = XK_u;
00780     const unsigned int keyI          = XK_i;
00781     const unsigned int keyO          = XK_o;
00782     const unsigned int keyP          = XK_p;
00783     const unsigned int keyDELETE     = XK_Delete;
00784     const unsigned int keyEND        = XK_End;
00785     const unsigned int keyPAGEDOWN   = XK_Page_Down;
00786     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
00787     const unsigned int keyA          = XK_a;
00788     const unsigned int keyS          = XK_s;
00789     const unsigned int keyD          = XK_d;
00790     const unsigned int keyF          = XK_f;
00791     const unsigned int keyG          = XK_g;
00792     const unsigned int keyH          = XK_h;
00793     const unsigned int keyJ          = XK_j;
00794     const unsigned int keyK          = XK_k;
00795     const unsigned int keyL          = XK_l;
00796     const unsigned int keyENTER      = XK_Return;
00797     const unsigned int keySHIFTLEFT  = XK_Shift_L;
00798     const unsigned int keyZ          = XK_z;
00799     const unsigned int keyX          = XK_x;
00800     const unsigned int keyC          = XK_c;
00801     const unsigned int keyV          = XK_v;
00802     const unsigned int keyB          = XK_b;
00803     const unsigned int keyN          = XK_n;
00804     const unsigned int keyM          = XK_m;
00805     const unsigned int keySHIFTRIGHT = XK_Shift_R;
00806     const unsigned int keyARROWUP    = XK_Up;
00807     const unsigned int keyCTRLLEFT   = XK_Control_L;
00808     const unsigned int keyAPPLEFT    = XK_Super_L;
00809     const unsigned int keySPACE      = XK_space;
00810     const unsigned int keyALTGR      = XK_Alt_R;
00811     const unsigned int keyAPPRIGHT   = XK_Super_R;
00812     const unsigned int keyMENU       = XK_Menu;
00813     const unsigned int keyCTRLRIGHT  = XK_Control_R;
00814     const unsigned int keyARROWLEFT  = XK_Left;
00815     const unsigned int keyARROWDOWN  = XK_Down;
00816     const unsigned int keyARROWRIGHT = XK_Right;  
00817 #endif
00818 
00819 #if cimg_display_type==2 && cimg_OS==2
00820     // Keycodes for Windows-OS
00822 
00823 
00831     const unsigned int keyESC        = 27;
00832     const unsigned int keyF1         = 112;
00833     const unsigned int keyF2         = 113;
00834     const unsigned int keyF3         = 114;
00835     const unsigned int keyF4         = 115;
00836     const unsigned int keyF5         = 116;
00837     const unsigned int keyF6         = 117;
00838     const unsigned int keyF7         = 118;
00839     const unsigned int keyF8         = 119;
00840     const unsigned int keyF9         = 120;
00841     const unsigned int keyF10        = 121;
00842     const unsigned int keyF11        = 122;
00843     const unsigned int keyF12        = 123;
00844     const unsigned int keyPAUSE      = 19;
00845     const unsigned int key1          = 49;
00846     const unsigned int key2          = 50;
00847     const unsigned int key3          = 51;
00848     const unsigned int key4          = 52;
00849     const unsigned int key5          = 53;
00850     const unsigned int key6          = 54;
00851     const unsigned int key7          = 55;
00852     const unsigned int key8          = 56;
00853     const unsigned int key9          = 57;
00854     const unsigned int key0          = 48;
00855     const unsigned int keyBACKSPACE  = 8;
00856     const unsigned int keyINSERT     = 45;
00857     const unsigned int keyHOME       = 36;
00858     const unsigned int keyPAGEUP     = 33;
00859     const unsigned int keyTAB        = 9;
00860     const unsigned int keyQ          = 81;
00861     const unsigned int keyW          = 87;
00862     const unsigned int keyE          = 69;
00863     const unsigned int keyR          = 82;
00864     const unsigned int keyT          = 84;
00865     const unsigned int keyY          = 89;
00866     const unsigned int keyU          = 85;
00867     const unsigned int keyI          = 73;
00868     const unsigned int keyO          = 79;
00869     const unsigned int keyP          = 80;
00870     const unsigned int keyDELETE     = 8;
00871     const unsigned int keyEND        = 35;
00872     const unsigned int keyPAGEDOWN   = 34;
00873     const unsigned int keyCAPSLOCK   = 20;
00874     const unsigned int keyA          = 65;
00875     const unsigned int keyS          = 83;
00876     const unsigned int keyD          = 68;
00877     const unsigned int keyF          = 70;
00878     const unsigned int keyG          = 71;
00879     const unsigned int keyH          = 72;
00880     const unsigned int keyJ          = 74;
00881     const unsigned int keyK          = 75;
00882     const unsigned int keyL          = 76;
00883     const unsigned int keyENTER      = 13;
00884     const unsigned int keySHIFTLEFT  = 16;
00885     const unsigned int keyZ          = 90;
00886     const unsigned int keyX          = 88;
00887     const unsigned int keyC          = 67;
00888     const unsigned int keyV          = 86;
00889     const unsigned int keyB          = 66;
00890     const unsigned int keyN          = 78;
00891     const unsigned int keyM          = 77;
00892     const unsigned int keySHIFTRIGHT = 16;
00893     const unsigned int keyARROWUP    = 38;
00894     const unsigned int keyCTRLLEFT   = 17;
00895     const unsigned int keyAPPLEFT    = 91;
00896     const unsigned int keySPACE      = 32;
00897     const unsigned int keyALTGR      = 17;
00898     const unsigned int keyAPPRIGHT   = 92;
00899     const unsigned int keyMENU       = 93;
00900     const unsigned int keyCTRLRIGHT  = 17;
00901     const unsigned int keyARROWLEFT  = 37;
00902     const unsigned int keyARROWDOWN  = 40;
00903     const unsigned int keyARROWRIGHT = 39;
00904 #endif
00905 
00906 
00907 #ifdef PI
00908 #undef PI
00909 #endif
00910     const double PI = 3.14159265358979323846;   
00911     const int infinity_int  = 0x7f800000;
00912     const double infinity = (double)*(float*)&cimg::infinity_int;
00913     
00914     // Definition of a 10x13 font (used in dialog boxes).
00915     const unsigned int font10x13[256*10*13/8] = {
00916       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00917       0x0,0x0,0x0,0x0,0x0,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,
00918       0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00919       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00920       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,
00921       0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00922       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,
00923       0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00924       0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
00925       0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
00926       0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
00927       0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
00928       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
00929       0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
00930       0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
00931       0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
00932       0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
00933       0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
00934       0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
00935       0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
00936       0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
00937       0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
00938       0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
00939       0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
00940       0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
00941       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
00942       0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
00943       0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00944       0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
00945       0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
00946       0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
00947       0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
00948       0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
00949       0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
00950       0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
00951       0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
00952       0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
00953       0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
00954       0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00955       0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
00956       0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
00957       0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
00958       0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
00959       0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
00960       0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
00961       0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
00962       0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
00963       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
00964       0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
00965       0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
00966       0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
00967       0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
00968       0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
00969       0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
00970       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
00971       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,
00972       0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
00973       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,
00974       0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
00975     };
00976     
00977     // Definition of a 7x11 font, used to return a default font for drawing text.
00978     const unsigned int font7x11[7*11*256/8] = {
00979       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,
00980       0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
00981       0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
00982       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00983       0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
00984       0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
00985       0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
00986       0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
00987       0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
00988       0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
00989       0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00990       0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
00991       0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00992       0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
00993       0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00994       0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
00995       0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00996       0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
00997       0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
00998       0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
00999       0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01000       0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
01001       0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
01002       0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
01003       0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
01004       0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
01005       0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
01006       0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
01007       0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
01008       0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
01009       0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
01010       0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
01011       0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
01012       0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
01013       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,
01014       0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
01015       0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
01016     };
01017 
01018     // Definition of a 40x38 'danger' color logo
01019     const unsigned char logo40x38[4576] = {
01020       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,
01021       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,
01022       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,
01023       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,
01024       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,
01025       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,
01026       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,
01027       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,
01028       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,
01029       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,
01030       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,
01031       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,
01032       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,
01033       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,
01034       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,
01035       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,
01036       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,
01037       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,
01038       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,
01039       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,
01040       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,
01041       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,
01042       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,
01043       200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
01044   
01045     // Return a 'stringification' of standart integral types.
01046     const char* const bool_st    = "bool";
01047     const char* const uchar_st   = "unsigned char";
01048     const char* const char_st    = "char";
01049     const char* const ushort_st  = "unsigned short";
01050     const char* const short_st   = "short";
01051     const char* const uint_st    = "unsigned int";
01052     const char* const int_st     = "int";
01053     const char* const ulong_st   = "unsigned long";
01054     const char* const long_st    = "long";
01055     const char* const float_st   = "float";
01056     const char* const double_st  = "double";
01057     const char* const unknown_st = "unknown";
01058     template<typename t> inline const char* get_type(const t&) { return cimg::unknown_st; }
01059     inline const char* get_type(const bool&          ) { return cimg::bool_st;   }
01060     inline const char* get_type(const unsigned char& ) { return cimg::uchar_st;  }
01061     inline const char* get_type(const char&          ) { return cimg::char_st;   }
01062     inline const char* get_type(const unsigned short&) { return cimg::ushort_st; }
01063     inline const char* get_type(const short&         ) { return cimg::short_st;  }
01064     inline const char* get_type(const unsigned int&  ) { return cimg::uint_st;   }
01065     inline const char* get_type(const int&           ) { return cimg::int_st;    }
01066     inline const char* get_type(const unsigned long& ) { return cimg::ulong_st;  }
01067     inline const char* get_type(const long&          ) { return cimg::long_st;   }
01068     inline const char* get_type(const float&         ) { return cimg::float_st;  }
01069     inline const char* get_type(const double&        ) { return cimg::double_st; }
01070     
01072     template<typename t> inline const t get_type_min(const t&) {
01073       static const double p = std::pow(2.0,8.0*sizeof(t)-1.0);
01074       static const t res = (t)(((t)-1)>=0?0:(-p)); 
01075       return res;
01076     }
01077     inline const float get_type_min(const float&)   { return -(float)cimg::infinity; }
01078     inline const double get_type_min(const double&) { return -cimg::infinity; }
01079 
01081     template<typename t> inline const t get_type_max(const t&) {
01082       static const double p = std::pow(2.0,8.0*sizeof(t)-1.0);
01083       static const t res = (t)(((t)-1)>=0?(2*p-1):(p-1));
01084       return res;
01085     }
01086     inline const float get_type_max(const float&)   { return (float)cimg::infinity; }
01087     inline const double get_type_max(const double&) { return cimg::infinity; }
01088                                                                        
01089     // Display a warning message
01090 #if cimg_debug>=1    
01091     static void warn(const bool cond,const char *format,...) {
01092       if (cond) {
01093         std::va_list ap;
01094         va_start(ap,format);
01095         std::fprintf(stderr,"<CImg Warning> ");
01096         std::vfprintf(stderr,format,ap);
01097         std::fputc('\n',stderr);
01098         va_end(ap);
01099       }
01100     }
01101 #else
01102     inline void warn(const bool cond,const char *format,...) {}
01103 #endif
01104 
01105     inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; }
01106     inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); }
01107     inline float atof(const char *str) {
01108       float x=0,y=1;
01109       if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
01110     }
01111     inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; }
01112     inline int strncmp(const char *s1,const char *s2,const int l) {
01113       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=std::abs(s1[k] - s2[k]); return n; }
01114       return 0;
01115     }
01116     inline int strncasecmp(const char *s1,const char *s2,const int l) {
01117       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=std::abs(uncase(s1[k])-uncase(s2[k])); return n; }
01118       return 0;
01119     }
01120     inline int strcmp(const char *s1,const char *s2) { 
01121       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
01122       return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
01123     }
01124     inline int strcasecmp(const char *s1,const char *s2) { 
01125       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
01126       return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
01127     }
01128     inline int strfind(const char *s,const char c) {
01129       if (s) { 
01130         int l; for (l=cimg::strlen(s); l>=0 && s[l]!=c; l--) ;
01131         return l; 
01132       }
01133       return -1; 
01134     }
01135     inline const char* basename(const char *s)  {
01136       return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):NULL):(s?s+1+cimg::strfind(s,'\\'):NULL); 
01137     }
01138 
01139     inline void system(const char *command) {
01140 #if cimg_OS==2
01141       PROCESS_INFORMATION pi;
01142       STARTUPINFO si;
01143       GetStartupInfo(&si);
01144       si.wShowWindow = SW_HIDE;
01145       si.dwFlags |= SW_HIDE;
01146       BOOL res = CreateProcess(NULL,(LPTSTR)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
01147       if (res) {
01148         WaitForSingleObject(pi.hProcess, INFINITE);
01149         CloseHandle(pi.hThread);
01150         CloseHandle(pi.hProcess);
01151       }
01152 #else
01153       std::system(command);
01154 #endif
01155     }
01156     
01158 
01177     inline const char* convert_path() {
01178       static char *convert_path = NULL;
01179       if (!convert_path) {
01180 #if cimg_OS==2 || defined(cimg_convert_path)
01181         bool stopflag = false;
01182         std::FILE *file;
01183 #endif
01184         convert_path = new char[1024];
01185 #ifdef cimg_convert_path
01186         std::strcpy(convert_path,cimg_convert_path);
01187         if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01188 #endif
01189 #if cimg_OS==2
01190         for (unsigned int k=0; k<=9 && !stopflag; k++) {
01191           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u-Q\\convert.exe",k);
01192           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01193         }
01194         if (!stopflag) for (unsigned int k=0; k<=9 && !stopflag; k++) {
01195           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u\\convert.exe",k);
01196           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
01197         }
01198         if (!stopflag) std::strcpy(convert_path,"convert.exe");
01199 #else
01200         std::strcpy(convert_path,"convert");
01201 #endif
01202       }
01203       return convert_path;
01204     }
01205     
01207 
01224     inline const char* temporary_path() {
01225       static char *st_temporary_path = NULL;
01226       if (!st_temporary_path) {
01227         st_temporary_path = new char[1024];
01228 #ifdef cimg_temporary_path
01229         std::strcpy(st_temporary_path,cimg_temporary_path);
01230         const char* testing_path[7] = { st_temporary_path, "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
01231 #else
01232         const char* testing_path[6] = { "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
01233 #endif
01234         char filetmp[1024];
01235         std::FILE *file=NULL;
01236         int i=-1;
01237         while (!file && testing_path[++i]) {
01238           std::sprintf(filetmp,"%s/CImg%.4d.ppm",testing_path[i],std::rand()%10000);
01239           if ((file=std::fopen(filetmp,"w"))!=NULL) { std::fclose(file); std::remove(filetmp); }
01240         }
01241         if (!file) 
01242           throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
01243                                 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
01244                                 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
01245         std::strcpy(st_temporary_path,testing_path[i]);
01246       }
01247       return st_temporary_path;
01248     }
01249     
01250     inline const char *filename_split(const char *const filename, char *const body=NULL) {
01251       if (!filename) throw CImgArgumentException("cimg::filename_split() : Can't split the (null) filename");
01252       int l = cimg::strfind(filename,'.');
01253       if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }}
01254       else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; }
01255       return filename+l+1;
01256     }
01257     
01258     inline char* filename_number(const char *filename,const int number,const unsigned int n,char *const string) {
01259       char format[1024],body[1024];
01260       const char *ext = cimg::filename_split(filename,body);
01261       if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
01262       else std::sprintf(format,"%s_%%d.%s",body,ext);
01263       std::sprintf(string,format,number);
01264       return string;
01265     }
01266     inline std::FILE *fopen(const char *const path,const char *const mode) {
01267       if(!path || !mode) throw CImgArgumentException("cimg::fopen() : Can't open file '%s' with mode '%s'",path,mode);
01268       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; else {
01269         std::FILE *dest=std::fopen(path,mode);
01270         if(!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened %s",
01271                                         path,mode[0]=='r'?"for reading":(mode[0]=='w'?"for writing":""),path);
01272         return dest;
01273       }
01274     }
01275     inline int fclose(std::FILE *file) {
01276       warn(!file,"cimg::fclose() : Can't close (null) file");
01277       if (!file || file==stdin || file==stdout) return 0;
01278       const int errn=std::fclose(file);
01279       warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn);
01280       return errn;
01281     }
01282     template<typename T> inline int fread(T *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
01283       if (!ptr || size<=0 || nmemb<=0 || !stream)
01284         throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
01285                                     nmemb,size,stream,ptr);
01286       const unsigned int errn = (unsigned int)std::fread((void*)ptr,size,nmemb,stream);
01287       cimg::warn(errn!=nmemb,"cimg::fread() : File reading problems, only %u/%u elements read",errn,nmemb);
01288       return errn;
01289     }
01290     inline int fwrite(const void *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
01291       if (!ptr || size<=0 || nmemb<=0 || !stream)
01292         throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
01293                                     nmemb,size,stream,ptr);
01294       const unsigned int errn = (unsigned int)std::fwrite(ptr,size,nmemb,stream);
01295       if(errn!=nmemb)
01296         throw CImgIOException("cimg::fwrite() : File writing problems, only %u/%u elements written",errn,nmemb);
01297       return errn;
01298     }
01299     
01300     // Exchange the values of variables \p a and \p b
01301     template<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; }
01302     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2) {
01303       cimg::swap(a1,b1); cimg::swap(a2,b2); 
01304     }
01305     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3) {
01306       cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); 
01307     }
01308     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4) {
01309       cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); 
01310     }
01311     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) {
01312       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); 
01313     }
01314     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) {
01315       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
01316     }
01317     
01318     template<typename T> inline T& endian_swap(T& a) {  
01319       if (sizeof(a)!=1) {
01320         unsigned char *pb=(unsigned char*)&a, *pe=pb+sizeof(a);
01321         for (int i=0; i<(int)sizeof(a)/2; i++) cimg::swap(*(pb++),*(--pe));
01322       }
01323       return a;
01324     }
01325 
01326     template<typename T> inline void endian_swap(T *const buffer,const unsigned int size) {
01327       T *ptr = buffer;
01328       for (unsigned int i=0; i<size; i++) cimg::endian_swap(*(ptr++));
01329     }
01330 
01331     inline const char* option(const char *const name,const unsigned int argc,char **argv,const char *const defaut,
01332                               const char *const usage=NULL) {
01333       static bool first=true, visu=false;
01334       const char *res = NULL;
01335       if (first) { first=false; visu = cimg::option("-h",argc,argv,(const char*)NULL)!=NULL; }
01336       if (!name && visu) {
01337         std::fprintf(stderr,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
01338         if (usage) std::fprintf(stderr," : %s",usage);
01339         std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__);
01340       }
01341       if (name) {
01342         if (argc>0) {
01343           unsigned int k=0,i;
01344           while (k<argc && cimg::strcmp(argv[k],name)) k++;
01345           i=k;
01346           res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
01347         } else res = defaut;
01348         if (visu && usage) std::fprintf(stderr,"    %s%-8s%s = %-12s : %s%s%s\n",
01349                                         cimg::t_bold,name,cimg::t_normal,res?res:"NULL",cimg::t_purple,usage,cimg::t_normal);
01350       }
01351       return res;
01352     }
01353 
01354     inline bool option(const char *const name,const unsigned int argc,char **argv,
01355                        const bool defaut,const char *const usage=NULL) {
01356       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01357       const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
01358       cimg::option(name,0,NULL,res?"true":"false",usage);
01359       return res;
01360     }
01361 
01362     inline int option(const char *const name,const unsigned int argc,char **argv,
01363                       const int defaut,const char *const usage=NULL) {
01364       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01365       const int res = s?std::atoi(s):defaut;
01366       char tmp[256];
01367       std::sprintf(tmp,"%d",res);
01368       cimg::option(name,0,NULL,tmp,usage);
01369       return res;
01370     }
01371 
01372     inline char option(const char *const name,const unsigned int argc,char **argv,
01373                        const char defaut,const char *const usage=NULL) {
01374       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01375       const char res = s?s[0]:defaut;
01376       char tmp[8];
01377       tmp[0] = res;
01378       tmp[1] ='\0';
01379       cimg::option(name,0,NULL,tmp,usage);
01380       return res;
01381     }
01382 
01383     inline double option(const char *const name,const unsigned int argc,char **argv,
01384                          const double defaut,const char *const usage=NULL) {
01385       const char *s = cimg::option(name,argc,argv,(const char*)NULL);
01386       const double res = s?cimg::atof(s):defaut;
01387       char tmp[256];
01388       std::sprintf(tmp,"%g",res);
01389       cimg::option(name,0,NULL,tmp,usage);
01390       return res;
01391     }
01392     
01394     inline const bool endian() { const int x=1; return ((unsigned char*)&x)[0]?false:true; }
01395 
01397     inline void info() {
01398       std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n",
01399                    cimg::t_red,cimg_version,cimg::t_normal,__DATE__,__TIME__);
01400       std::fprintf(stderr,"  > Architecture   : %s%-12s%s %s(cimg_OS=%d)\n%s",
01401                    cimg::t_bold,
01402                    cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknown"),
01403                    cimg::t_normal,cimg::t_purple,cimg_OS,cimg::t_normal);
01404       std::fprintf(stderr,"  > Display type   : %s%-12s%s %s(cimg_display_type=%d)%s\n",
01405                    cimg::t_bold,cimg_display_type==0?"No":
01406                    (cimg_display_type==1?"X11":
01407                     (cimg_display_type==2?"WindowsGDI":
01408                      "Unknown")),
01409                    cimg::t_normal,cimg::t_purple,cimg_display_type,cimg::t_normal);
01410 #ifdef cimg_color_terminal
01411       std::fprintf(stderr,"  > Color terminal : %s%-12s%s %s(cimg_color_terminal defined)%s\n",
01412                    cimg::t_bold,"Yes",cimg::t_normal,cimg::t_purple,cimg::t_normal);
01413 #else
01414       std::fprintf(stderr,"  > Color terminal : %-12s (cimg_color_terminal undefined)\n","No");
01415 #endif
01416       std::fprintf(stderr,"  > Debug messages : %s%-12s%s %s(cimg_debug=%d)%s\n",cimg::t_bold,
01417                    cimg_debug==2?"High":(cimg_debug==1?"Yes":"No"),
01418                    cimg::t_normal,cimg::t_purple,cimg_debug,cimg::t_normal);
01419       std::fprintf(stderr,"\n");
01420     }
01421     
01423     inline long time() {
01424 #if cimg_OS==1
01425       struct timeval st_time;
01426       gettimeofday(&st_time,NULL);
01427       return (long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
01428 #elif cimg_OS==2
01429       static SYSTEMTIME st_time;
01430       GetSystemTime(&st_time);
01431       return (long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
01432 #else 
01433       return 0;
01434 #endif
01435     }
01436 
01438 
01443     inline void sleep(const int milliseconds) {
01444 #if cimg_OS==1
01445       struct timespec tv;
01446       tv.tv_sec = milliseconds/1000;
01447       tv.tv_nsec = (milliseconds%1000)*1000000;
01448       nanosleep(&tv,NULL);
01449 #elif cimg_OS==2
01450       Sleep(milliseconds);
01451 #endif
01452     }
01453 
01455 
01460     inline long wait(const int milliseconds=20,long reference_time=-1) {
01461       static long latest_time = cimg::time();
01462       if (reference_time>=0) latest_time = reference_time;
01463       const long current_time = cimg::time(), time_diff = milliseconds + latest_time - current_time;
01464       if (time_diff>0) { cimg::sleep(time_diff); return (latest_time = current_time + time_diff); }
01465       else return (latest_time = current_time);
01466     }
01467 
01469     template<typename T> inline const T rol(const T& a,const unsigned int n=1) { return (a<<n)|(a>>((sizeof(T)<<3)-n)); }
01471     template<typename T> inline const T ror(const T& a,const unsigned int n=1) { return (a>>n)|(a<<((sizeof(T)<<3)-n)); }
01472 
01473 #if ( !defined(_MSC_VER) || _MSC_VER>1200 )
01474 
01475     template<typename T> inline const T abs(const T& a) { return a>=0?a:-a; }
01476     inline const double abs(const double& a) { return std::fabs(a); }
01477     inline const float abs(const float& a)   { return (float)std::fabs((double)a); }
01478     inline const int abs(const int& a)       { return std::abs(a); }
01479     
01481     template<typename T> inline const T& min(const T& a,const T& b) { return a<=b?a:b; }
01483     template<typename T> inline const T& min(const T& a,const T& b,const T& c) { return cimg::min(cimg::min(a,b),c); }
01485     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); }
01487     template<typename T> inline const T& max(const T& a,const T& b) { return a>=b?a:b; }
01489     template<typename T> inline const T& max(const T& a,const T& b,const T& c) { return cimg::max(cimg::max(a,b),c); }
01491     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); }
01493     template<typename T> inline char sign(const T& x) { return (x<0)?-1:(x==0?0:1); }
01494 #else
01495     // Special versions due to object reference bug in VisualC++ 6.0.
01496     template<typename T> inline const T abs(const T a) { return a>=0?a:-a; }
01497     template<typename T> inline const T min(const T a,const T b) { return a<=b?a:b; }
01498     template<typename T> inline const T min(const T a,const T b,const T c) { return cimg::min(cimg::min(a,b),c); }
01499     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); }
01500     template<typename T> inline const T max(const T a,const T b) { return a>=b?a:b; }
01501     template<typename T> inline const T max(const T a,const T b,const T c) { return cimg::max(cimg::max(a,b),c); }
01502     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); }
01503     template<typename T> inline char sign(const T x) { return (x<0)?-1:(x==0?0:1); }
01504 #endif
01505 
01507 
01510     inline double mod(const double& x,const double& m) { return x-m*std::floor(x/m); }
01511     inline float  mod(const float& x,const float& m)   { return (float)(x-m*std::floor((double)x/m)); }
01512     inline int    mod(const int x,const int m)         { return x>=0?x%m:(x%m?m+x%m:0); }
01513 
01515 
01520     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)); }
01522     inline double rand() { return (double)std::rand()/RAND_MAX; }
01524     inline double crand() { return 1-2*cimg::rand(); }
01526     inline double grand() {
01527       return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*cimg::rand())))*std::cos((double)(2*PI*cimg::rand())); 
01528     }
01529 
01530     // Return (a^2+b^2)^0.5
01531     inline double pythagore(double a, double b) {
01532       const double absa = cimg::abs(a), absb = cimg::abs(b);
01533       if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
01534       else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
01535     }
01536   }
01537 
01538   /*-------------------------------------------------------
01539     
01540   
01541   
01542   
01543     Definition of the CImgStats structure
01544   
01545   
01546   
01547     
01548     ------------------------------------------------------*/
01550 
01564   struct CImgStats {
01565     double min;                 
01566     double max;                 
01567     double mean;                
01568     double variance;            
01569     int xmin;                   
01570     int ymin;                   
01571     int zmin;                   
01572     int vmin;                   
01573     int lmin;                   
01574     int xmax;                   
01575     int ymax;                   
01576     int zmax;                   
01577     int vmax;                   
01578     int lmax;                   
01579 
01581     CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1),
01582                 xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {}
01584     CImgStats(const CImgStats& stats):min(stats.min),max(stats.max),mean(stats.mean),variance(stats.variance),
01585                                       xmin(stats.xmin),ymin(stats.ymin),zmin(stats.zmin),vmin(stats.vmin),lmin(stats.lmin),
01586                                       xmax(stats.xmax),ymax(stats.ymax),zmax(stats.zmax),vmax(stats.vmax),lmax(stats.lmax) {};
01587 
01589 
01592     template<typename T> CImgStats(const CImg<T>& img,const bool compute_variance=true):mean(0),variance(0),lmin(-1),lmax(-1) {
01593       cimg_test(img,"CImgStats::CImgStats");
01594       T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin;
01595       cimg_map(img,ptr,T) {
01596         const T& a=*ptr;
01597         mean+=(double)a;
01598         if (a<pmin) { pmin=a; ptrmin = ptr; }
01599         if (a>pmax) { pmax=a; ptrmax = ptr; }
01600       }
01601       mean/=img.size();
01602       min=(double)pmin;
01603       max=(double)pmax;
01604       unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data);
01605       const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height;      
01606       vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.width; xmin = offmin%img.width;
01607       vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.width; xmax = offmax%img.width;
01608       if (compute_variance) {
01609         cimg_map(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
01610         variance/=img.size();
01611       }
01612     }
01613 
01615 
01619     template<typename T> CImgStats(const CImgl<T>& list,const bool compute_variance=true):mean(0),variance(0) {
01620       cimgl_test(list,"CImgStats::CImgStats");
01621       T pmin=list[0][0], pmax=pmin, *ptrmin=list[0].data, *ptrmax=ptrmin;
01622       int psize=0;
01623       cimgl_map(list,l) {
01624         cimg_map(list[l],ptr,T) {
01625           const T& a=*ptr;
01626           mean+=(double)a;
01627           if (a<pmin) { pmin=a; ptrmin = ptr; lmin = l; }
01628           if (a>pmax) { pmax=a; ptrmax = ptr; lmax = l; }
01629         }
01630         psize+=list[l].size();
01631       }
01632       mean/=psize;
01633       min=(double)pmin;
01634       max=(double)pmax;
01635       const CImg<T> &imin = list[lmin], &imax = list[lmax];
01636       unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data);
01637       const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height;
01638       vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.width; xmin = offmin%imin.width;
01639       const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height;
01640       vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.width; xmax = offmax%imax.width;
01641       if (compute_variance) {
01642         cimgl_map(list,l) cimg_map(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
01643         variance/=psize;
01644       }
01645     }
01646 
01648     CImgStats& operator=(const CImgStats stats) {
01649       min = stats.min;
01650       max = stats.max;
01651       mean = stats.mean;
01652       variance = stats.variance;
01653       xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin;
01654       xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax;
01655       return *this;
01656     }
01658     const CImgStats& print(const char* title=NULL) const {
01659       if (lmin>=0 && lmax>=0)
01660         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
01661                      "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n",
01662                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
01663                      lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax);
01664       else
01665         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
01666                      "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n",
01667                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
01668                      xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax);
01669       return *this;
01670     }
01671     
01672 #ifdef cimgstats_plugin
01673 #include cimgstats_plugin
01674 #endif
01675 
01676   };
01677 
01678   /*-------------------------------------------------------
01679   
01680 
01681 
01682 
01683     Definition of the CImgDisplay structure
01684 
01685 
01686 
01687 
01688   ------------------------------------------------------*/
01689 
01691 
01699   struct CImgDisplay {
01700 
01701     //------------------------
01702     //
01703     // CImgDisplay variables
01704     //
01705     //------------------------
01706 
01708 
01721     unsigned int width;
01722 
01724 
01737     unsigned int height;
01738 
01740 
01746     volatile unsigned int window_width;
01747 
01749 
01755     volatile unsigned int window_height;
01756 
01758     volatile int window_x;
01759 
01761     volatile int window_y;
01762 
01764 
01774     unsigned int normalization;
01775 
01777 
01788     unsigned int events;
01789 
01791 
01796     const bool fullscreen;
01797 
01799 
01807     volatile int mouse_x;
01808 
01810 
01818     volatile int mouse_y;
01819 
01822 
01837     volatile unsigned int button;
01838 
01840 
01865     volatile unsigned int key;
01866 
01868 
01891     volatile bool closed;
01892 
01894     volatile bool resized;
01895     volatile bool moved;
01896 
01897     // Not documented, internal use only.
01898     double min,max;
01899 
01900     //------------------------
01901     //
01902     // CImgDisplay functions
01903     //
01904     //------------------------
01905 
01907 
01913     const int dimx() const { return (int)width; }
01914 
01916 
01922     const int dimy() const { return (int)height; }
01923 
01924     const int window_dimx() const { return (int)window_width; }
01925     const int window_dimy() const { return (int)window_height; }    
01926 
01927     // operator=(). It is actually defined to avoid its use, and throw a CImgDisplay exception.
01928     CImgDisplay& operator=(const CImgDisplay&) {
01929       throw CImgDisplayException("CImgDisplay()::operator=() : Assignement of CImgDisplay is not allowed. Use pointers instead !");
01930       return *this;
01931     }
01932     
01934 
01936       const CImgDisplay& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; }
01937 
01939 
01948     template<typename T> CImgDisplay& display(const CImgl<T>& list,const char axe='x',const char align='c') { 
01949       return display(list.get_append(axe,align)); 
01950     } 
01951 
01953 
01961     template<typename T> CImgDisplay& resize(const CImg<T>& img,const bool redraw=false,const bool force=true) { 
01962       return resize(img.width,img.height,redraw,force); 
01963     }
01964 
01965     CImgDisplay& resize(const CImgDisplay& disp,const bool redraw=false,const bool force=true) {
01966       return resize(disp.width,disp.height,redraw,force);
01967     }
01968 
01969     CImgDisplay& resize(const bool redraw=false,const bool force=false) {
01970       resize(window_width,window_height,redraw,force);
01971       return *this;
01972     }
01973 
01974     // When no display available
01975     //---------------------------
01976 #if cimg_display_type==0
01977     void nodisplay_available() {
01978       static bool first = true;
01979       if (first) {
01980         cimg::warn(true,"CImgDisplay() : Display has been required but is not available (cimg_display_type=0)");
01981         first = false;
01982       }    
01983     }  
01985 
01994     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
01995                 const unsigned int normalization_type=1,const unsigned int events_type=3,
01996                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
01997       nodisplay_available(); 
01998     }
01999 
02001 
02008     template<typename T> 
02009     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02010                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02011                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
02012       nodisplay_available(); 
02013     }
02014     
02016 
02023     template<typename T> 
02024     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02025                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02026                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
02027       nodisplay_available(); 
02028     }
02029   
02031 
02034     CImgDisplay(const CImgDisplay& win, char *title=NULL):fullscreen(false) { nodisplay_available(); }
02035 
02037     CImgDisplay& resize(const int width, const int height,const bool redraw=false,const bool force=true) {
02038       return *this; 
02039     }
02041     CImgDisplay& move(const int posx,const int posy) { return *this; }
02042 
02044     ~CImgDisplay() {}
02046     template<typename T> void render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {}
02048     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=-1) { return *this; }
02050     CImgDisplay& wait()  { return *this; }
02052     CImgDisplay& show()  { return *this; }
02054     CImgDisplay& close() { return *this; }
02055   
02057     static const int screen_dimx() { return 0; }
02058 
02060     static const int screen_dimy() { return 0; }
02061 
02062     // X11-based display
02063     //------------------
02064 #elif cimg_display_type==1
02065     void *data;
02066     Window window;
02067     XImage *image;
02068  
02069     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
02070                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02071                 const bool fullscreen_flag=false,const bool closed_flag=false):
02072       width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3),
02073       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02074       if (!dimw || !dimh) throw CImgArgumentException("CImgDisplay::CImgDisplay() : null size specified");
02075       new_lowlevel(title);
02076       std::memset(data,0,(cimg::X11attr().nb_bits>16?sizeof(unsigned int):sizeof(unsigned short))*width*height);
02077       pthread_mutex_lock(cimg::X11attr().mutex);
02078       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02079       XFlush(cimg::X11attr().display);
02080       pthread_mutex_unlock(cimg::X11attr().mutex);
02081     }
02082 
02083     template<typename T> 
02084     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02085                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02086                 const bool fullscreen_flag=false,const bool closed_flag=false):
02087       normalization(normalization_type&3),events(events_type&3),
02088       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02089       cimg_test(img,"CImgDisplay::CImgDisplay");
02090       CImg<T> tmp;
02091       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
02092       width  = nimg.width;
02093       height = nimg.height;
02094       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02095       new_lowlevel(title);
02096       display(nimg);
02097     }
02098 
02099     template<typename T> 
02100     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02101                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02102                 const bool fullscreen_flag=false,const bool closed_flag=false):
02103       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
02104       closed(closed_flag),min(0),max(0) {
02105       cimgl_test(list,"CImgDisplay::CImgDisplay");
02106       CImg<T> tmp;
02107       const CImg<T> 
02108         img0 = list.get_append('x'), 
02109         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
02110       width  = img.width; 
02111       height = img.height;
02112       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02113       new_lowlevel(title);
02114       display(img);
02115     }
02116 
02117     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
02118       width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3),
02119       fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) {
02120       new_lowlevel(title);
02121       std::memcpy(data,win.data,(cimg::X11attr().nb_bits>16?sizeof(unsigned int):sizeof(short))*width*height);
02122       pthread_mutex_lock(cimg::X11attr().mutex);
02123       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02124       XFlush(cimg::X11attr().display);
02125       pthread_mutex_unlock(cimg::X11attr().mutex);
02126     }
02127 
02128     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
02129       const unsigned int
02130         dimx=(nwidth>0)?nwidth:(-width*nwidth/100),
02131         dimy=(nheight>0)?nheight:(-height*nheight/100);
02132       if (!dimx || !dimy) return *this;
02133       pthread_mutex_lock(cimg::X11attr().mutex);
02134       if (dimx!=width || dimy!=height) {
02135         if (cimg::X11attr().nb_bits>16) {
02136           unsigned int *ndata = new unsigned int[dimx*dimy];
02137           if (redraw) for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
02138             ndata[x+y*dimx] = ((unsigned int*)data)[x*width/dimx + width*(y*height/dimy)];
02139           else std::memset(ndata,0,sizeof(unsigned int)*dimx*dimy);
02140           data = (void*)ndata;
02141         } else {
02142           unsigned short *ndata = new unsigned short[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 short*)data)[x*width/dimx + width*(y*height/dimy)];
02145           else std::memset(ndata,0,sizeof(unsigned short)*dimx*dimy);
02146           data = (void*)ndata;
02147         }
02148         XDestroyImage(image);
02149         image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02150                              cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,dimx,dimy,8,0);
02151       }
02152       width  = dimx;
02153       height = dimy;
02154       if (force && (window_width!=width || window_height!=height)) {
02155         XResizeWindow(cimg::X11attr().display,window,width,height);
02156         window_width = width;
02157         window_height = height;
02158       }
02159       XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02160       XFlush(cimg::X11attr().display);
02161       resized = false;
02162       pthread_mutex_unlock(cimg::X11attr().mutex);
02163       return *this;
02164     }
02165   
02166     CImgDisplay& move(const int posx,const int posy) {
02167       pthread_mutex_lock(cimg::X11attr().mutex);
02168       window_x = posx;
02169       window_y = posy;
02170       XMoveWindow(cimg::X11attr().display,window,posx,posy);
02171       XFlush(cimg::X11attr().display);
02172       moved = false;
02173       pthread_mutex_unlock(cimg::X11attr().mutex);
02174       return *this;
02175     }
02176     
02177     ~CImgDisplay() {
02178       unsigned int i;
02179       pthread_mutex_lock(cimg::X11attr().mutex);
02180       for (i=0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; i++) i++;
02181       for (; i<cimg::X11attr().nb_wins-1; i++) cimg::X11attr().wins[i]=cimg::X11attr().wins[i+1];
02182       cimg::X11attr().nb_wins--;
02183       XDestroyWindow(cimg::X11attr().display,window);
02184       XDestroyImage(image);
02185       if (!cimg::X11attr().nb_wins) {
02186         pthread_cancel(*cimg::X11attr().event_thread);
02187         pthread_join(*cimg::X11attr().event_thread,NULL);
02188         XCloseDisplay(cimg::X11attr().display);
02189         cimg::X11attr().display=NULL;
02190         pthread_mutex_unlock(cimg::X11attr().mutex);
02191         pthread_mutex_destroy(cimg::X11attr().mutex);
02192         delete cimg::X11attr().event_thread;
02193         delete cimg::X11attr().mutex;
02194         delete cimg::X11attr().gc;
02195       } else pthread_mutex_unlock(cimg::X11attr().mutex);
02196     }
02197   
02198     void new_lowlevel(const char *title=NULL) {
02199       cimg::warn(fullscreen,"CImgDisplay::new_lowlevel() : Fullscreen mode requested, "
02200                  "but not supported on X11 Displays");
02201       if (!cimg::X11attr().display) { // Open X11 Display if not already done.
02202         cimg::X11attr().nb_wins = 0;
02203         cimg::X11attr().thread_finished = false;
02204         cimg::X11attr().mutex = new pthread_mutex_t;
02205         pthread_mutex_init(cimg::X11attr().mutex,NULL);
02206         pthread_mutex_lock(cimg::X11attr().mutex);
02207         cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02208         if (!cimg::X11attr().display) throw CImgDisplayException("CImgDisplay::new_lowlevel() : Can't open X11 display");
02209         cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
02210         if (cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24)
02211           throw CImgDisplayException("CImgDisplay::new_lowlevel() : %u bits mode is not supported "
02212                                      "(only 16 and 24 bits are supported)",cimg::X11attr().nb_bits);
02213         cimg::X11attr().gc = new GC;
02214         *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02215         Visual *visual = DefaultVisual(cimg::X11attr().display,0);
02216         XVisualInfo vtemplate;
02217         vtemplate.visualid = XVisualIDFromVisual(visual);
02218         int nb_visuals;
02219         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
02220         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().endian = true;
02221         cimg::X11attr().event_thread = new pthread_t;
02222         pthread_create(cimg::X11attr().event_thread,NULL,thread_lowlevel,NULL);
02223       } else pthread_mutex_lock(cimg::X11attr().mutex);
02224       
02225       // Create display window and image data.
02226       window = XCreateSimpleWindow(cimg::X11attr().display,RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02227                                      0,0,width,height,2,0,0x0L);
02228       if (cimg::X11attr().nb_bits>16) data = new unsigned int[width*height]; else data = new unsigned short[width*height];
02229       image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
02230                              cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);      
02231       XStoreName(cimg::X11attr().display,window,title?title:"");
02232       if (!closed) {
02233         XEvent event;
02234         XSelectInput(cimg::X11attr().display,window,StructureNotifyMask);
02235         XMapWindow(cimg::X11attr().display,window);
02236         do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event); while (event.type!=MapNotify);
02237         XWindowAttributes attr;
02238         XGetWindowAttributes(cimg::X11attr().display,window,&attr);
02239         window_x = attr.x;
02240         window_y = attr.y;
02241       } else window_x = window_y = 0;
02242       if (events) { 
02243         Atom atom = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False); 
02244         XSetWMProtocols(cimg::X11attr().display, window, &atom, 1); 
02245       }
02246       window_width = width;
02247       window_height = height;
02248       mouse_x = mouse_y = -1;
02249       button = key = 0;
02250       resized = moved = false;
02251       cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
02252       pthread_mutex_unlock(cimg::X11attr().mutex);
02253     }
02254   
02255     void proc_lowlevel(XEvent *pevent) {
02256       const unsigned int buttoncode[3] = { 1,4,2 };
02257       XEvent event=*pevent;
02258       switch (event.type) {
02259       case ClientMessage:
02260         XUnmapWindow(cimg::X11attr().display,window);
02261         mouse_x=mouse_y=-1; 
02262         button=key=0;
02263         closed=true; 
02264         break;
02265      case ConfigureNotify: {
02266         while (::XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event));
02267         const unsigned int
02268           nw = event.xconfigure.width,
02269           nh = event.xconfigure.height;
02270         const int
02271           nx = event.xconfigure.x,
02272           ny = event.xconfigure.y;
02273         if (nw && nh && (nw!=window_width || nh!=window_height)) { 
02274           window_width = nw; 
02275           window_height = nh; 
02276           mouse_x = mouse_y = -1;
02277           XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
02278           resized = true;
02279         }
02280         if (nx!=window_x || ny!=window_y) {
02281           window_x = nx;
02282           window_y = ny;
02283           moved = true;
02284         }
02285       } break;
02286       case Expose:
02287         while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event));
02288         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02289         break;
02290       case ButtonPress:
02291         while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
02292         button |= buttoncode[event.xbutton.button-1];
02293         break;
02294       case ButtonRelease:
02295         while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
02296         button &= ~buttoncode[event.xbutton.button-1];
02297         break;
02298       case KeyPress: {
02299         while (XCheckWindowEvent(cimg::X11attr().display,window,KeyPressMask,&event));
02300         char tmp;
02301         KeySym ksym;
02302         XLookupString(&event.xkey,&tmp,1,&ksym,NULL);
02303         key = (unsigned int)ksym;
02304       }
02305         break;
02306       case KeyRelease:
02307         while (XCheckWindowEvent(cimg::X11attr().display,window,KeyReleaseMask,&event));
02308         key = 0;
02309         break;
02310       case LeaveNotify:
02311         while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event));
02312         mouse_x = mouse_y =-1; 
02313         break;
02314       case MotionNotify:
02315         while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event));
02316         mouse_x = event.xmotion.x; 
02317         mouse_y = event.xmotion.y;
02318         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x=mouse_y=-1; 
02319         break;
02320       }
02321     }
02322   
02323     static void* thread_lowlevel(void *arg) {
02324       XEvent event;
02325       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
02326       for (;;) {
02327         pthread_mutex_lock(cimg::X11attr().mutex);
02328         for (unsigned int i=0; i<cimg::X11attr().nb_wins; i++) {
02329           const unsigned int xevent_type = (cimg::X11attr().wins[i]->events)&3;
02330           const unsigned int emask =
02331             ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
02332             ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
02333             ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
02334           XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask);
02335         }
02336         bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
02337         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
02338                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
02339                                                       KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
02340                                                       KeyReleaseMask,&event);
02341         if (event_flag) {
02342           for (unsigned int i=0; i<cimg::X11attr().nb_wins; i++)
02343             if (!cimg::X11attr().wins[i]->closed && event.xany.window==cimg::X11attr().wins[i]->window)
02344               cimg::X11attr().wins[i]->proc_lowlevel(&event);
02345           cimg::X11attr().thread_finished = true;
02346         }
02347         pthread_mutex_unlock(cimg::X11attr().mutex);
02348         cimg::wait(25);
02349       }
02350       return NULL;
02351     }
02352 
02353     template<typename T> XImage* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
02354       cimg_test(img,"CImgDisplay::render");
02355       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),0,~0);
02356       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),0,~0);
02357       const bool by = (ymin<=ymax);
02358       const unsigned int 
02359         nymin = (by?ymin:ymax),
02360         nymax = (by?(ymax<height?ymax:height-1):(ymin<height?ymin:height-1)),
02361         xymax = (nymax+1)*width;
02362       const T 
02363         *data1 = img.ptr(0,nymin,0,0),
02364         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
02365         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
02366       if (cimg::X11attr().endian) cimg::swap(data1,data3);
02367       pthread_mutex_lock(cimg::X11attr().mutex);
02368       if (!normalization) {
02369         switch (cimg::X11attr().nb_bits) {
02370         case 16: {
02371           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02372             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
02373             XPutPixel(image,xy,0,((R>>3)<<11) | ((G>>2)<<5) | (B>>3));
02374           }
02375         } break;
02376         case 24: {
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<<16) | (G<<8) | B);
02380           }
02381         } break;
02382         };
02383       } else {
02384         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
02385         const T nmin = (T)min, delta = (T)max-nmin, mm=delta?delta:(T)1;
02386         switch (cimg::X11attr().nb_bits) {
02387         case 16: {
02388           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02389             const unsigned char
02390               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02391               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02392               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02393             XPutPixel(image,xy,0,((R>>3)<<11) | ((G>>2)<<5) | (B>>3));
02394           }
02395         } break;
02396         case 24: {
02397           for (unsigned int xy=nymin*width; xy<xymax; xy++) {
02398             const unsigned char
02399               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02400               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02401               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02402             XPutPixel(image,xy,0,(R<<16) | (G<<8) | B);
02403           } 
02404         } break;
02405         } 
02406       }
02407       pthread_mutex_unlock(cimg::X11attr().mutex);
02408       return image;
02409     }
02410     
02411     template<typename T> CImgDisplay& display(const CImg<T>& pimg,const unsigned int pymin=0,const unsigned int pymax=~0) {
02412       const unsigned int
02413         ymin = pymin<pymax?pymin:pymax,
02414         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
02415       render(pimg,ymin,ymax);
02416       if (!closed) {      
02417         pthread_mutex_lock(cimg::X11attr().mutex);
02418         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,ymin,0,ymin,width,ymax-ymin+1);
02419         XFlush(cimg::X11attr().display);
02420         pthread_mutex_unlock(cimg::X11attr().mutex);
02421       }
02422       return *this;
02423     }
02424   
02425     CImgDisplay& wait() {
02426       if (!closed && events) {
02427         XEvent event;
02428         do {
02429           pthread_mutex_lock(cimg::X11attr().mutex);
02430           const unsigned int 
02431             emask = ExposureMask|StructureNotifyMask|
02432             ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
02433             ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0);
02434           XSelectInput(cimg::X11attr().display,window,emask);
02435           XPeekEvent(cimg::X11attr().display,&event);
02436           cimg::X11attr().thread_finished = false;
02437           pthread_mutex_unlock(cimg::X11attr().mutex);
02438         } while (event.xany.window!=window);
02439         while (!cimg::X11attr().thread_finished) cimg::wait(25);
02440       }
02441       return *this;
02442     }
02443 
02444     CImgDisplay& show() {
02445       if (closed) {
02446         pthread_mutex_lock(cimg::X11attr().mutex);
02447         XEvent event;
02448         XSelectInput(cimg::X11attr().display,window,StructureNotifyMask);
02449         XMapWindow(cimg::X11attr().display,window);
02450         do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event);
02451         while (event.type!=MapNotify);
02452         XWindowAttributes attr;
02453         XGetWindowAttributes(cimg::X11attr().display,window,&attr);
02454         window_x = attr.x;
02455         window_y = attr.y;
02456         XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
02457         XFlush(cimg::X11attr().display);
02458         closed = false;
02459         pthread_mutex_unlock(cimg::X11attr().mutex);
02460       }
02461       return *this;
02462     }
02463     CImgDisplay& close() {
02464       if (!closed) {
02465         pthread_mutex_lock(cimg::X11attr().mutex);
02466         XUnmapWindow(cimg::X11attr().display,window);
02467         XFlush(cimg::X11attr().display);
02468         closed = true;
02469         window_x = window_y = 0;        
02470         pthread_mutex_unlock(cimg::X11attr().mutex);
02471       }
02472       return *this;
02473     }
02474 
02475     static const int screen_dimx() { 
02476       int res = 0;
02477       if (!cimg::X11attr().display) {
02478         Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02479         if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display");
02480         res = DisplayWidth(disp,DefaultScreen(disp));
02481         XCloseDisplay(disp);
02482       } else res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02483       return res;
02484     }
02485 
02486     static const int screen_dimy() { 
02487       int res = 0;
02488       if (!cimg::X11attr().display) {
02489         Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
02490         if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display");
02491         res = DisplayHeight(disp,DefaultScreen(disp));
02492         XCloseDisplay(disp);
02493       } else res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
02494       return res;
02495     }
02496 
02497     // Windows-based display
02498     //-----------------------
02499 #elif cimg_display_type==2
02500     CLIENTCREATESTRUCT ccs;
02501     BITMAPINFO bmi;
02502     unsigned int *data;
02503     DEVMODE curr_mode;
02504     HWND window;
02505     HDC hdc;
02506     HANDLE thread;
02507     HANDLE wait_disp;
02508     HANDLE created;
02509     HANDLE mutex;
02510 
02511     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
02512                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02513                 const bool fullscreen_flag=false,const bool closed_flag=false):
02514       width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3),
02515       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02516       if (!dimw || !dimh) throw CImgArgumentException("CImgDisplay::CImgDisplay() : null size specified. ");
02517       new_lowlevel(title);
02518       std::memset(data,0,sizeof(unsigned int)*width*height);
02519       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02520     }
02521 
02522     template<typename T> 
02523     CImgDisplay(const CImg<T>& img,const char *title=NULL,
02524                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02525                 const bool fullscreen_flag=false,const bool closed_flag=false):
02526       normalization(normalization_type&3),events(events_type&3),
02527       fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) {
02528       cimg_test(img,"CImgDisplay::CImgDisplay");
02529       CImg<T> tmp;
02530       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
02531       width  = nimg.width;
02532       height = nimg.height;
02533       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02534       new_lowlevel(title);
02535       display(nimg);
02536     }
02537 
02538     template<typename T>
02539     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
02540                 const unsigned int normalization_type=1,const unsigned int events_type=3,
02541                 const bool fullscreen_flag=false,const bool closed_flag=false):
02542       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
02543       closed(closed_flag),min(0),max(0) {
02544       cimgl_test(list,"CImgDisplay::CImgDisplay");
02545       CImg<T> tmp;
02546       const CImg<T>
02547         img0 = list.get_append('x'),
02548         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
02549       width  = img.width;
02550       height = img.height;
02551       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
02552       new_lowlevel(title);
02553       display(img);
02554     }
02555 
02556     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
02557       width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3),
02558       fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) {
02559       new_lowlevel(title);
02560       std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
02561       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02562     }
02563 
02564     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
02565       const unsigned int
02566         dimx=(nwidth>0)?nwidth:(-nwidth*width/100),
02567         dimy=(nheight>0)?nheight:(-nheight*height/100);
02568       if (!dimx || !dimy) return *this;
02569       if (dimx!=width || dimy!=height) {
02570         unsigned int *ndata = new unsigned int[dimx*dimy];
02571         if (redraw) 
02572           for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
02573             ndata[x+y*dimx] = data[x*width/dimx + width*(y*height/dimy)];
02574         else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
02575         delete[] data;
02576         data = ndata;
02577         bmi.bmiHeader.biWidth=dimx;
02578         bmi.bmiHeader.biHeight=-(int)dimy;
02579       }
02580       width  = dimx;
02581       height = dimy;
02582       if (force && (window_width!=width || window_height!=height)) {
02583         RECT rect; rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02584         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02585         const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
02586         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
02587         window_width  = width;
02588         window_height = height;
02589       }
02590       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02591       resized = false;
02592       return *this;
02593     }
02594     
02595     CImgDisplay& move(const int posx,const int posy) {
02596       RECT rect; rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02597       AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02598       const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
02599       window_x = posx;
02600       window_y = posy;
02601       SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
02602       moved = false;
02603       return *this;
02604     }
02605 
02606     ~CImgDisplay() {
02607       DestroyWindow(window);
02608       if (events) TerminateThread(thread,0);
02609       delete[] data;
02610       if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
02611     }
02612   
02613     void new_lowlevel(const char *title=NULL) {
02614       unsigned long ThreadID;
02615       DEVMODE mode;
02616       unsigned int imode=0,ibest=0,bestbpp=0;
02617       void *arg = (void*)(new void*[2]);
02618       ((void**)arg)[0]=(void*)this;
02619       ((void**)arg)[1]=(void*)title;
02620       if (fullscreen) {
02621         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(NULL,imode,&mode); imode++)
02622           if (mode.dmPelsWidth==width && mode.dmPelsHeight==height && mode.dmBitsPerPel>bestbpp) {
02623             bestbpp = mode.dmBitsPerPel;
02624             ibest=imode; 
02625           }
02626         cimg::warn(!bestbpp,"CImgDisplay::new_lowlevel() : Could not initialize fullscreen mode %ux%u\n",width,height);
02627         if (bestbpp) {
02628           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
02629           EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&curr_mode);
02630           EnumDisplaySettings(NULL,ibest,&mode);
02631           ChangeDisplaySettings(&mode,0);
02632         }
02633         else curr_mode.dmSize = 0;
02634       }
02635       else curr_mode.dmSize = 0;
02636       if (events) {
02637         mutex     = CreateMutex(NULL,FALSE,NULL);
02638         created   = CreateEvent(NULL,FALSE,FALSE,NULL);
02639         wait_disp = CreateEvent(NULL,FALSE,FALSE,NULL);
02640         thread    = CreateThread(NULL,0,thread_lowlevel,arg,0,&ThreadID);
02641         WaitForSingleObject(created,INFINITE);
02642       } else thread_lowlevel(arg);
02643     }
02644   
02645     static LRESULT APIENTRY proc_lowlevel(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
02646       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
02647       MSG st_msg;
02648 
02649       switch(msg) {
02650       case WM_CLOSE:
02651         disp->mouse_x=disp->mouse_y=-1;
02652         disp->key=disp->button=disp->window_x=disp->window_y=0;
02653         disp->closed=true;
02654         ReleaseMutex(disp->mutex);
02655         ShowWindow(disp->window,SW_HIDE);
02656         return 0;
02657       case WM_SIZE: {
02658         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
02659         WaitForSingleObject(disp->mutex,INFINITE);
02660         const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
02661         if (nw && nh && (nw!=disp->width || nh!=disp->height)) { 
02662           disp->window_width  = nw; 
02663           disp->window_height = nh;
02664           disp->mouse_x = disp->mouse_y = -1;
02665           disp->resized = true;
02666         }
02667         ReleaseMutex(disp->mutex);
02668       } break;
02669       case WM_MOVE: {
02670         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
02671         WaitForSingleObject(disp->mutex,INFINITE);
02672         const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
02673         if (nx!=disp->window_x || ny!=disp->window_y) {
02674           disp->window_x = nx;
02675           disp->window_y = ny;
02676           disp->moved = true;
02677         }
02678         ReleaseMutex(disp->mutex);
02679       } break;
02680       case WM_PAINT:
02681         WaitForSingleObject(disp->mutex,INFINITE);
02682         SetDIBitsToDevice(disp->hdc,0,0,disp->width,disp->height,0,0,0,disp->height,disp->data,&(disp->bmi),DIB_RGB_COLORS);
02683         ReleaseMutex(disp->mutex);
02684         break;
02685       }
02686       if (disp->events>=2) switch(msg) {
02687       case WM_KEYDOWN:
02688         while (PeekMessage(&st_msg,window,WM_KEYDOWN,WM_KEYDOWN,PM_REMOVE)); 
02689         disp->key=(int)wParam;
02690         break;
02691       case WM_MOUSEMOVE: {
02692         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE));
02693         disp->mouse_x = LOWORD(lParam);
02694         disp->mouse_y = HIWORD(lParam);
02695         if (disp->mouse_x<0 || disp->mouse_y<0 ||       disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
02696           disp->mouse_x=disp->mouse_y=-1;
02697       }
02698         break;
02699       case WM_LBUTTONDOWN: 
02700         while (PeekMessage(&st_msg,window,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE));
02701         disp->button |= 1; 
02702         break;
02703       case WM_RBUTTONDOWN: 
02704         while (PeekMessage(&st_msg,window,WM_RBUTTONDOWN,WM_RBUTTONDOWN,PM_REMOVE));
02705         disp->button |= 2; 
02706         break;
02707       case WM_MBUTTONDOWN: 
02708         while (PeekMessage(&st_msg,window,WM_MBUTTONDOWN,WM_MBUTTONDOWN,PM_REMOVE));
02709         disp->button |= 4; 
02710         break;
02711       }
02712       if (disp->events>=3) switch(msg) {
02713       case WM_KEYUP:
02714         while (PeekMessage(&st_msg,window,WM_KEYUP,WM_KEYUP,PM_REMOVE));
02715         disp->key=0;
02716         break;
02717       case WM_LBUTTONUP:
02718         while (PeekMessage(&st_msg,window,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE));
02719         disp->button &= ~1; 
02720         break;
02721       case WM_RBUTTONUP:
02722         while (PeekMessage(&st_msg,window,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE)); 
02723         disp->button &= ~2;
02724         break;
02725       case WM_MBUTTONUP:
02726         while (PeekMessage(&st_msg,window,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE)); 
02727         disp->button &= ~4;
02728         break;
02729       }
02730       return DefWindowProc(window,msg,wParam,lParam);
02731     }
02732   
02733     static DWORD WINAPI thread_lowlevel(void* arg) {
02734       CImgDisplay *disp  = (CImgDisplay*)(((void**)arg)[0]);
02735       const char *title = (const char*)(((void**)arg)[1]);
02736       MSG msg;
02737       delete[] (void**)arg;
02738       disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
02739       disp->bmi.bmiHeader.biWidth=disp->width;
02740       disp->bmi.bmiHeader.biHeight=-(int)disp->height;
02741       disp->bmi.bmiHeader.biPlanes=1;
02742       disp->bmi.bmiHeader.biBitCount=32;
02743       disp->bmi.bmiHeader.biCompression=BI_RGB;
02744       disp->bmi.bmiHeader.biSizeImage=0;
02745       disp->bmi.bmiHeader.biXPelsPerMeter=1;
02746       disp->bmi.bmiHeader.biYPelsPerMeter=1;
02747       disp->bmi.bmiHeader.biClrUsed=0;
02748       disp->bmi.bmiHeader.biClrImportant=0;
02749       disp->data = new unsigned int[disp->width*disp->height];
02750       if (!disp->curr_mode.dmSize) { // Normal window
02751         RECT rect;
02752         rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1;
02753         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02754         const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
02755         disp->window = CreateWindow("MDICLIENT",title?title:"",
02756                                     WS_OVERLAPPEDWINDOW | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
02757                                     disp->width + 2*border1, disp->height + border1 + border2,
02758                                     NULL,NULL,NULL,&(disp->ccs));
02759         if (!disp->closed) {
02760           GetWindowRect(disp->window,&rect);    
02761           disp->window_x = rect.left + border1;
02762           disp->window_y = rect.top + border2;
02763         } else disp->window_x = disp->window_y = 0;
02764       } else { // Fullscreen window
02765         disp->window = CreateWindow("MDICLIENT",title?title:"",
02766                                     WS_POPUP | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
02767                                     disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs));
02768         disp->window_x = disp->window_y = 0;
02769       }
02770       SetForegroundWindow(disp->window);
02771       disp->hdc = GetDC(disp->window);
02772       disp->window_width = disp->width;
02773       disp->window_height = disp->height;
02774       disp->mouse_x = disp->mouse_y = -1;
02775       disp->button = disp->key = 0;
02776       disp->resized = disp->moved = false;      
02777       if (disp->events) {
02778         SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
02779         SetWindowLong(disp->window,GWL_WNDPROC,(LONG)proc_lowlevel);
02780         SetEvent(disp->created);
02781         while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); SetEvent(disp->wait_disp); }
02782       }
02783       return 0;
02784     }
02785 
02786     template<typename T> BITMAPINFO* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
02787       cimg_test(img,"CImgDisplay::render");
02788       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),
02789                                       (unsigned int)0,~(unsigned int)0);
02790       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),
02791                                                                 (unsigned int)0,~(unsigned int)0);
02792       const bool by=(ymin<=ymax);
02793       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin);
02794       const T 
02795         *data1 = img.ptr(0,nymin,0,0),
02796         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
02797         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
02798       unsigned int *ximg = data + nymin*width;
02799       WaitForSingleObject(mutex,INFINITE);
02800       if (!normalization) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--)
02801         *(ximg++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
02802       else {
02803         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
02804         const T nmin = (T)min, delta = (T)(max-nmin), mm = delta?delta:(T)1;
02805         for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
02806           const unsigned char
02807             R = (unsigned char)(255*(*(data1++)-nmin)/mm),
02808             G = (unsigned char)(255*(*(data2++)-nmin)/mm),
02809             B = (unsigned char)(255*(*(data3++)-nmin)/mm);
02810           *(ximg++) = (R<<16) | (G<<8) | (B);
02811         }
02812       }
02813       ReleaseMutex(mutex);
02814       return &bmi;
02815     }
02816 
02817     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int pymin=0,const unsigned int pymax=~0) {
02818       cimg_test(img,"CImgDisplay::display");
02819       const unsigned int 
02820         ymin = pymin<pymax?pymin:pymax,
02821         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
02822       render(img,ymin,ymax);
02823       if (!closed) {
02824         WaitForSingleObject(mutex,INFINITE);
02825         SetDIBitsToDevice(hdc,0,ymin,width,ymax-ymin+1,0,0,0,ymax-ymin+1,data+ymin*width,&bmi,DIB_RGB_COLORS);
02826         ReleaseMutex(mutex);
02827       }
02828       return *this;
02829     }
02830   
02831     CImgDisplay& wait() {
02832       if (!closed && events) WaitForSingleObject(wait_disp,INFINITE);
02833       return *this;
02834     }
02835 
02836     CImgDisplay& show() {
02837       if (closed) {
02838         ShowWindow(window,SW_SHOW);     
02839         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
02840         RECT rect; 
02841         rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
02842         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
02843         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
02844         GetWindowRect(window,&rect);
02845         window_x = rect.left + border1;
02846         window_y = rect.top + border2;
02847         closed = false;
02848       }
02849       return *this;
02850     }
02851 
02852     CImgDisplay& close() {
02853       if (!closed) {
02854         ShowWindow(window,SW_HIDE);
02855         closed = true;
02856         window_x = window_y = 0;
02857       }
02858       return *this;
02859     }
02860 
02861     static const int screen_dimx() { 
02862       DEVMODE mode;
02863       mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0;
02864       EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode);
02865       return mode.dmPelsWidth;      
02866     }
02867 
02868     static const int screen_dimy() {
02869       DEVMODE mode;
02870       mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0;
02871       EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode);
02872       return mode.dmPelsHeight;      
02873     }
02874 
02875 #endif
02876 
02877 #ifdef cimgdisplay_plugin
02878 #include cimgdisplay_plugin
02879 #endif
02880     
02881   };
02882 
02883   /*-------------------------------------------------------
02884 
02885 
02886 
02887   
02888     Definition of the CImg<T> structure
02889         
02890         
02891         
02892         
02893   ------------------------------------------------------*/
02894 
02896 
02967   template<typename T> struct CImg {
02968     
02970 
02978     unsigned int width;       
02979     
02981 
02989     unsigned int height;
02990     
02992 
03000     unsigned int depth;
03001     
03003 
03011     unsigned int dim;
03012     
03014 
03022     T *data;
03023 
03024     //------------------------------------------
03025     //------------------------------------------
03026     //
03028 
03029     //------------------------------------------
03030     //------------------------------------------
03031   
03033 
03043     explicit CImg(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1):
03044       width(dx),height(dy),depth(dz),dim(dv) {
03045       const unsigned int siz = size();
03046       if (siz) data = new T[siz]; else { data=NULL; width=height=depth=dim=0; }
03047     }
03048 
03051 
03058     explicit CImg(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val):
03059       width(dx),height(dy),depth(dz),dim(dv) {
03060       const unsigned int siz = size();
03061       if (siz) { data = new T[siz]; fill(val); } else { data=NULL; width=height=depth=dim=0; }
03062     }
03063 
03065 
03070     template<typename t> CImg(const CImg<t>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
03071       const unsigned int siz = size();
03072       if (siz) {
03073         data = new T[siz];
03074         const t *ptrs = img.data + siz;
03075         cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs);
03076       } else data = NULL;
03077     }
03078 
03079     CImg(const CImg<T>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
03080       const unsigned siz = size();
03081       if (siz) {
03082         data = new T[width*height*depth*dim];
03083         std::memcpy(data,img.data,siz*sizeof(T));
03084       } else data = NULL;
03085     }
03086 
03087 
03089 
03104     template<typename t> CImg(const CImg<t>& img,const bool pixel_copy):width(0),height(0),depth(0),dim(0),data(NULL) {
03105       if (pixel_copy) CImg<T>(img).swap(*this);
03106       CImg<T>(img.width,img.height,img.depth,img.dim).swap(*this);
03107     }
03108 
03110 
03116     CImg(const char *const filename):width(0),height(0),depth(0),dim(0),data(NULL) { load(filename).swap(*this); }
03117 
03119 
03129     template<typename t> CImg(const t *const data_buffer,
03130                               const unsigned int dx,const unsigned int dy=1,
03131                               const unsigned int dz=1,const unsigned int dv=1,
03132                               const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
03133       const unsigned int siz = size();
03134       if (data_buffer && siz) {
03135         data = new T[siz];
03136         if (multiplexed) {
03137           const t *ptrs = data_buffer;
03138           T *ptrd = data;
03139           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
03140         } else { const t *ptrs = data_buffer+siz; cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)); }
03141       } else { width=height=depth=dim=0; data = NULL; }
03142     }
03143     // Add template overloading if VC>7.1 (optimized version)
03144 #if !defined(_MSC_VER) && _MSC_VER>1300
03145     CImg(const T *const data_buffer,
03146          const unsigned int dx,const unsigned int dy=1,
03147          const unsigned int dz=1,const unsigned int dv=1,
03148          const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
03149       const unsigned int siz = size();
03150       if (data_buffer && siz) {
03151         data = new T[siz];
03152         if (multiplexed) {
03153           const T *ptrs = data_buffer;
03154           T *ptrd = data;
03155           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
03156         } else std::memcpy(data,data_buffer,siz*sizeof(T));
03157       } else { width=height=depth=dim=0; data = NULL; }
03158     }
03159 #endif
03160     
03162 
03165     ~CImg() { if (data) delete[] data; }
03166     
03168 
03174     CImg& empty() { return CImg<T>().swap(*this); }
03175 
03177     //-----------------------------------------------------
03178     //-----------------------------------------------------
03179     //
03181 
03182     //-----------------------------------------------------
03183     //-----------------------------------------------------
03184   
03186 
03192     static const char* pixel_type() { T val; return cimg::get_type(val); }
03193 
03195 
03199     const unsigned int size() const { return width*height*depth*dim; }  
03200 
03202 
03209     const int dimx() const { return (int)width; }  
03210 
03212 
03219     const int dimy() const { return (int)height; }
03220   
03222 
03228     const int dimz() const { return (int)depth; }
03229   
03231 
03237     const int dimv() const { return (int)dim; }
03238   
03240     // with respect to the pixel data pointer \ref data.
03249     const long offset(const int x=0, const int y=0, const int z=0, const int v=0) const { 
03250       return x+width*(y+height*(z+depth*v)); }
03251   
03253 
03262     T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
03263       const long off = offset(x,y,z,v);
03264 #if cimg_debug>1
03265       if (off<0 || off>=size()) {
03266         cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%d) which is"
03267                    "outside the data of the image (%u,%u,%u,%u) (size=%u)",
03268                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
03269         return data;
03270       }
03271 #endif
03272       return data+off;
03273     }
03274 
03276 
03283     T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const {
03284       const int off = offset(x,y,z,v);
03285 #if cimg_debug>1
03286       if (!data || off>=(int)size()) {
03287         cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) "
03288                    "outside the image range (%u,%u,%u,%u) (size=%u)",
03289                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());                     
03290         return *data;
03291       }
03292 #endif
03293       return data[off];
03294     }
03295     
03297 
03301     T& operator[](const unsigned long off) const {
03302 #if cimg_debug>1
03303       if (!data || off>=size()) {
03304         cimg::warn(true,
03305                    "CImg<%s>::operator[] : Trying to get a pixel at offset=%d, outside the range of the image (%u,%u,%u,%u) (size=%u)",
03306                    pixel_type(),off,width,height,depth,dim,size());                     
03307         return *data;
03308       }
03309 #endif
03310       return data[off];
03311     }
03312 
03314 
03321     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 {
03322       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
03323     }
03324 
03326 
03333     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 {
03334       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
03335     }
03337 
03344     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 {
03345       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
03346     }
03347 
03349 
03356     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 {
03357       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
03358     }
03359 
03361 
03367     const T& neumann_pix4d(const int x,const int y=0,const int z=0,const int v=0) const {
03368       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03369                      y<0?0:(y>=dimy()?dimy()-1:y),
03370                      z<0?0:(z>=dimz()?dimz()-1:z),
03371                      v<0?0:(v>=dimv()?dimv()-1:v));
03372     }
03374 
03380     const T& neumann_pix3d(const int x,const int y=0,const int z=0,const int v=0) const {
03381       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03382                      y<0?0:(y>=dimy()?dimy()-1:y),
03383                      z<0?0:(z>=dimz()?dimz()-1:z),v);
03384     }
03385 
03387 
03393     const T& neumann_pix2d(const int x,const int y=0,const int z=0,const int v=0) const {
03394       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
03395                      y<0?0:(y>=dimy()?dimy()-1:y),z,v);
03396     }
03398 
03404     const T& neumann_pix1d(const int x,const int y=0,const int z=0,const int v=0) const {
03405       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
03406     }
03407     
03409 
03415     double linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const {
03416       double valx0,valx1,valy0,valy1,valz0,valz1;
03417       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy),
03418         fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv);
03419       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy,  z = (unsigned int)fz, v = (unsigned int)fv;
03420       const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
03421       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;
03422       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03423       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03424       valy0 = (1-dy)*valx0 + (dy)*valx1;
03425       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
03426       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
03427       valy1 = (1-dy)*valx0 + (dy)*valx1;
03428       valz0 = (1-dz)*valy0 + (dz)*valy1;
03429       valx0 = (1-dx)*(*this)(x,y,z,nv)  + (dx)*(*this)(nx,y,z,nv);
03430       valx1 = (1-dx)*(*this)(x,ny,z,nv) + (dx)*(*this)(nx,ny,z,nv);
03431       valy0 = (1-dy)*valx0 + (dy)*valx1;
03432       valx0 = (1-dx)*(*this)(x,y,nz,nv)  + (dx)*(*this)(nx,y,nz,nv);
03433       valx1 = (1-dx)*(*this)(x,ny,nz,nv) + (dx)*(*this)(nx,ny,nz,nv);
03434       valy1 = (1-dy)*valx0 + (dy)*valx1;
03435       valz1 = (1-dz)*valy0 + (dz)*valy1;
03436       return (1-dv)*valz0 + (dv)*valz1;
03437     }
03438 
03440 
03446     double linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const {
03447       double valx0,valx1,valy0,valy1;
03448       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);
03449       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz;
03450       const float dx = fx-x, dy = fy-y, dz = fz-z;
03451       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z;
03452       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03453       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03454       valy0 = (1-dy)*valx0 + (dy)*valx1;
03455       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
03456       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
03457       valy1 = (1-dy)*valx0 + (dy)*valx1;
03458       return (1-dz)*valy0 + (dz)*valy1;
03459     }
03460 
03462 
03468     double linear_pix2d(const float ffx,const float ffy=0,const int z=0,int v=0) const {
03469       double valx0,valx1;
03470       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy);
03471       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy;
03472       const float dx = fx-x, dy = fy-y;
03473       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y;
03474       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03475       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
03476       return (1-dy)*valx0 + (dy)*valx1;
03477     }
03478 
03480 
03486     double linear_pix1d(const float ffx,const int y=0,const int z=0,int v=0) const {
03487       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx);
03488       const unsigned int x = (unsigned int)fx;
03489       const float dx = fx-x;
03490       const unsigned int nx = dx>0?x+1:x;
03491       return (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
03492     }
03493 
03495 
03501     double cubic_pix2d(const float pfx,const float pfy=0,const int z=0,int v=0) const {
03502       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy);
03503       const unsigned int 
03504         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,
03505         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;
03506       const float dx = fx-x, dy = fy-y;
03507       const T& 
03508         a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v),
03509         e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v),
03510         i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v),
03511         m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v);
03512       const double 
03513         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,
03514         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,
03515         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,
03516         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;
03517       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;
03518     }
03519 
03521 
03527     double cubic_pix1d(const float pfx,const int y=0,const int z=0,int v=0) const {
03528       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx);
03529       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;
03530       const float dx = fx-x;
03531       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);
03532       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;
03533     }
03534     
03536 
03542     const CImg& print(const char *title=NULL,const unsigned int print_flag=1) const {
03543       std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p",
03544                    title?title:"CImg",(void*)this,
03545                    width,height,depth,dim,pixel_type(),(void*)data);
03546       if (size()==0 || !data) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; }
03547       if (print_flag>=1) { 
03548         CImgStats st(*this);
03549         std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)",
03550                      st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax); 
03551       }     
03552       if (print_flag>=2 || size()<=16) {
03553         std::fprintf(stderr," }\n%s = [ ",title?title:"data");
03554         cimg_mapXYZV(*this,x,y,z,k) 
03555           std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k),
03556                        ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]\n":(((x+1)%width==0)?" ; ":" ")));
03557       } else std::fprintf(stderr," }\n");
03558       return *this;
03559     }
03560 
03562 
03567     const CImg& print(const unsigned int print_flag) const { return print(NULL,print_flag); }
03568   
03570     //--------------------------------------------------
03571     //--------------------------------------------------
03572     //
03574 
03575     //--------------------------------------------------
03576     //--------------------------------------------------
03577   
03579 
03583     template<typename t> CImg<T>& operator=(const CImg<t>& img) { 
03584       const unsigned int sizes = img.size(), sized = size();
03585       if (sizes!=sized) return CImg<T>(img).swap(*this); 
03586       const t* ptrs = img.data + sized;
03587       for (T *ptrd = data+sized; ptrd>data; ) *(--ptrd) = (T)*(--ptrs);
03588       width = img.width; height = img.height; depth = img.depth; dim = img.dim;
03589       return *this;
03590     }
03591     
03592     CImg& operator=(const CImg& img) {
03593       if (&img==this) return *this;
03594       const unsigned int sizes = img.size(), sized = size();
03595       if (sizes!=sized) return CImg<T>(img).swap(*this); 
03596       std::memcpy(data,img.data,sizeof(T)*sized);
03597       width = img.width; height = img.height; depth = img.depth; dim = img.dim;
03598       return *this;
03599     }
03600       
03602 
03605     CImg& operator=(const T& val) { return fill(val); }
03606 
03608 
03611     CImg& operator=(const T *buf) {
03612       if (buf) std::memcpy(data,buf,size()*sizeof(T));
03613       else throw CImgArgumentException("CImg<T>::operator=() : Given array pointer 'ptr' is NULL");
03614       return *this; 
03615     }
03616        
03618 
03621     CImg& operator+=(const T& val) { cimg_map(*this,ptr,T) (*ptr)+=val; return *this; }
03622 
03624     CImg& operator++() { return (*this)+=1; }
03625 
03627 
03630     CImg& operator-=(const T& val) { cimg_map(*this,ptr,T) (*ptr)-=val; return *this; }
03631 
03633     CImg& operator--() { return (*this)-=1; }
03634 
03636 
03639     CImg& operator%=(const T& val) { cimg_map(*this,ptr,T) (*ptr)%=val; return *this; }
03640 
03642 
03645     CImg& operator&=(const T& val) { cimg_map(*this,ptr,T) (*ptr)&=val; return *this; }
03646 
03648     CImg& operator|=(const T& val) { cimg_map(*this,ptr,T) (*ptr)|=val; return *this; }
03649 
03651     CImg& operator^=(const T& val) { cimg_map(*this,ptr,T) (*ptr)^=val; return *this; }
03652 
03654     CImg operator+(const T& val) const { return CImg<T>(*this)+=val; }
03655 
03657     CImg operator-(const T& val) const { return CImg<T>(*this)-=val; }
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 {
03673       CImg<T> res(*this,false);
03674       const T *ptrs = ptr() + size();
03675       cimg_map(res,ptrd,T) *ptrd=!(*(--ptrs));
03676       return res;
03677     }
03678 
03680     CImg operator~() const {
03681       CImg<T> res(*this,false);
03682       const T *ptrs = ptr() + size();
03683       cimg_map(res,ptrd,T) *ptrd=~(*(--ptrs));
03684       return res;
03685     }
03686     
03688     template<typename t> CImg& operator+=(const CImg<t>& img) {
03689       const unsigned int smin = cimg::min(size(),img.size());
03690       t *ptrs = img.data+smin;
03691       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs))));
03692       return *this;
03693     }
03695     template<typename t> CImg& operator-=(const CImg<t>& img) {
03696       const unsigned int smin = cimg::min(size(),img.size());
03697       t *ptrs = img.data+smin;
03698       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs))));
03699       return *this;
03700     }
03702     CImg& operator%=(const CImg& img) {
03703       const unsigned int smin = cimg::min(size(),img.size());
03704       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--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     }
03725 
03727     template<typename t> CImg operator+(const CImg<t>& img)  const { return CImg<T>(*this)+=img; }
03728 
03730     template<typename t> CImg operator-(const CImg<t>& img)  const { return CImg<T>(*this)-=img; }
03731 
03733     CImg operator%(const CImg& img) const { return CImg<T>(*this)%=img; }
03734 
03736     CImg operator&(const CImg& 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 double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)*val); return *this; }
03746 
03748     CImg& operator/=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)/val); return *this; }
03749 
03751     CImg operator*(const double val) const { return CImg<T>(*this)*=val; }
03752 
03754     CImg operator/(const double val) const { return CImg<T>(*this)/=val; }
03755 
03757     friend CImg operator+(const T& val, const CImg& img) { return CImg<T>(img)+=val; }
03758 
03760     friend CImg operator*(const double val,const CImg &img) { return CImg<T>(img)*=val; }
03761 
03763     friend CImg operator-(const T& val, const CImg& img) { return CImg<T>(img.width,img.height,img.depth,img.dim,val)-=img; }
03764 
03766     template<typename t> const bool operator==(const CImg<t>& img) const {
03767       const unsigned int siz = size();
03768       bool vequal = true;
03769       if (siz!=img.size()) return false;
03770       t *ptrs=img.data+siz;
03771       for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs))));
03772       return vequal;
03773     }
03775     template<typename t> const bool operator!=(const CImg<t>& img) const { return !((*this)==img); }
03776 
03778     //--------------------------------------------------
03779     //--------------------------------------------------
03780     //
03782 
03783     //--------------------------------------------------
03784     //--------------------------------------------------
03785      
03787 
03791     template<typename t> CImg& mul(const CImg<t>& img) {
03792       t *ptrs = img.data;
03793       T *ptrf = data + cimg::min(size(),img.size());
03794       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd*(*(ptrs++)));
03795       return *this;
03796     }
03797 
03799 
03805     template<typename t> CImg get_mul(const CImg<t>& img) const { return CImg<T>(*this).mul(img); }
03806   
03808 
03812     template<typename t> CImg& div(const CImg<t>& img) {
03813       t *ptrs = img.data;
03814       T *ptrf = data + cimg::min(size(),img.size());
03815       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd/(*(ptrs++)));
03816       return *this;
03817     }
03818 
03820 
03826     template<typename t> CImg get_div(const CImg<t>& img) const { return CImg<T>(*this).div(img); }
03827   
03829 
03833     template<typename t> CImg& max(const CImg<t>& img) {
03834       t *ptrs = img.data;
03835       T *ptrf = data + cimg::min(size(),img.size());
03836       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::max((T)(*(ptrs++)),*ptrd);
03837       return *this;
03838     }
03840 
03844     template<typename t> CImg get_max(const CImg<t>& img) const { return CImg<T>(*this).max(img); }
03845   
03847 
03851     template<typename t> CImg& min(const CImg<t>& img) {
03852       t *ptrs = img.data;
03853       T *ptrf = data + cimg::min(size(),img.size());
03854       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::min((T)(*(ptrs++)),*ptrd);
03855       return *this;
03856     }
03858 
03862     template<typename t> CImg get_min(const CImg<t>& img) const { return CImg<T>(*this).min(img); }
03863 
03865 
03868     CImg& sqrt() {
03869       cimg_map(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr));
03870       return *this;
03871     }
03872 
03874 
03877     CImg get_sqrt() const { return CImg<T>(*this).sqrt(); }
03878   
03880 
03883     CImg& log() {
03884       cimg_map(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr));
03885       return *this;
03886     }
03887 
03889 
03892     CImg get_log() const { return CImg<T>(*this).log(); }
03893 
03895 
03898     CImg& log10() {
03899       cimg_map(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr));
03900       return *this;
03901     }
03902 
03904 
03907     CImg get_log10() const { return CImg<T>(*this).log10(); }
03908 
03910 
03914     CImg& pow(const double p) {
03915       if (p==0) return fill(1);
03916       if (p==1) return *this;
03917       if (p==2) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val; } return *this; }
03918       if (p==3) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val; } return *this; }
03919       if (p==4) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val*val; } return *this; }
03920       cimg_map(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p);
03921       return *this;
03922     }
03923 
03925 
03929     CImg get_pow(const double p) const { return CImg<T>(*this).pow(p); }
03930   
03932 
03935     CImg& abs() {
03936       cimg_map(*this,ptr,T) (*ptr)=cimg::abs(*ptr);
03937       return *this;
03938     }
03939 
03941 
03944     CImg get_abs() const { return CImg<T>(*this).abs(); }
03945   
03947 
03950     CImg& cos() {
03951       cimg_map(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr));
03952       return *this;
03953     }
03954 
03956 
03959     CImg get_cos() const { return CImg<T>(*this).cos(); }
03960  
03962 
03965     CImg& sin() {
03966       cimg_map(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr));
03967       return *this;
03968     }
03969 
03971 
03974     CImg get_sin() const { return CImg<T>(*this).sin(); }
03975   
03977 
03980     CImg& tan() {
03981       cimg_map(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr));
03982       return *this;
03983     }
03984 
03986 
03989     CImg get_tan() const { return CImg<T>(*this).tan(); }
03990   
03991 
03993     //------------------------------------------
03994     //------------------------------------------
03995     //
03997 
03998     //------------------------------------------
03999     //------------------------------------------
04000     
04002 
04007     CImg& fill(const T& val) {
04008       cimg_test(*this,"CImg<T>::fill");      
04009       if (val!=0 && sizeof(T)!=1) cimg_map(*this,ptr,T) *ptr=val; 
04010       else std::memset(data,(int)val,size()*sizeof(T));
04011       return *this;
04012     }
04013 
04015 
04019     CImg& fill(const T& val0,const T& val1) {
04020       cimg_test(*this,"CImg<T>::fill");
04021       T *ptr, *ptr_end = data+size();
04022       for (ptr=data; ptr<ptr_end-1; ) { *(ptr++)=val0; *(ptr++)=val1; }
04023       if (ptr!=ptr_end) *(ptr++)=val0;
04024       return *this;
04025     }
04026     
04028 
04033     CImg& fill(const T& val0,const T& val1,const T& val2) {
04034       cimg_test(*this,"CImg<T>::fill");
04035       T *ptr, *ptr_end = data+size();
04036       for (ptr=data; ptr<ptr_end-2; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; }     
04037       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1;
04038       return *this;
04039     }
04040     
04042 
04048     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3) {
04049       cimg_test(*this,"CImg<T>::fill");
04050       T *ptr, *ptr_end = data+size();
04051       for (ptr=data; ptr<ptr_end-3; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; }
04052       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04053       return *this;
04054     }
04055 
04057 
04064     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4) {
04065       cimg_test(*this,"CImg<T>::fill");
04066       T *ptr, *ptr_end = data+size();
04067       for (ptr=data; ptr<ptr_end-4; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; }
04068       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04069       if (ptr!=ptr_end) *(ptr++)=val3;
04070       return *this;
04071     }
04072     
04074 
04082     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5) {
04083       cimg_test(*this,"CImg<T>::fill");
04084       T *ptr, *ptr_end = data+size(); 
04085       for (ptr=data; ptr<ptr_end-5; ) {
04086         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04087       }
04088       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04089       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4;
04090       return *this;
04091     }
04092 
04094 
04103     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04104                const T& val4,const T& val5,const T& val6) {
04105       cimg_test(*this,"CImg<T>::fill");
04106       T *ptr, *ptr_end = data+size(); 
04107       for (ptr=data; ptr<ptr_end-6; ) {
04108         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6;
04109       }
04110       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04111       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04112       return *this;
04113     }
04114 
04116 
04126     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04127                const T& val4,const T& val5,const T& val6,const T& val7) {
04128       cimg_test(*this,"CImg<T>::fill");
04129       T *ptr, *ptr_end = data+size();
04130       for (ptr=data; ptr<ptr_end-7; ) {
04131         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3;
04132         *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7;
04133       }
04134       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04135       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04136       if (ptr!=ptr_end) *(ptr++)=val6;
04137       return *this;
04138     }
04139 
04141 
04152     CImg& fill(const T& val0,const T& val1,const T& val2,
04153                const T& val3,const T& val4,const T& val5,
04154                const T& val6,const T& val7,const T& val8) {
04155       cimg_test(*this,"CImg<T>::fill");
04156       T *ptr, *ptr_end = data+size();
04157       for (ptr=data; ptr<ptr_end-8; ) {
04158         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; 
04159         *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04160         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8;
04161       }
04162       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04163       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04164       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7;
04165       return *this;
04166     }
04167 
04169 
04181     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,
04182                const T& val5,const T& val6,const T& val7,const T& val8,const T& val9) {
04183       cimg_test(*this,"CImg<T>::fill");
04184       T *ptr, *ptr_end = data+size();
04185       for (ptr=data; ptr<ptr_end-9; ) {
04186         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4;
04187         *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9;
04188       }
04189       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04190       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04191       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04192       return *this;
04193     }
04194 
04196 
04210     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04211                const T& val4,const T& val5,const T& val6,const T& val7,
04212                const T& val8,const T& val9,const T& val10,const T& val11) {
04213       cimg_test(*this,"CImg<T>::fill");
04214       T *ptr, *ptr_end = data+size();
04215       for (ptr=data; ptr<ptr_end-11; ) {
04216         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04217         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
04218       }
04219       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04220       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04221       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04222       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10;
04223       return *this;
04224     }
04226 
04244     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
04245                const T& val4,const T& val5,const T& val6,const T& val7,
04246                const T& val8,const T& val9,const T& val10,const T& val11,
04247                const T& val12,const T& val13,const T& val14,const T& val15) {
04248       cimg_test(*this,"CImg<T>::fill");
04249       T *ptr, *ptr_end = data+size();
04250       for (ptr=data; ptr<ptr_end-15; ) {
04251         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; 
04252         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
04253         *(ptr++)=val12; *(ptr++)=val13; *(ptr++)=val14; *(ptr++)=val15;
04254       }
04255       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
04256       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
04257       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
04258       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10; if (ptr!=ptr_end) *(ptr++)=val11;
04259       if (ptr!=ptr_end) *(ptr++)=val12; if (ptr!=ptr_end) *(ptr++)=val13; if (ptr!=ptr_end) *(ptr++)=val14;
04260       return *this;
04261     }
04262   
04264 
04269     CImg& normalize(const T& a,const T& b) {
04270       cimg_test(*this,"CImg<T>::normalize");
04271       const CImgStats st(*this,false);
04272       if (st.min==st.max) fill(0);
04273       else cimg_map(*this,ptr,T) *ptr=(T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a);
04274       return *this;
04275     }
04276 
04278 
04283     CImg get_normalize(const T& a,const T& b) const { return CImg<T>(*this).normalize(a,b); }
04284   
04286 
04291     CImg& cut(const T& a, const T& b) {
04292       cimg_test(*this,"CImg<T>::cut");
04293       cimg_map(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
04294       return *this;
04295     }
04296 
04298 
04303     CImg get_cut(const T& a, const T& b) const { return CImg<T>(*this).cut(a,b); }
04304 
04306 
04310     CImg& quantify(const unsigned int n=256) {
04311       cimg_test(*this,"CImg<T>::quantify");
04312       const CImgStats st(*this,false);
04313       const double range = st.max-st.min;
04314       cimg_map(*this,ptr,T) *ptr = (T)(st.min + range*(int)((*ptr-st.min)*(int)n/range)/n);
04315       return *this;
04316     }
04317 
04319 
04323     CImg get_quantify(const unsigned int n=256) const { return CImg<T>(*this).quantify(n); }
04324 
04326 
04330     CImg& threshold(const T& thres) {
04331       cimg_test(*this,"CImg<T>::threshold");
04332       cimg_map(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1;
04333       return *this;
04334     }
04335 
04337 
04341     CImg get_threshold(const T& thres) const { return CImg<T>(*this).threshold(thres); }
04342   
04344 
04353     CImg get_rotate(const float angle,const unsigned int cond=2) const {
04354       cimg_test(*this,"CImg<T>::get_rotate");
04355       CImg dest;
04356       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
04357         ca=(float)std::cos(rad), sa=(float)std::sin(rad);
04358     
04359       if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
04360         const int iangle = (int)nangle/90;
04361         switch (iangle) {
04362         case 1: {
04363           dest = CImg<T>(height,width,depth,dim); 
04364           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,height-1-x,z,v); 
04365         } break; 
04366         case 2: {
04367           dest = CImg<T>(width,height,depth,dim);
04368           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v); 
04369         } break;
04370         case 3: {
04371           dest = CImg<T>(height,width,depth,dim); 
04372           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-y,x,z,v); 
04373         } break;
04374         default: 
04375           return *this;        
04376         }
04377       } else { // generic version
04378         const float 
04379           ux  = (float)(cimg::abs(width*ca)),  uy  = (float)(cimg::abs(width*sa)),
04380           vx  = (float)(cimg::abs(height*sa)), vy  = (float)(cimg::abs(height*ca)),
04381           w2  = 0.5f*width,           h2  = 0.5f*height,
04382           dw2 = 0.5f*(ux+vx),         dh2 = 0.5f*(uy+vy);
04383         dest = CImg<T>((int)(ux+vx), (int)(uy+vy),depth,dim);
04384 
04385         switch (cond) {
04386         case 0: { 
04387           cimg_mapXY(dest,x,y)
04388             cimg_mapZV(*this,z,v) 
04389             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);
04390         } break;
04391         case 1: {
04392           cimg_mapXY(dest,x,y)
04393             cimg_mapZV(*this,z,v) 
04394             dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width),
04395                                     cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height),z,v);
04396         } break;
04397         default: {
04398           cimg_mapXY(dest,x,y) {
04399             const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
04400             const int ix = (int)X, iy = (int)Y;
04401             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
04402             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
04403           }
04404         } break; 
04405         }
04406       }
04407       return dest;
04408     }
04409   
04411 
04419     CImg& rotate(const float angle,const unsigned int cond=2) { return get_rotate(angle,cond).swap(*this); }
04420   
04422 
04433     CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) const {
04434       cimg_test(*this,"CImg<T>::get_rotate");
04435       CImg dest(*this,false);
04436       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
04437         ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom;
04438     
04439       if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
04440         const int iangle = (int)nangle/90;
04441         switch (iangle) {
04442         case 1: {
04443           dest.fill(0);
04444           const unsigned int
04445             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
04446             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
04447             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
04448             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
04449           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
04450             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
04451         } break;
04452         case 2: {
04453           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v); 
04454         } break;
04455         case 3: {
04456           dest.fill(0);
04457           const unsigned int
04458             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
04459             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
04460             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
04461             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
04462           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
04463             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
04464         } break;
04465         default: 
04466           return *this;        
04467         }
04468       } else 
04469         switch (cond) { // generic version
04470         case 0: { 
04471           cimg_mapXY(dest,x,y)
04472             cimg_mapZV(*this,z,v) 
04473             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);
04474         } break;
04475         case 1: {
04476           cimg_mapXY(dest,x,y)
04477             cimg_mapZV(*this,z,v) 
04478             dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width),
04479                                     cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height),z,v);
04480         } break;
04481         default: {
04482           cimg_mapXY(dest,x,y) {
04483             const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
04484             const int ix = (int)X, iy = (int)Y;
04485             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
04486             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
04487           }
04488         } break; 
04489         }
04490       return dest;
04491     }
04492   
04494 
04506     CImg& rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) {
04507       return get_rotate(angle,cx,cy,zoom,cond).swap(*this);
04508     }
04509  
04511 
04525     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 {
04526       cimg_test(*this,"CImg<T>::get_resize");
04527       const unsigned int 
04528         dx = pdx<0?-pdx*width/100:pdx,
04529         dy = pdy<0?-pdy*height/100:pdy,
04530         dz = pdz<0?-pdz*depth/100:pdz, 
04531         dv = pdv<0?-pdv*dim/100:pdv;
04532       CImg res(dx?dx:1,dy?dy:1,dz?dz:1,dv?dv:1);
04533       if (width==res.width && height==res.height && depth==res.depth && dim==res.dim) return *this;
04534       switch (interp) {
04535       case 0: { // Zero filling
04536         res.fill(0).draw_image(*this,0,0,0,0);
04537       } break;
04538       case 1: { // Bloc interpolation
04539         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
04540         float cx,cy,cz,ck=0;
04541         cimg_mapV(res,k) { cz = 0; 
04542         cimg_mapZ(res,z) { cy = 0; 
04543         cimg_mapY(res,y) { cx = 0; 
04544         cimg_mapX(res,x) { res(x,y,z,k) = (*this)((unsigned int)cx,(unsigned int)cy,(unsigned int)cz,(unsigned int)ck); cx+=sx;
04545         } cy+=sy;
04546         } cz+=sz;
04547         } ck+=sk;
04548         }
04549       } break;
04550       case 2: { // Mosaic filling
04551         for (unsigned int k=0; k<res.dim; k+=dim)
04552           for (unsigned int z=0; z<res.depth; z+=depth)
04553             for (unsigned int y=0; y<res.height; y+=height)
04554               for (unsigned int x=0; x<res.width; x+=width) res.draw_image(*this,x,y,z,k);
04555       } break;
04556       case 3: { // Linear interpolation
04557         const float
04558           sx = res.width>1?(float)(width-1)/(res.width-1):0,
04559           sy = res.height>1?(float)(height-1)/(res.height-1):0,
04560           sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
04561           sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
04562         float cx,cy,cz,ck = 0;
04563         cimg_mapV(res,k) { cz = 0; 
04564         cimg_mapZ(res,z) { cy = 0;
04565         cimg_mapY(res,y) { cx = 0; 
04566         cimg_mapX(res,x) { res(x,y,z,k) = (T)linear_pix4d(cx,cy,cz,ck); cx+=sx;
04567         } cy+=sy;
04568         } cz+=sz;
04569         } ck+=sk;
04570         }
04571       } break;
04572       case 4: { // Grid filling
04573         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
04574         res.fill(0);
04575         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);
04576       } break;
04577       case 5: { // Cubic interpolation
04578         const float
04579           sx = res.width>1?(float)(width-1)/(res.width-1):0,
04580           sy = res.height>1?(float)(height-1)/(res.height-1):0,
04581           sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
04582           sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
04583         float cx,cy,cz,ck = 0;
04584         cimg_mapV(res,k) { cz = 0;
04585         cimg_mapZ(res,z) { cy = 0;
04586         cimg_mapY(res,y) { cx = 0;
04587         cimg_mapX(res,x) { res(x,y,z,k) = (T)cubic_pix2d(cx,cy,(int)cz,(int)ck); cx+=sx;
04588         } cy+=sy;
04589         } cz+=sz;
04590         } ck+=sk;
04591         }
04592       } break;      
04593       }
04594       return res;
04595     }
04596 
04598 
04609     template<typename t> CImg get_resize(const CImg<t>& src,const unsigned int interp=1) const {
04610       return get_resize(src.width,src.height,src.depth,src.dim,interp); 
04611     }  
04612 
04614 
04625     CImg get_resize(const CImgDisplay& disp,const unsigned int interp=1) const {
04626       return get_resize(disp.width,disp.height,depth,dim,interp);
04627     }
04628 
04630 
04644     CImg& resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) {
04645       const unsigned int
04646         dx = pdx<0?-pdx*width/100 :(pdx==0?1:pdx),
04647         dy = pdy<0?-pdy*height/100:(pdy==0?1:pdy),
04648         dz = pdz<0?-pdz*depth/100 :(pdz==0?1:pdz),
04649         dv = pdv<0?-pdv*dim/100   :(pdv==0?1:pdv);
04650       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
04651       else return get_resize(dx,dy,dz,dv,interp).swap(*this);
04652     }
04653 
04655 
04666     template<typename t> CImg& resize(const CImg<t>& src,const unsigned int interp=1) { 
04667       return resize(src.width,src.height,src.depth,src.dim,interp); 
04668     }
04669 
04671 
04682     CImg& resize(const CImgDisplay& disp,const unsigned int interp=1) {
04683       return resize(disp.width,disp.height,depth,dim,interp);
04684     }
04685 
04687 
04690     CImg get_resize_halfXY() const {
04691       cimg_test(*this,"CImg<T>::get_resize_halfXY");
04692       CImg<float> mask = CImg<float>::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f,
04693                                              0.1231940459f,  0.1935127547f, 0.1231940459f,
04694                                              0.07842776544f, 0.1231940459f, 0.07842776544f);
04695       CImg_3x3(I,float);
04696       CImg dest(width/2,height/2,depth,dim);
04697       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);
04698       return dest;
04699     }
04700 
04702 
04705     CImg& resize_halfXY() {     return get_resize_halfXY().swap(*this); }
04706 
04708 
04720     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
04721                   const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
04722                   const bool border_condition = false) const {
04723       cimg_test(*this,"CImg<T>::get_crop");
04724       const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1;
04725       CImg dest(dx,dy,dz,dv);
04726       if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth ||
04727           v0>=dim || v1>=dim || x1<x0 || y1<y0 || z1<z0 || v1<v0)
04728         switch (border_condition) {
04729         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;
04730         default: { cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = neumann_pix4d(x0+x,y0+y,z0+z,v0+v); } break;
04731         } else {
04732           T *psrc = ptr(x0,y0,z0,v0), *pdest = dest.ptr(0,0,0,0);
04733           if (dx!=width)
04734             for (unsigned int k=0; k<dv; k++) {
04735               for (unsigned int z=0; z<dz; z++) {
04736                 for (unsigned int y=0; y<dy; y++) {
04737                   std::memcpy(pdest,psrc,dx*sizeof(T));
04738                   pdest+=dx;
04739                   psrc+=width;
04740                 }
04741                 psrc+=width*(height-dy);
04742               }
04743               psrc+=width*height*(depth-dz);
04744             }
04745           else {
04746             if (dy!=height)         
04747               for (unsigned int k=0; k<dv; k++) {
04748                 for (unsigned int z=0; z<dz; z++) {
04749                   std::memcpy(pdest,psrc,dx*dy*sizeof(T));
04750                   pdest+=dx*dy;
04751                   psrc+=width*height;
04752                 }
04753                 psrc+=width*height*(depth-dz);
04754               }
04755             else {
04756               if (dz!=depth)
04757                 for (unsigned int k=0; k<dv; k++) {
04758                   std::memcpy(pdest,psrc,dx*dy*dz*sizeof(T));
04759                   pdest+=dx*dy*dz;
04760                   psrc+=width*height*depth;
04761                 }
04762               else std::memcpy(pdest,psrc,dx*dy*dz*dv*sizeof(T));
04763             }
04764           }
04765         }
04766       return dest;
04767     }
04768     
04770 
04779     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
04780                   const unsigned int x1,const unsigned int y1,const unsigned int z1,
04781                   const bool border_condition=false) const {
04782       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
04783     }
04784 
04786 
04793     CImg get_crop(const unsigned int x0,const unsigned int y0,
04794                   const unsigned int x1,const unsigned int y1,
04795                   const bool border_condition=false) const {
04796       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
04797     }
04798 
04800 
04805     CImg get_crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) const {
04806       return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition); 
04807     }
04808 
04810 
04821     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
04822                const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
04823                const bool border_condition=false) {
04824       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).swap(*this);
04825     }
04826 
04828 
04837     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
04838                const unsigned int x1,const unsigned int y1,const unsigned int z1,
04839                const bool border_condition=false) {
04840       return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
04841     }
04842 
04844 
04851     CImg& crop(const unsigned int x0,const unsigned int y0,
04852                const unsigned int x1,const unsigned int y1,
04853                const bool border_condition=false) { 
04854       return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition); 
04855     }
04856 
04858 
04863     CImg& crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) { 
04864       return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
04865     }
04866 
04868 
04872     CImg get_channel(const unsigned int v0=0) const { return get_crop(0,0,0,v0,width-1,height-1,depth-1,v0); }
04873 
04875 
04879     CImg get_slice(const unsigned int z0=0) const { return get_crop(0,0,z0,0,width-1,height-1,z0,dim-1); }
04880 
04882 
04887     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); }
04888 
04890     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 {
04891       cimg_test(*this,"CImg<T>::ref_pointset");
04892       if (xmax<xmin || xmax>=width || y0>=height || z0>=depth || v0>=dim)
04893         throw CImgArgumentException("CImg<%s>::ref_pointset() : Cannot return a reference (%u->%u,%u,%u,%u) from a (%u,%u,%u,%u) image",
04894                                     pixel_type(),xmin,xmax,y0,z0,v0,width,height,depth,dim);
04895       return CImgROI<T>(1+xmax-xmin,1,1,1,ptr(xmin,y0,z0,v0));
04896     }
04897 
04899     CImgROI<T> ref_lineset(const unsigned int ymin,const unsigned int ymax,const unsigned int z0=0,const unsigned int v0=0) const {
04900       cimg_test(*this,"CImg<T>::ref_lineset");
04901       if (ymax<ymin || ymax>=height || z0>=depth || v0>=dim)
04902         throw CImgArgumentException("CImg<%s>::ref_lineset() : Cannot return a reference (0->%u,%u->%u,%u,%u) from a (%u,%u,%u,%u) image",
04903                                     pixel_type(),width-1,ymin,ymax,z0,v0,width,height,depth,dim);
04904       return CImgROI<T>(width,1+ymax-ymin,1,1,ptr(0,ymin,z0,v0));
04905     }
04906   
04908     CImgROI<T> ref_planeset(const unsigned int zmin,const unsigned int zmax,const unsigned int v0=0) const {
04909       cimg_test(*this,"CImg<T>::ref_planeset");
04910       if(zmax<zmin || zmax>=depth || v0>=dim)
04911         throw CImgArgumentException("CImg<%s>::ref_planeset() : Cannot return a reference (0->%u,0->%u,%u->%u,%u) from a (%u,%u,%u,%u) image",
04912                                     pixel_type(),width-1,height-1,zmin,zmax,v0,width,height,depth,dim);
04913       return CImgROI<T>(width,height,1+zmax-zmin,1,ptr(0,0,zmin,v0));
04914     }
04915 
04917     CImgROI<T> ref_channelset(const unsigned int vmin,const unsigned int vmax) const {
04918       cimg_test(*this,"CImg<T>::ref_channelset");
04919       if (vmax<vmin || vmax>=dim)
04920         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",
04921                                     pixel_type(),width-1,height-1,depth-1,vmin,vmax,width,height,depth,dim);
04922       return CImgROI<T>(width,height,depth,1+vmax-vmin,ptr(0,0,0,vmin));
04923     }
04924   
04926     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); }
04927 
04929     CImgROI<T> ref_plane(const unsigned int z0,const unsigned int v0=0) const { return ref_lineset(0,height-1,z0,v0); }
04930 
04932     CImgROI<T> ref_channel(const unsigned int v0) const { return ref_planeset(0,depth-1,v0); }
04933 
04935     CImg& channel(const unsigned int v0=0) { return get_channel(v0).swap(*this); }
04936 
04938     CImg& slice(const unsigned int z0=0) { return get_slice(z0).swap(*this); }
04939 
04941     CImg& plane(const unsigned int z0=0, const unsigned int v0=0) { return get_plane(z0,v0).swap(*this); }
04942   
04944     CImg& flip(const char axe='x') {
04945       cimg_test(*this,"CImg<T>::flip");
04946       T *pf,*pb,*buf=NULL;
04947       switch (cimg::uncase(axe)) {
04948       case 'x': {
04949         pf = ptr(); pb = ptr(width-1);
04950         for (unsigned int yzv=0; yzv<height*depth*dim; yzv++) { 
04951           for (unsigned int x=0; x<width/2; x++) { const T val = *pf; *(pf++)=*pb; *(pb--)=val; }
04952           pf+=width-width/2;
04953           pb+=width+width/2;
04954         }
04955       } break;
04956       case 'y': {
04957         buf = new T[width];
04958         pf = ptr(); pb = ptr(0,height-1);
04959         for (unsigned int zv=0; zv<depth*dim; zv++) {
04960           for (unsigned int y=0; y<height/2; y++) {
04961             std::memcpy(buf,pf,width*sizeof(T));
04962             std::memcpy(pf,pb,width*sizeof(T));
04963             std::memcpy(pb,buf,width*sizeof(T));
04964             pf+=width;
04965             pb-=width;
04966           }
04967           pf+=width*(height-height/2);
04968           pb+=width*(height+height/2);
04969         }
04970       } break;
04971       case 'z': {
04972         buf = new T[width*height];
04973         pf = ptr(); pb = ptr(0,0,depth-1);
04974         cimg_mapV(*this,v) {
04975           for (unsigned int z=0; z<depth/2; z++) {
04976             std::memcpy(buf,pf,width*height*sizeof(T));
04977             std::memcpy(pf,pb,width*height*sizeof(T));
04978             std::memcpy(pb,buf,width*height*sizeof(T));
04979             pf+=width*height;
04980             pb-=width*height;
04981           }
04982           pf+=width*height*(depth-depth/2);
04983           pb+=width*height*(depth+depth/2);
04984         }
04985       } break;
04986       case 'v': {
04987         buf = new T[width*height*depth];
04988         pf = ptr(); pb = ptr(0,0,0,dim-1);
04989         for (unsigned int v=0; v<dim/2; v++) {
04990           std::memcpy(buf,pf,width*height*depth*sizeof(T));
04991           std::memcpy(pf,pb,width*height*depth*sizeof(T));
04992           std::memcpy(pb,buf,width*height*depth*sizeof(T));
04993           pf+=width*height*depth;
04994           pb-=width*height*depth;
04995         }
04996       } break;
04997       default:
04998         throw CImgArgumentException("CImg<%s>::flip() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
04999       }
05000       if (buf) delete[] buf;
05001       return *this;
05002     }
05003 
05005     CImg get_flip(const char axe='x') { return CImg<T>(*this).flip(axe); }
05006     
05008     CImg& scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,const int border_condition=0) {
05009       cimg_test(*this,"CImg<T>::scroll");
05010       
05011       if (scrollx) // Scroll along X-axis
05012         switch (border_condition) {
05013         case 0:
05014           if (cimg::abs(scrollx)>=(int)width) return fill(0);
05015           if (scrollx>0) cimg_mapYZV(*this,y,z,k) {
05016             std::memmove(ptr(0,y,z,k),ptr(scrollx,y,z,k),(width-scrollx)*sizeof(T));
05017             std::memset(ptr(width-scrollx,y,z,k),0,scrollx*sizeof(T));
05018           } else cimg_mapYZV(*this,y,z,k) {
05019             std::memmove(ptr(-scrollx,y,z,k),ptr(0,y,z,k),(width+scrollx)*sizeof(T));
05020             std::memset(ptr(0,y,z,k),0,-scrollx*sizeof(T));
05021           }
05022           break;   
05023         case 1:
05024           if (scrollx>0) {
05025             const int nscrollx = (scrollx>=(int)width)?width-1:scrollx;
05026             if (!nscrollx) return *this;
05027             cimg_mapYZV(*this,y,z,k) {
05028               std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
05029               T *ptrd = ptr(width-1,y,z,k);
05030               const T &val = *ptrd;
05031               for (int l=0; l<nscrollx-1; l++) *(--ptrd) = val;
05032             }
05033           } else {
05034             const int nscrollx = (-scrollx>=(int)width)?width-1:-scrollx;
05035             if (!nscrollx) return *this;
05036             cimg_mapYZV(*this,y,z,k) {
05037               std::memmove(ptr(nscrollx,y,z,k),ptr(0,y,z,k),(width-nscrollx)*sizeof(T));
05038               T *ptrd = ptr(0,y,z,k);
05039               const T &val = *ptrd;
05040               for (int l=0; l<nscrollx-1; l++) *(++ptrd) = val;
05041             }
05042           }    
05043           break; 
05044         case 2: {
05045           const int ml = cimg::mod(scrollx,width), nscrollx = (ml<=(int)width/2)?ml:(ml-(int)width);
05046           if (!nscrollx) return *this;
05047           T* buf = new T[cimg::abs(nscrollx)];
05048           if (nscrollx>0) cimg_mapYZV(*this,y,z,k) {
05049             std::memcpy(buf,ptr(0,y,z,k),nscrollx*sizeof(T));
05050             std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
05051             std::memcpy(ptr(width-nscrollx,y,z,k),buf,nscrollx*sizeof(T));
05052           } else cimg_mapYZV(*this,y,z,k) {
05053             std::memcpy(buf,ptr(width+nscrollx,y,z,k),-nscrollx*sizeof(T));
05054             std::memmove(ptr(-nscrollx,y,z,k),ptr(0,y,z,k),(width+nscrollx)*sizeof(T));
05055             std::memcpy(ptr(0,y,z,k),buf,-nscrollx*sizeof(T));
05056           }
05057           delete[] buf;
05058         } break;
05059         }
05060 
05061       if (scrolly) // Scroll along Y-axis
05062         switch (border_condition) {
05063         case 0:
05064           if (cimg::abs(scrolly)>=(int)height) return fill(0);
05065           if (scrolly>0) cimg_mapZV(*this,z,k) {
05066             std::memmove(ptr(0,0,z,k),ptr(0,scrolly,z,k),width*(height-scrolly)*sizeof(T));
05067             std::memset(ptr(0,height-scrolly,z,k),0,width*scrolly*sizeof(T));
05068           } else cimg_mapZV(*this,z,k) {
05069             std::memmove(ptr(0,-scrolly,z,k),ptr(0,0,z,k),width*(height+scrolly)*sizeof(T));
05070             std::memset(ptr(0,0,z,k),0,-scrolly*width*sizeof(T));
05071           }
05072           break;      
05073         case 1:
05074           if (scrolly>0) {
05075             const int nscrolly = (scrolly>=(int)height)?height-1:scrolly;
05076             if (!nscrolly) return *this;
05077             cimg_mapZV(*this,z,k) {
05078               std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
05079               T *ptrd = ptr(0,height-nscrolly,z,k), *ptrs = ptr(0,height-1,z,k);
05080               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
05081             }
05082           } else {
05083             const int nscrolly = (-scrolly>=(int)height)?height-1:-scrolly;
05084             if (!nscrolly) return *this;
05085             cimg_mapZV(*this,z,k) {
05086               std::memmove(ptr(0,nscrolly,z,k),ptr(0,0,z,k),width*(height-nscrolly)*sizeof(T));
05087               T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
05088               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
05089             }
05090           }    
05091           break;  
05092         case 2: {
05093           const int ml = cimg::mod(scrolly,height), nscrolly = (ml<=(int)height/2)?ml:(ml-(int)height);
05094           if (!nscrolly) return *this;
05095           T* buf = new T[width*cimg::abs(nscrolly)];
05096           if (nscrolly>0) cimg_mapZV(*this,z,k) {
05097             std::memcpy(buf,ptr(0,0,z,k),width*nscrolly*sizeof(T));
05098             std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
05099             std::memcpy(ptr(0,height-nscrolly,z,k),buf,width*nscrolly*sizeof(T));
05100           } else cimg_mapZV(*this,z,k) {
05101             std::memcpy(buf,ptr(0,height+nscrolly,z,k),-nscrolly*width*sizeof(T));
05102             std::memmove(ptr(0,-nscrolly,z,k),ptr(0,0,z,k),width*(height+nscrolly)*sizeof(T));
05103             std::memcpy(ptr(0,0,z,k),buf,-nscrolly*width*sizeof(T));
05104           }
05105           delete[] buf;
05106         } break;    
05107         }
05108 
05109       if (scrollz) // Scroll along Z-axis
05110         switch (border_condition) {
05111         case 0:
05112           if (cimg::abs(scrollz)>=(int)depth) return fill(0);
05113           if (scrollz>0) cimg_mapV(*this,k) {
05114             std::memmove(ptr(0,0,0,k),ptr(0,0,scrollz,k),width*height*(depth-scrollz)*sizeof(T));
05115             std::memset(ptr(0,0,depth-scrollz,k),0,width*height*scrollz*sizeof(T));
05116           } else cimg_mapV(*this,k) {
05117             std::memmove(ptr(0,0,-scrollz,k),ptr(0,0,0,k),width*height*(depth+scrollz)*sizeof(T));
05118             std::memset(ptr(0,0,0,k),0,-scrollz*width*height*sizeof(T));
05119           }
05120           break;      
05121         case 1:
05122           if (scrollz>0) {
05123             const int nscrollz = (scrollz>=(int)depth)?depth-1:scrollz;
05124             if (!nscrollz) return *this;
05125             cimg_mapV(*this,k) {
05126               std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
05127               T *ptrd = ptr(0,0,depth-nscrollz,k), *ptrs = ptr(0,0,depth-1,k);
05128               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
05129             }
05130           } else {
05131             const int nscrollz = (-scrollz>=(int)depth)?depth-1:-scrollz;
05132             if (!nscrollz) return *this;
05133             cimg_mapV(*this,k) {
05134               std::memmove(ptr(0,0,nscrollz,k),ptr(0,0,0,k),width*height*(depth-nscrollz)*sizeof(T));
05135               T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
05136               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
05137             }
05138           }    
05139           break;      
05140         case 2: {
05141           const int ml = cimg::mod(scrollz,depth), nscrollz = (ml<=(int)depth/2)?ml:(ml-(int)depth);
05142           if (!nscrollz) return *this;
05143           T* buf = new T[width*height*cimg::abs(nscrollz)];
05144           if (nscrollz>0) cimg_mapV(*this,k) {
05145             std::memcpy(buf,ptr(0,0,0,k),width*height*nscrollz*sizeof(T));
05146             std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
05147             std::memcpy(ptr(0,0,depth-nscrollz,k),buf,width*height*nscrollz*sizeof(T));
05148           } else cimg_mapV(*this,k) {
05149             std::memcpy(buf,ptr(0,0,depth+nscrollz,k),-nscrollz*width*height*sizeof(T));
05150             std::memmove(ptr(0,0,-nscrollz,k),ptr(0,0,0,k),width*height*(depth+nscrollz)*sizeof(T));
05151             std::memcpy(ptr(0,0,0,k),buf,-nscrollz*width*height*sizeof(T));
05152           }
05153           delete[] buf;
05154         } break;    
05155         }
05156 
05157       if (scrollv) // Scroll along V-axis
05158         switch (border_condition) {
05159         case 0:
05160           if (cimg::abs(scrollv)>=(int)dim) return fill(0);
05161           if (scrollv>0) {
05162             std::memmove(data,ptr(0,0,0,scrollv),width*height*depth*(dim-scrollv)*sizeof(T));
05163             std::memset(ptr(0,0,0,dim-scrollv),0,width*height*depth*scrollv*sizeof(T));
05164           } else cimg_mapV(*this,k) {
05165             std::memmove(ptr(0,0,0,-scrollv),data,width*height*depth*(dim+scrollv)*sizeof(T));
05166             std::memset(data,0,-scrollv*width*height*depth*sizeof(T));
05167           }
05168           break;      
05169         case 1:
05170           if (scrollv>0) {
05171             const int nscrollv = (scrollv>=(int)dim)?dim-1:scrollv;
05172             if (!nscrollv) return *this;
05173             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
05174             T *ptrd = ptr(0,0,0,dim-nscrollv), *ptrs = ptr(0,0,0,dim-1);
05175             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }      
05176           } else {
05177             const int nscrollv = (-scrollv>=(int)dim)?dim-1:-scrollv;
05178             if (!nscrollv) return *this;
05179             std::memmove(ptr(0,0,0,nscrollv),data,width*height*depth*(dim-nscrollv)*sizeof(T));
05180             T *ptrd = ptr(0,0,0,1);
05181             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }      
05182           }    
05183           break;      
05184         case 2: {
05185           const int ml = cimg::mod(scrollv,dim), nscrollv = (ml<=(int)dim/2)?ml:(ml-(int)dim);
05186           if (!nscrollv) return *this;
05187           T* buf = new T[width*height*depth*cimg::abs(nscrollv)];
05188           if (nscrollv>0) {
05189             std::memcpy(buf,data,width*height*depth*nscrollv*sizeof(T));
05190             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
05191             std::memcpy(ptr(0,0,0,dim-nscrollv),buf,width*height*depth*nscrollv*sizeof(T));
05192           } else {
05193             std::memcpy(buf,ptr(0,0,0,dim+nscrollv),-nscrollv*width*height*depth*sizeof(T));
05194             std::memmove(ptr(0,0,0,-nscrollv),data,width*height*depth*(dim+nscrollv)*sizeof(T));
05195             std::memcpy(data,buf,-nscrollv*width*height*depth*sizeof(T));
05196           }
05197           delete[] buf;
05198         } break;    
05199         }
05200 
05201       return *this;
05202     }
05203 
05205     CImg get_scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,
05206                     const int border_condition=0) const {
05207       return CImg<T>(*this).scroll(scrollx,scrolly,scrollz,scrollv,border_condition);
05208     }
05209     
05211     CImg get_3dplanes(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const {
05212       cimg_test(*this,"CImg<T>::get_3dplanes");
05213       const unsigned int
05214         x0=(px0>=width)?width-1:px0,
05215         y0=(py0>=height)?height-1:py0,
05216         z0=(pz0>=depth)?depth-1:pz0;
05217       CImg res(width+depth,height+depth,1,dim);
05218       res.fill((*this)[0]);
05219       { cimg_mapXYV(*this,x,y,k) res(x,y,0,k)        = (*this)(x,y,z0,k); }
05220       { cimg_mapYZV(*this,y,z,k) res(width+z,y,0,k)  = (*this)(x0,y,z,k); }
05221       { cimg_mapXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); }
05222       return res;
05223     }
05224 
05226     CImg<float> get_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const {
05227       cimg_test(*this,"CImg<T>::get_histogram");
05228       if (nblevels<1) {
05229         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %u levels",
05230                                     pixel_type(),nblevels);
05231       }
05232       T vmin=val_min,vmax=val_max;
05233       CImg<float> res(nblevels,1,1,1,0);
05234       if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
05235       cimg_map(*this,ptr,T) { const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); if (pos>=0 && pos<(int)nblevels) res[pos]++; }
05236       return res;
05237     }
05238 
05240     CImg& equalize_histogram(const unsigned int nblevels=256) {
05241       cimg_test(*this,"CImg<T>::equalize_histogram");
05242       CImgStats st(*this,false);
05243       CImg<float> hist = get_histogram(nblevels,(T)st.min,(T)st.max);
05244       float cumul=0;
05245       cimg_mapX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
05246       cimg_map(*this,ptr,T) {
05247         unsigned int pos = (unsigned int)((*ptr-st.min)*nblevels/(1+st.max-st.min));
05248         *ptr = (T)(st.min + (st.max-st.min)*hist[pos]/size());
05249       }
05250       return *this;
05251     }
05253     CImg get_equalize_histogram(const unsigned int nblevels=256) const { return CImg<T>(*this).equalize_histogram(nblevels); }
05254 
05256     CImg<float> get_norm_pointwise(int ntype=2) const {
05257       cimg_test(*this,"CImg<T>::get_norm_pointwise");
05258       CImg<float> res(width,height,depth);
05259       switch(ntype) {
05260       case -1:                // Linf norm
05261         {
05262           cimg_mapXYZ(*this,x,y,z) {
05263             float n=0; cimg_mapV(*this,v) {
05264               const double tmp = cimg::abs((double)(*this)(x,y,z,v));
05265               if (tmp>n) n=(float)tmp; res(x,y,z) = n;
05266             }
05267           }
05268         } break;
05269       case 1:               // L1 norm
05270         {
05271           cimg_mapXYZ(*this,x,y,z) {
05272             float n=0; cimg_mapV(*this,v) n+=cimg::abs((float)((*this)(x,y,z,v))); res(x,y,z) = n;
05273           }
05274         } break;
05275       default:              // L2 norm
05276         {
05277           cimg_mapXYZ(*this,x,y,z) {
05278             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);
05279           }
05280         } break;
05281       }
05282       return res;
05283     }
05284 
05286     CImg& norm_pointwise() { return CImg<T>(get_norm_pointwise()).swap(*this); }
05287 
05289     CImg get_orientation_pointwise() const {
05290       cimg_test(*this,"CImg<T>::get_orientation_pointwise");
05291       CImg dest(width,height,depth,dim);
05292       cimg_mapXYZ(dest,x,y,z) {
05293         float n = 0;
05294         cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
05295         n = (float)std::sqrt((double)n);
05296         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;
05297       }
05298       return dest;
05299     }
05300 
05302     CImg& orientation_pointwise() { return get_orientation_pointwise().swap(*this); }
05303 
05305 
05308     CImgl<T> get_split(const char axe,const unsigned int nb=0) const {
05309       cimg_test(*this,"CImg<T>::get_split");
05310       CImgl<T> res;
05311       switch (cimg::uncase(axe)) {
05312       case 'x': {
05313         res = CImgl<T>(nb?nb:width);
05314         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);
05315         } break;
05316       case 'y': {
05317         res = CImgl<T>(nb?nb:height);
05318         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);
05319         } break;
05320       case 'z': {
05321         res = CImgl<T>(nb?nb:depth);
05322         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);
05323         } break;
05324       case 'v': {
05325         res = CImgl<T>(nb?nb:dim);
05326         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);
05327         } break;
05328       default:
05329         throw CImgArgumentException("CImg<%s>::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
05330         break;
05331       }
05332       return res;
05333     }
05334 
05336 
05346     CImgl<T> get_gradientXY(const int scheme=0,const float alpha=0) const {
05347       cimg_test(*this,"CImg<T>::get_gradientXY");
05348       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
05349       CImgl<T> res(2,width,height,depth,dim);
05350       CImg_3x3(I,T);
05351       switch(scheme) {
05352       case -1: { // backward finite differences
05353         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; } 
05354       } break;
05355       case 1: { // forward finite differences
05356         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; }
05357       } break;
05358       case 2: { // using Sobel mask
05359         const float a = 1, b = 2;
05360         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
05361           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
05362           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
05363         }
05364       } break;
05365       case 3: { // using rotation invariant mask
05366         const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1));
05367         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
05368           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
05369           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
05370         }
05371       } break;
05372       case 4: { // using Deriche filter with low standart variation
05373         res[0] = get_deriche(alpha,1,'x');
05374         res[1] = get_deriche(alpha,1,'y');
05375       } break;
05376       default: { // central finite differences
05377         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) { 
05378           res[0](x,y,z,k) = (T)(0.5*(Inc-Ipc));
05379           res[1](x,y,z,k) = (T)(0.5*(Icn-Icp)); 
05380         } 
05381       } break;
05382       }
05383       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
05384       return res;
05385     }
05386 
05388 
05391     CImgl<T> get_gradientXYZ(const int scheme=0,const float alpha=0) const {
05392       cimg_test(*this,"CImg<T>::get_gradientXYZ");
05393       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
05394       CImgl<T> res(3,width,height,depth,dim);
05395       CImg_3x3x3(I,T);
05396       switch(scheme) {
05397       case -1: { // backward finite differences
05398         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) { 
05399           res[0](x,y,z,k) = Iccc-Ipcc;
05400           res[1](x,y,z,k) = Iccc-Icpc;
05401           res[2](x,y,z,k) = Iccc-Iccp; 
05402         }
05403       } break;
05404       case 1: { // forward finite differences
05405         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
05406           res[0](x,y,z,k) = Incc-Iccc; 
05407           res[1](x,y,z,k) = Icnc-Iccc;
05408           res[2](x,y,z,k) = Iccn-Iccc; 
05409         } 
05410       } break;
05411       case 4: { // using Deriche filter with low standart variation
05412         res[0] = get_deriche(alpha,1,'x');
05413         res[1] = get_deriche(alpha,1,'y');
05414         res[2] = get_deriche(alpha,1,'z');
05415       } break;
05416       default: { // central finite differences
05417         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
05418           res[0](x,y,z,k) = (T)(0.5*(Incc-Ipcc));
05419           res[1](x,y,z,k) = (T)(0.5*(Icnc-Icpc)); 
05420           res[2](x,y,z,k) = (T)(0.5*(Iccn-Iccp)); 
05421         } 
05422       } break;
05423       }
05424       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
05425       return res;
05426     }
05427 
05429     //--------------------------------------
05430     //--------------------------------------
05431     //
05433 
05434     //--------------------------------------
05435     //--------------------------------------
05436   
05438     CImg& RGBtoXYZ() {
05439       cimg_test(*this,"CImg<T>::RGBtoXYZ");
05440       if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
05441                                               "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
05442       cimg_mapXYZ(*this,x,y,z) {
05443         const T R = (*this)(x,y,z,0), G = (*this)(x,y,z,1), B = (*this)(x,y,z,2);
05444         (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B);
05445         (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B);
05446         (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B);
05447       }
05448       return *this;
05449     }
05450 
05452     CImg& XYZtoRGB() {
05453       cimg_test(*this,"CImg<T>::XYZtoRGB");
05454       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
05455                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05456       cimg_mapXYZ(*this,x,y,z) {
05457         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
05458         (*this)(x,y,z,0) = (T)(3.240479*X  - 1.537150*Y - 0.498535*Z);
05459         (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z);
05460         (*this)(x,y,z,2) = (T)(0.055648*X  - 0.204043*Y + 1.057311*Z);
05461       }
05462       return *this;
05463     }
05464 
05466 #define cimg_Labf(x)  ((x)>=0.008856?(std::pow(x,1/3.0)):(7.787*(x)+16.0/116.0))
05467 #define cimg_Labfi(x) ((x)>=0.206893?((x)*(x)*(x)):(((x)-16.0/116.0)/7.787))
05468 
05469     CImg& XYZtoLab() {
05470       cimg_test(*this,"CImg<T>::XYZtoLab");
05471       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
05472                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05473       const double
05474         Xn = 0.412453 + 0.357580 + 0.180423,
05475         Yn = 0.212671 + 0.715160 + 0.072169,
05476         Zn = 0.019334 + 0.119193 + 0.950227;
05477       cimg_mapXYZ(*this,x,y,z) {
05478         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
05479         const double
05480           XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
05481           fX = cimg_Labf(XXn), fY = cimg_Labf(YYn), fZ = cimg_Labf(ZZn);
05482         (*this)(x,y,z,0) = (T)(116*fY-16);
05483         (*this)(x,y,z,1) = (T)(500*(fX-fY));
05484         (*this)(x,y,z,2) = (T)(200*(fY-fZ));
05485       }
05486       return *this;
05487     }
05488 
05490     CImg& LabtoXYZ() {
05491       cimg_test(*this,"CImg<T>::LabtoXYZ");
05492       if (dim!=3) throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
05493                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05494       const double
05495         Xn = 0.412453 + 0.357580 + 0.180423,
05496         Yn = 0.212671 + 0.715160 + 0.072169,
05497         Zn = 0.019334 + 0.119193 + 0.950227;
05498       cimg_mapXYZ(*this,x,y,z) {
05499         const T L = (*this)(x,y,z,0), a = (*this)(x,y,z,1), b = (*this)(x,y,z,2);
05500         const double
05501           cY = (L+16)/116.0,
05502           Y = Yn*cimg_Labfi(cY),
05503           pY = std::pow(Y/Yn,1.0/3),
05504           cX = a/500+pY,
05505           X = Xn*cX*cX*cX,
05506           cZ = pY-b/200,
05507           Z = Zn*cZ*cZ*cZ;
05508         (*this)(x,y,z,0) = (T)(X);
05509         (*this)(x,y,z,1) = (T)(Y);
05510         (*this)(x,y,z,2) = (T)(Z);
05511       }
05512       return *this;
05513     }
05514 
05516     CImg& XYZtoxyY() {
05517       cimg_test(*this,"CImg<T>::XYZtoxyY()");
05518       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
05519                                               "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
05520       cimg_mapXYZ(*this,x,y,z) {
05521         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;
05522         (*this)(x,y,z,0) = X/nsum;
05523         (*this)(x,y,z,1) = Y/nsum;
05524         (*this)(x,y,z,2) = Y;
05525       }
05526       return *this;
05527     }
05528 
05530     CImg& xyYtoXYZ() {
05531       cimg_test(*this,"CImg<T>::xyYtoXYZ()");
05532       if (dim!=3) throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
05533                                               "should be a (x,y,Y) image (dim=3)",pixel_type(),dim);
05534       cimg_mapXYZ(*this,x,y,z) {
05535         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;
05536         (*this)(x,y,z,0) = (T)(px*Y/ny);
05537         (*this)(x,y,z,1) = Y;
05538         (*this)(x,y,z,2) = (T)((1-px-py)*Y/ny);
05539       }
05540       return *this;
05541     }
05542     
05543     // Other conversions functions
05544     CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); }
05545     CImg& LabtoRGB() { return LabtoXYZ().XYZtoRGB(); }
05546     CImg& RGBtoxyY() { return RGBtoXYZ().XYZtoxyY(); }
05547     CImg& xyYtoRGB() { return xyYtoXYZ().XYZtoRGB(); }
05548 
05549     // equivalent with get_*()
05550     CImg get_RGBtoXYZ() const { return CImg<T>(*this).RGBtoXYZ(); }
05551     CImg get_XYZtoRGB() const { return CImg<T>(*this).XYZtoRGB(); }
05552     CImg get_XYZtoLab() const { return CImg<T>(*this).XYZtoLab(); }
05553     CImg get_LabtoXYZ() const { return CImg<T>(*this).LabtoXYZ(); }
05554     CImg get_XYZtoxyY() const { return CImg<T>(*this).XYZtoxyY(); }
05555     CImg get_xyYtoXYZ() const { return CImg<T>(*this).xyYtoXYZ(); }
05556     CImg get_RGBtoLab() const { return CImg<T>(*this).RGBtoLab(); }
05557     CImg get_LabtoRGB() const { return CImg<T>(*this).LabtoRGB(); }
05558     CImg get_RGBtoxyY() const { return CImg<T>(*this).RGBtoxyY(); }
05559     CImg get_xyYtoRGB() const { return CImg<T>(*this).xyYtoRGB(); }
05560 
05562     //--------------------------------------
05563     //--------------------------------------
05564     //
05566 
05567     //--------------------------------------
05568     //--------------------------------------
05569 
05570     // Should be used only by member functions. Not an user-friendly function.
05571     // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
05572     CImg& draw_scanline(const int x0,const int x1,const int y,const T *const color,const float opacity=1,
05573                        const bool init=false) {
05574       static float nopacity=0, copacity=0;
05575       static unsigned int whz=0;
05576       static const T* col = NULL;
05577       if (init) {
05578         cimg_test(*this,"CImg<T>::draw_scanline");
05579         if (!color) throw CImgArgumentException("CImg<%s>::draw_scanline() : specified color is (null)",pixel_type());
05580         nopacity = cimg::abs(opacity);
05581         copacity = 1-cimg::max(opacity,0.0f); 
05582         whz = width*height*depth;
05583         col = color;
05584       } else {
05585         const int nx0 = cimg::max(x0,0), nx1 = cimg::min(x1,(int)width-1), dx = nx1-nx0;
05586         T *ptrd = ptr(nx0,y,0,0);
05587         if (dx>=0) {
05588           if (opacity>=1) {
05589             int off = whz-dx-1;
05590             if (sizeof(T)!=1) cimg_mapV(*this,k) {
05591               const T& val = *(col++);
05592               for (int x=dx; x>=0; x--) *(ptrd++)=val;
05593               ptrd+=off;
05594             } else cimg_mapV(*this,k) { std::memset(ptrd,(int)*(col++),dx+1); ptrd+=whz; }
05595             col-=dim;
05596           } else {
05597             int off = whz-dx-1;
05598             cimg_mapV(*this,k) {
05599               const T& val = *(col++);
05600               for (int x=dx; x>=0; x--) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ptrd++; }
05601               ptrd+=off;
05602             }
05603             col-=dim;
05604           }
05605         }
05606       }
05607       return *this;
05608     }
05609     
05610     CImg& draw_scanline(const T *const color,const float opacity=1) { return draw_scanline(0,0,0,color,opacity,true); }
05611 
05613 
05621     CImg& draw_point(const int x0,const int y0,const int z0,
05622                      const T *const color,const float opacity=1) {
05623       cimg_test(*this,"CImg<T>::draw_point");
05624       if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : specified color is (null)",pixel_type());
05625       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
05626         const T *col=color;
05627         const unsigned int whz = width*height*depth;
05628         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05629         T *ptrd = ptr(x0,y0,z0,0);
05630         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
05631         else cimg_mapV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
05632       }
05633       return *this;
05634     }
05635 
05637 
05644     CImg& draw_point(const int x0,const int y0,const T *const color,const float opacity=1) { 
05645       return draw_point(x0,y0,0,color,opacity); 
05646     }
05647 
05649 
05659     CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
05660                     const T *const color,const unsigned int pattern=~0L,const float opacity=1) {
05661       cimg_test(*this,"CImg<T>::draw_line"); 
05662       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
05663       const T* col=color;
05664       unsigned int hatch=1;     
05665       int nx0=x0, nx1=x1, ny0=y0, ny1=y1;
05666       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1);
05667       if (nx1<0 || nx0>=dimx()) return *this;
05668       if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; }
05669       if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;}
05670       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
05671       if (ny1<0 || ny0>=dimy()) return *this;
05672       if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; }
05673       if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;}
05674       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), whz = width*height*depth;
05675       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0;
05676       float x = (float)nx0, y = (float)ny0;
05677       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
05678         if (!(~pattern) || (~pattern && pattern&hatch)) {
05679           T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);      
05680           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
05681           col-=dim;
05682         }
05683         x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05684       } else {
05685         const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f);
05686         for (unsigned int t=0; t<=dmax; t++) {
05687           if (!(~pattern) || (~pattern && pattern&hatch)) {
05688             T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05689             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
05690             col-=dim;
05691           }
05692           x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05693         }
05694       }
05695       return *this;
05696     }
05697   
05699 
05711     CImg& draw_line(const int x0,const int y0,const int z0,const int x1,const int y1,const int z1,
05712                     const T *const color,const unsigned int pattern=~0L,const float opacity=1) {
05713       cimg_test(*this,"CImg<T>::draw_line"); 
05714       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
05715       const T* col=color;
05716       unsigned int hatch=1;
05717       int nx0=x0, ny0=y0, nz0=z0, nx1=x1, ny1=y1, nz1=z1;
05718       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05719       if (nx1<0 || nx0>=dimx()) return *this;
05720       if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; nz0-=nx0*(nz1-nz0)/D; nx0=0; }
05721       if (nx1>=dimx()) { const int d=nx1-dimx(), D=nx1-nx0; ny1+=d*(ny0-ny1)/D; nz1+=d*(nz0-nz1)/D; nx1=dimx()-1;}
05722       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05723       if (ny1<0 || ny0>=dimy()) return *this;
05724       if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; nz0-=ny0*(nz1-nz0)/D; ny0=0; }
05725       if (ny1>=dimy()) { const int d=ny1-dimy(), D=ny1-ny0; nx1+=d*(nx0-nx1)/D; nz1+=d*(nz0-nz1)/D; ny1=dimy()-1;}
05726       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
05727       if (nz1<0 || nz0>=dimz()) return *this;
05728       if (nz0<0) { const int D=nz1-nz0; nx0-=nz0*(nx1-nx0)/D; ny0-=nz0*(ny1-ny0)/D; nz0=0; }
05729       if (nz1>=dimz()) { const int d=nz1-dimz(), D=nz1-nz0; nx1+=d*(nx0-nx1)/D; ny1+=d*(ny0-ny1)/D; nz1=dimz()-1;}
05730       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),cimg::abs(ny1-ny0),nz1-nz0), whz = width*height*depth;
05731       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, pz = dmax?(nz1-nz0)/(float)dmax:0;
05732       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
05733       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) { 
05734         if (!(~pattern) || (~pattern && pattern&hatch)) {
05735           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
05736           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }        
05737           col-=dim; 
05738         }
05739         x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
05740       } else {
05741         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05742         for (unsigned int t=0; t<=dmax; t++) { 
05743           if (!(~pattern) || (~pattern && pattern&hatch)) {
05744             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
05745             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
05746             col-=dim; 
05747           }
05748           x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));        
05749         }
05750       }
05751       return *this;
05752     }
05753 
05755 
05768     template<typename t> CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
05769                                          const CImg<t>& texture,
05770                                          const int tx0,const int ty0,const int tx1,const int ty1,
05771                                          const float opacity=1) {
05772       cimg_test(*this,"CImg<T>::draw_line"); 
05773       cimg_test(texture,"CImg<T>::draw_line");
05774       if (texture.dim<dim)
05775         throw CImgArgumentException("CImg<%s>::draw_line() : texture has %u channel while image has %u channels",texture.dim,dim);
05776       int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1;
05777       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
05778       if (nx1<0 || nx0>=dimx()) return *this;
05779       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; }
05780       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; }
05781       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
05782       if (ny1<0 || ny0>=dimy()) return *this;
05783       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; }
05784       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; }
05785       const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), 
05786         whz = width*height*depth, twhz = texture.width*texture.height*texture.depth;
05787       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0,
05788         tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0;
05789       float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0;
05790       if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) { 
05791         T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05792         t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
05793         cimg_mapV(*this,k) { *ptrd = (T)(*ptrs); ptrd+=whz; ptrs+=twhz; }
05794         x+=px; y+=py; tx+=tpx; ty+=tpy;
05795       } else {
05796         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05797         for (unsigned int tt=0; tt<=dmax; tt++) { 
05798           T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
05799           t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
05800           cimg_mapV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; }
05801           x+=px; y+=py; tx+=tpx; ty+=tpy;
05802         }
05803       }
05804       return *this;
05805     }
05806 
05808 
05820     CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1,
05821                      const T *const color,
05822                      const float angle=30,const float length=-10,const unsigned int pattern=~0L,const float opacity=1) {
05823       cimg_test(*this,"CImg<T>::draw_arrow");
05824       const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v,
05825         deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
05826         l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
05827       if (sq>0) {
05828         const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg);        
05829         const int 
05830           xl = x1+(int)(l*cl), yl = y1+(int)(l*sl),
05831           xr = x1+(int)(l*cr), yr = y1+(int)(l*sr),
05832           xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2;
05833         draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
05834       } else draw_point(x0,y0,color,opacity);
05835       return *this;
05836     }
05837 
05839 
05848     template<typename t> CImg& draw_image(const CImg<t>& sprite,
05849                                           const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) {
05850       cimg_test(*this,"CImg<T>::draw_image");
05851       cimg_test(sprite,"CImg<T>::draw_image");
05852       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05853       const int 
05854         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05855         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05856         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
05857         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
05858       const t *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
05859         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
05860       const unsigned int
05861         offX = width-lX, soffX = sprite.width-lX,
05862         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05863         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
05864       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05865       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05866       if (lX>0 && lY>0 && lZ>0 && lV>0)
05867         for (int v=0; v<lV; v++) {
05868           for (int z=0; z<lZ; z++) {
05869             for (int y=0; y<lY; y++) {
05870               if (opacity>=1) for (int x=0; x<lX; x++) *(ptrd++) = (T)(*(ptrs++));
05871               else for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
05872               ptrd+=offX; ptrs+=soffX;
05873             }
05874             ptrd+=offY; ptrs+=soffY;
05875           }
05876           ptrd+=offZ; ptrs+=soffZ;
05877         }
05878       return *this;
05879     }
05880 
05881     // Add template overloading for VC++>=7.1
05882 #if ( !defined(_MSC_VER) || _MSC_VER>1300 )
05883     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) {
05884       cimg_test(*this,"CImg<T>::draw_image");
05885       cimg_test(sprite,"CImg<T>::draw_image");
05886       if (this==&sprite) return draw_image(CImg<T>(sprite),x0,y0,z0,v0,opacity);
05887       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05888       const int 
05889         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05890         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05891         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
05892         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
05893       const T *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
05894         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
05895       const unsigned int
05896         offX = width-lX, soffX = sprite.width-lX,
05897         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05898         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ),
05899         slX = lX*sizeof(T);    
05900       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
05901       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05902       if (lX>0 && lY>0 && lZ>0 && lV>0)
05903         for (int v=0; v<lV; v++) {
05904           for (int z=0; z<lZ; z++) {
05905             if (opacity>=1) for (int y=0; y<lY; y++) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
05906             else for (int y=0; y<lY; y++) {
05907               for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
05908               ptrd+=offX; ptrs+=soffX;
05909             }
05910             ptrd+=offY; ptrs+=soffY;
05911           }
05912           ptrd+=offZ; ptrs+=soffZ;
05913         }
05914       return *this;
05915     }
05916 #endif
05917 
05919 
05932     template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite,const CImg<tm>& mask,
05933                                                        const int x0=0,const int y0=0,const int z0=0,const int v0=0,
05934                                                        const tm mask_valmax=1,const float opacity=1) {
05935       cimg_test(*this,"CImg<T>::draw_image");
05936       cimg_test(sprite,"CImg<T>::draw_image");
05937       cimg_test(mask,"CImg<T>::draw_image");
05938       if ((void*)this==(void*)&sprite) return draw_image(CImg<T>(sprite),mask,x0,y0,z0,v0);
05939       if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
05940         throw CImgArgumentException("CImg<%s>::draw_image() : mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
05941                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
05942       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
05943       const int
05944         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
05945         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
05946         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),      
05947         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);    
05948       const int coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-
05949         (bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
05950         ssize = mask.dimx()*mask.dimy()*mask.dimz();
05951       const ti *ptrs = sprite.ptr() + coff;
05952       const tm *ptrm = mask.ptr() + coff;
05953       const unsigned int
05954         offX = width-lX, soffX = sprite.width-lX,
05955         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
05956         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
05957       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
05958       if (lX>0 && lY>0 && lZ>0 && lV>0)
05959         for (int v=0; v<lV; v++) {
05960           ptrm = mask.data + (ptrm - mask.data)%ssize;
05961           for (int z=0; z<lZ; z++) {
05962             for (int y=0; y<lY; y++) {
05963               for (int x=0; x<lX; x++) {
05964                 const float mopacity = *(ptrm++)*opacity,
05965                   nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f);
05966                 *ptrd = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax);
05967                 ptrd++;
05968               }
05969               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
05970             }
05971             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
05972           }
05973           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
05974         }
05975       return *this;
05976     }
05977 
05979 
05992     CImg& draw_rectangle(const int x0,const int y0,const int z0,const int v0,
05993                          const int x1,const int y1,const int z1,const int v1,
05994                          const T& val,float opacity=1) {
05995       cimg_test(*this,"CImg<T>::draw_rectangle");
05996       const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1);
05997       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;
05998       const int 
05999         lX = (1+nx1-nx0) + (nx1>=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0),
06000         lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0),
06001         lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0),
06002         lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0);
06003       const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ);
06004       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06005       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
06006       if (lX>0 && lY>0 && lZ>0 && lV>0)
06007         for (int v=0; v<lV; v++) {
06008           for (int z=0; z<lZ; z++) {
06009             for (int y=0; y<lY; y++) {
06010               if (opacity>=1) {
06011                 if (sizeof(T)!=1) { for (int x=0; x<lX; x++) *(ptrd++) = val; ptrd+=offX; }
06012                 else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
06013               } else { for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ptrd++; } ptrd+=offX; }
06014             }
06015             ptrd+=offY;
06016           }
06017           ptrd+=offZ;
06018         }  
06019       return *this;
06020     }
06021 
06023 
06034     CImg& draw_rectangle(const int x0,const int y0,const int z0,
06035                          const int x1,const int y1,const int z1,
06036                          const T *const color,const float opacity=1) {
06037       if (!color) throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",pixel_type());
06038       cimg_mapV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
06039       return *this;
06040     }
06041 
06043 
06052     CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1,
06053                          const T *const color,const float opacity=1) {
06054       draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
06055       return *this;
06056     }
06057   
06059 
06070     CImg& draw_triangle(const int x0,const int y0,
06071                         const int x1,const int y1,
06072                         const int x2,const int y2,
06073                         const T *const color, const float opacity=1) {
06074       draw_scanline(color,opacity);
06075       int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2;
06076       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
06077       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
06078       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
06079       if (ny0>=dimy() || ny2<0) return *this;
06080       const float 
06081         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
06082         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
06083         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1);
06084       float xleft = (float)nx0, xright = xleft, pleft = (p1<p2)?p1:p2, pright = (p1<p2)?p2:p1;
06085       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; }
06086       const int ya = ny1>dimy()?height:ny1;
06087       for (int y=ny0<0?0:ny0; y<ya; y++) { draw_scanline((int)xleft,(int)xright,y,color,opacity); xleft+=pleft; xright+=pright; }
06088       if (p1<p2) { xleft=(float)nx1;  pleft=p3;  if (ny1<0) xleft-=ny1*pleft; } 
06089       else       { xright=(float)nx1; pright=p3; if (ny1<0) xright-=ny1*pright; }
06090       const int yb = ny2>=dimy()?height-1:ny2;
06091       for (int yy=ny1<0?0:ny1; yy<=yb; yy++) { draw_scanline((int)xleft,(int)xright,yy,color,opacity); xleft+=pleft; xright+=pright; }
06092       return *this;
06093     }
06094   
06096 
06113     template<typename t> CImg& draw_triangle(const int x0,const int y0,
06114                                              const int x1,const int y1,
06115                                              const int x2,const int y2,
06116                                              const CImg<t>& texture,
06117                                              const int tx0,const int ty0,
06118                                              const int tx1,const int ty1,
06119                                              const int tx2,const int ty2,
06120                                              const float opacity=1) {
06121       cimg_test(*this,"CImg<T>::draw_triangle"); 
06122       cimg_test(texture,"CImg<T>::draw_triangle");
06123       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;
06124       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
06125       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
06126       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
06127       if (ny0>=dimy() || ny2<0) return *this;
06128       const float 
06129         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
06130         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
06131         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1),
06132         tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0,
06133         tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0,
06134         tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0,
06135         tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0,
06136         tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0,
06137         tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0;
06138       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06139       float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,
06140         xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft;
06141       if (p1<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; } 
06142       else       { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; }
06143       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft;
06144         txright-=ny0*tpxright; tyright-=ny0*tpyright; }
06145       const int ya = ny1<dimy()?ny1:height;
06146       for (int y=(ny0<0?0:ny0); y<ya; y++) {
06147         const int dx = (int)xright-(int)xleft;
06148         const float
06149           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
06150           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,        
06151           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
06152           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
06153         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
06154         if (xmin<=xmax) {
06155           const int offx=whz-xmax+xmin-1;
06156           T* ptrd = ptr(xmin,y,0,0);
06157           if (opacity>=1) cimg_mapV(*this,k) {
06158             float tx=txi, ty=tyi;
06159             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
06160             ptrd+=offx;
06161           } else cimg_mapV(*this,k) {
06162             float tx=txi, ty=tyi;
06163             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; }
06164             ptrd+=offx;
06165           }
06166         }
06167         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
06168       }
06169 
06170       if (p1<p2) {
06171         xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3;
06172         if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; }
06173       } else { 
06174         xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3;
06175         if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; }
06176       }    
06177       const int yb = ny2>=dimy()?(height-1):ny2;
06178       for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) {
06179         const int dx = (int)xright-(int)xleft;
06180         const float
06181           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
06182           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,        
06183           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
06184           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
06185         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
06186         if (xmin<=xmax) {
06187           const int offx=whz-xmax+xmin-1;
06188           T* ptrd = ptr(xmin,yy,0,0);
06189           if (opacity>=1) cimg_mapV(*this,k) { 
06190             float tx=txi, ty=tyi;
06191             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
06192             ptrd+=offx;
06193           } else cimg_mapV(*this,k) { 
06194             float tx=txi, ty=tyi;
06195             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; }
06196             ptrd+=offx;
06197           }
06198         }
06199         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
06200       }
06201       return *this;
06202     }
06203 
06205 
06216     CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv,
06217                        const T *const color,const unsigned int pattern=0L, const float opacity=1) {
06218       cimg_test(*this,"CImg<T>::draw_ellipse");
06219       draw_scanline(color,opacity);
06220       if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : specified color is (null).",pixel_type());
06221       unsigned int hatch=1;
06222       const float
06223         nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
06224         norm = (float)std::sqrt(ru*ru+rv*rv),
06225         u = norm>0?ru/norm:1,
06226         v = norm>0?rv/norm:0,
06227         rmax = cimg::max(nr1,nr2),
06228         l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2),
06229         l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2),
06230         a = l1*u*u + l2*v*v,
06231         b = u*v*(l1-l2),
06232         c = l1*v*v + l2*u*u;
06233       const int
06234         yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)),
06235         ymin = (y0-yb<0)?0:(y0-yb),
06236         ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb);
06237       int oxmin=0, oxmax=0;
06238       bool first_line = true;
06239       for (int y=ymin; y<=ymax; y++) {
06240         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));
06241         int xmin = (int)(x0-(b*Y+sdelta)/a), xmax = (int)(x0-(b*Y-sdelta)/a);
06242         if (!pattern) draw_scanline(xmin,xmax,y,color,opacity);
06243         else {
06244           if (!(~pattern) || (~pattern && pattern&hatch)) {
06245             if (first_line) { draw_scanline(xmin,xmax,y,color,opacity); first_line = false; }
06246             else {
06247               if (xmin<oxmin) draw_scanline(xmin,oxmin-1,y,color,opacity); 
06248               else draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
06249               if (xmax<oxmax) draw_scanline(xmax,oxmax-1,y,color,opacity); 
06250               else draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity); 
06251             }
06252           }
06253         }
06254         oxmin = xmin; oxmax = xmax;
06255         if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
06256       }
06257       return *this;
06258     }
06259     
06261 
06269     template<typename t> CImg& draw_ellipse(const int x0,const int y0,const CImg<t> &tensor,
06270                                             const T *color,const unsigned int pattern=0L,const float opacity=1) {
06271       CImgl<t> eig = tensor.get_symeigen();
06272       const CImg<t> &val = eig[0], &vec = eig[1];
06273       return draw_ellipse(x0,y0,val(0),val(1),vec(0),vec(1),color,pattern,opacity);
06274     }
06275     
06277 
06285     CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const unsigned int pattern=0L,const float opacity=1) {
06286       return draw_ellipse(x0,y0,r,r,1,0,color,pattern,opacity);
06287     }
06288   
06290 
06301     template<typename t> CImg& draw_text(const char *const text,
06302                                          const int x0,const int y0,
06303                                          const T *const fgcolor,const T *const bgcolor,
06304                                          const CImgl<t>& font,const float opacity=1) {
06305 
06306       cimgl_test(font,"CImg<%s>::draw_text");
06307       if (!text) throw CImgArgumentException("CImg<%s>::draw_text() : NULL string specified as input",pixel_type());
06308       if (!width || !height || !depth || !dim || !data) {
06309         // If needed, pre-compute needed size of the image
06310         int x=0, y=0, w=0;
06311         for (int i=0; i<cimg::strlen(text); i++) {
06312           const unsigned char c = text[i];
06313           switch (c) {
06314           case '\n': y+=font[' '].height; if (x>w) w=x; x=0; break;
06315           case '\t': x+=4*font[' '].width; break;
06316           default: if (c<font.size) x+=font[c].width;
06317           }
06318         }       
06319         if (x!=0) {
06320           if (x>w) w=x;
06321           y+=font[' '].height;
06322         }
06323         (*this) = CImg<T>(x0+w,y0+y,1,font[' '].dim,0);
06324         if (bgcolor) cimg_mapV(*this,k) ref_channel(k).fill(bgcolor[k]);
06325       }
06326 
06327       int x=x0, y=y0;
06328       CImg letter;
06329       for (int i=0; i<cimg::strlen(text); i++) {
06330         const unsigned char c = text[i];
06331         switch (c) {
06332         case '\n': y+=font[' '].height; x=x0; break;
06333         case '\t': x+=4*font[' '].width; break;
06334         default: if (c<font.size) {
06335             letter = font[c];
06336             const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c];
06337             if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) 
06338               if (mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=(T)(letter(p,0,0,k)*fgcolor[k]);
06339             if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++)
06340               if (!mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=bgcolor[k];
06341             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);
06342             x+=letter.width;
06343           }
06344           break;
06345         }
06346       }
06347       return *this;
06348     }
06349 
06350 
06352 
06362     CImg& draw_text(const char *const text,
06363                     const int x0,const int y0,
06364                     const T *const fgcolor=NULL,const T *const bgcolor=NULL,
06365                     const float opacity=1) {
06366       static bool first = true;
06367       static CImgl<T> default_font;
06368       if (first) { default_font = CImgl<T>::get_font7x11(); first = false; }
06369       return draw_text(text,x0,y0,fgcolor,bgcolor,default_font,opacity);
06370     }
06371   
06373 
06383     CImg& draw_text(const int x0,const int y0,
06384                     const T *const fgcolor,const T *const bgcolor,
06385                     const float opacity,const char *format,...) {
06386       char tmp[2048]; 
06387       std::va_list ap;
06388       va_start(ap,format);
06389       std::vsprintf(tmp,format,ap);
06390       va_end(ap);
06391       return draw_text(tmp,x0,y0,fgcolor,bgcolor,opacity);
06392     }
06393     template<typename t> CImg& draw_text(const int x0,const int y0,
06394                                          const T *const fgcolor,const T *const bgcolor,
06395                                          const CImgl<t>& font, const float opacity, const char *format,...) {
06396       char tmp[2048]; std::va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap);
06397       return draw_text(tmp,x0,y0,fgcolor,bgcolor,font);
06398     }
06399   
06401 
06410     template<typename t> 
06411     CImg& draw_quiver(const CImg<t>& flow,const T *const color,const unsigned int sampling=25,const float factor=-20,
06412                       const int quiver_type=0,const float opacity=1) {
06413       cimg_test(*this,"CImg<T>::draw_quiver");
06414       cimg_test(flow,"CImg<T>::draw_quiver");
06415       if (!color) 
06416         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified color is (null)",pixel_type());
06417       if (sampling<=0)
06418         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
06419       if (flow.dim!=2)
06420         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
06421                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
06422       float vmax,fact;
06423       if (factor<=0) {
06424         CImgStats st(flow.get_norm_pointwise(2),false);
06425         vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
06426         fact = -factor;
06427       } else { fact = factor; vmax = 1; }
06428 
06429       for (unsigned int y=sampling/2; y<height; y+=sampling)
06430         for (unsigned int x=sampling/2; x<width; x+=sampling) {
06431           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
06432           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
06433           if (!quiver_type) {
06434             const int xx = x+(int)u, yy = y+(int)v;
06435             draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,~0L,opacity);
06436           } 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);
06437         }
06438       return *this; 
06439     }
06440 
06442 
06451     template<typename t1,typename t2>
06452       CImg& draw_quiver(const CImg<t1>& flow,const CImg<t2>& color,const unsigned int sampling=25,const float factor=-20,
06453                         const int quiver_type=0,const float opacity=1) {
06454       cimg_test(*this,"CImg<T>::draw_quiver"); 
06455       cimg_test(flow,"CImg<T>::draw_quiver");
06456       cimg_test(color,"CImg<T>::draw_quiver");
06457       if (sampling<=0)
06458         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
06459       if (flow.dim!=2)
06460         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
06461                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
06462       if (color.width!=flow.width || color.height!=flow.height)
06463         throw CImgArgumentException("CImg<%s>::draw_quiver() : input color data map=(%u,%u,%u,%u)\
06464  and data flow=(%u,%u,%u,%u) must have same dimension.",
06465                                     color.width,color.height,color.depth,color.data,
06466                                     flow.width,flow.height,flow.depth,flow.data);
06467       float vmax,fact;
06468       if (factor<=0) {
06469         CImgStats st(flow.get_norm_pointwise(2),false);
06470         vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
06471         fact = -factor;
06472       } else { fact = factor; vmax = 1; }
06473 
06474       for (unsigned int y=sampling/2; y<height; y+=sampling)
06475         for (unsigned int x=sampling/2; x<width; x+=sampling) {
06476           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
06477           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
06478           if (!quiver_type) {
06479             const int xx = x+(int)u, yy = y+(int)v;
06480             draw_arrow(x,y,xx,yy,color.get_vector(X,Y).data,45,sampling/5,~0L,opacity);
06481           } 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);
06482         }
06483       return *this; 
06484     }
06485 
06487 
06501     template<typename t>
06502     CImg& draw_graph(const CImg<t>& data,const T *const color,const unsigned int gtype=0,
06503                      const double ymin=0,const double ymax=0,const float opacity=1) {
06504       cimg_test(*this,"CImg<T>::draw_graph");
06505       if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : specified color is (null)",pixel_type());
06506       T *color1 = new T[dim], *color2 = new T[dim];
06507       cimg_mapV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); }
06508       CImgStats st;
06509       if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; }
06510       if (st.min==st.max) { st.min--; st.max++; }
06511       const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min;
06512       const int Y0 = (int)(-cb/ca);
06513       int pY=0;
06514       cimg_mapoff(data,off) {     
06515         const int Y = (int)((data[off]-cb)/ca);
06516         switch (gtype) {
06517         case 0: // plot with segments
06518           if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity);
06519           break;
06520         case 1: { // plot with bars
06521           const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1;
06522           draw_rectangle(X,(int)Y0,nX,Y,color1,opacity);
06523           draw_line(X,Y,X,(int)Y0,color2,~0L,opacity);
06524           draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity);
06525           draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity);
06526           draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity);
06527         } break;
06528         }        
06529         pY=Y;
06530       }
06531       if (gtype==2) { // plot with cubic interpolation
06532         const CImgROI<t> ndata(data.size(),1,1,1,data.ptr());
06533         cimg_mapX(*this,x) {
06534           const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca);
06535           if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity);
06536           pY=Y;
06537         }
06538       }
06539       delete[] color1; delete[] color2;
06540       return *this;     
06541     }
06542 
06544 
06554     CImg& draw_axeX(const double x0,const double x1,const int y,const T *const color,
06555                     const double precision=0,const float opacity=1) {
06556       if (x0==x1) return *this;
06557       if (x0<x1) draw_arrow(0,y,width-1,y,color,30,5,~0L,opacity);
06558       else draw_arrow(width-1,y,0,y,color,30,5,~0L,opacity);
06559       const int yt = (y+14)<dimy()?(y+3):(y-14);
06560       double nprecision=precision;
06561       if (precision<=0) { 
06562         const double nb_pow = std::floor(std::log10(cimg::abs(x1-x0)))-1;
06563         nprecision = std::pow(10.0,nb_pow);
06564         while ((cimg::abs(x1-x0)/nprecision)>(dimx()/40)) nprecision*=2;
06565       }
06566       const double xmin=x0<x1?x0:x1, xmax=x0<x1?x1:x0,
06567         tx0 = cimg::mod(xmin,nprecision)==0?xmin:((xmin+nprecision)-cimg::mod(xmin+nprecision,nprecision)),
06568         tx1 = cimg::mod(xmax,nprecision)==0?xmax:((xmax+nprecision)-cimg::mod(xmax+nprecision,nprecision));
06569       char txt[32];
06570       for (double x=tx0; x<=tx1; x+=nprecision) {
06571         std::sprintf(txt,"%g",x);               
06572         const int xi=(int)((x-x0)*(width-1)/(x1-x0)), xt = xi-(int)std::strlen(txt)*3;
06573         draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
06574           draw_text(txt,xt<0?0:xt,yt,color,NULL,opacity);
06575       }
06576       return *this;
06577     }
06578 
06580 
06590     CImg& draw_axeY(const int x,const double y0,const double y1,const T *const color,
06591                     const double precision=0,const float opacity=1) {
06592       if (y0==y1) return *this;
06593       if (y0<y1) draw_arrow(x,0,x,height-1,color,30,5,~0L,opacity);
06594       else draw_arrow(x,height-1,x,0,color,30,5,~0L,opacity);
06595       double nprecision=precision;
06596       if (precision<=0) {
06597         const double nb_pow = std::floor(std::log10(cimg::abs(y1-y0)))-1;
06598         nprecision = std::pow(10.0,nb_pow);
06599         while ((cimg::abs(y1-y0)/nprecision)>(dimy()/40)) nprecision*=2;
06600       }
06601       const double ymin=y0<y1?y0:y1, ymax=y0<y1?y1:y0,
06602         ty0 = cimg::mod(ymin,nprecision)==0?ymin:((ymin+nprecision)-cimg::mod(ymin+nprecision,nprecision)),
06603         ty1 = cimg::mod(ymax,nprecision)==0?ymax:((ymax+nprecision)-cimg::mod(ymax+nprecision,nprecision));
06604       char txt[32];
06605       for (double y=ty0; y<=ty1; y+=nprecision) {
06606         std::sprintf(txt,"%g",y);
06607         const int yi = (int)((y-y0)*(height-1)/(y1-y0)), xt = x-(int)std::strlen(txt)*7;
06608         draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
06609         if (xt>0) draw_text(txt,xt,yi-5,color,NULL,opacity);
06610         else draw_text(txt,x+3,yi-5,color,NULL,opacity);
06611       }
06612       return *this;
06613     }
06614 
06616 
06628     CImg& draw_axeXY(const double x0,const double x1,const double y0,const double y1,const T *const color,
06629                      const double precisionx=0,const double precisiony=0,const float opacity=1) {
06630       if (x0*x1<=0) {
06631         const int xz = (int)(-x0*(width-1)/(x1-x0));
06632         if (xz>=0 && xz<dimx()) draw_axeY(xz,y0,y1,color,precisiony,opacity);
06633       }
06634       if (y0*y1<=0) {
06635         const int yz = (int)(-y0*(height-1)/(y1-y0));
06636         if (yz>=0 && yz<dimy()) draw_axeX(x0,x1,yz,color,precisionx,opacity);
06637       }
06638       return *this;
06639     }
06640   
06641     // Local class used by function CImg<>::draw_fill()
06642     template<typename T1,typename T2> struct _draw_fill {
06643       const T1 *const color;
06644       const float sigma,opacity;
06645       const CImg<T1> value;
06646       CImg<T2> region;
06647 
06648       _draw_fill(const CImg<T1>& img,const int x,const int y,const int z,
06649                  const T *const pcolor,const float psigma,const float popacity):
06650         color(pcolor),sigma(psigma),opacity(popacity),
06651         value(img.get_vector(x,y,z)), region(CImg<T2>(img.width,img.height,img.depth,1,(T2)false)) {
06652         cimg_test(img,"CImg<T>::draw_fill");
06653         if (!color) throw CImgArgumentException("CImg<%s>::draw_fill() : specified color is (null)",img.pixel_type());
06654       }
06655 
06656            _draw_fill& operator=(const _draw_fill& d) {
06657                         color = d.color;
06658                         sigma = d.sigma;
06659                         opacity = d.opacity;
06660                         value = d.value;
06661                         region = d.region;
06662                 }
06663 
06664       bool comp(const CImg<T1>& A,const CImg<T1>& B) const {
06665         bool res=true;
06666         const T *pA=A.data+A.size();
06667         for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) );
06668         return res;
06669       }
06670 
06671       void fill(CImg<T1>& img,const int x,const int y,const int z) {
06672         if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return;
06673         if (!region(x,y,z) && comp(value,img.get_vector(x,y,z))) {
06674           const T *col=color;
06675           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06676           int xmin,xmax;
06677           if (opacity>=1) cimg_mapV(img,k) img(x,y,z,k)=*(col++);
06678           else cimg_mapV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k));
06679           col-=img.dim;
06680           region(x,y,z) = (T2)true;
06681           for (xmin=x-1; xmin>=0 && comp(value,img.get_vector(xmin,y,z)); xmin--) {
06682             if (opacity>=1) cimg_mapV(img,k) img(xmin,y,z,k) = *(col++);
06683             else cimg_mapV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k)); 
06684             col-=img.dim;
06685             region(xmin,y,z)=(T2)true;
06686           }
06687           for (xmax=x+1; xmax<img.dimx() && comp(value,img.get_vector(xmax,y,z)); xmax++) {
06688             if (opacity>=1) cimg_mapV(img,k) img(xmax,y,z,k) = *(col++);
06689             else cimg_mapV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k));
06690             col-=img.dim;
06691             region(xmax,y,z)=(T2)true; 
06692           }
06693           xmin++; xmax--;
06694           for (; xmin<=xmax; xmin++) { 
06695             fill(img,xmin,y-1,z); 
06696             fill(img,xmin,y+1,z);
06697             fill(img,xmin,y,z-1); 
06698             fill(img,xmin,y,z+1);
06699           }
06700         }
06701       }        
06702     };
06703 
06705 
06716     template<typename t> CImg& draw_fill(const int x,const int y,const int z,
06717                                          const T *const color, CImg<t>& region,const float sigma=0,
06718                                          const float opacity=1) {
06719       _draw_fill<T,t> F(*this,x,y,z,color,sigma,opacity);
06720       F.fill(*this,x,y,z);
06721       region = F.region;
06722       return *this;
06723     }
06724 
06726 
06734     CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) {
06735       CImg<bool> tmp;
06736       return draw_fill(x,y,z,color,tmp,sigma,opacity);
06737     }
06738 
06740 
06747     CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) {      
06748       CImg<bool> tmp;
06749       return draw_fill(x,y,0,color,tmp,sigma,opacity);
06750     }
06751 
06753 
06762     CImg& draw_plasma(const int x0,const int y0,const int x1,const int y1,
06763                       const double alpha=1.0,const double beta=1.0,const float opacity=1) {
06764       cimg_test(*this,"CImg<T>::draw_plasma");
06765       int nx0=x0,nx1=x1,ny0=y0,ny1=y1;
06766       if (nx1<nx0) cimg::swap(nx0,nx1);
06767       if (ny1<ny0) cimg::swap(ny0,ny1);
06768       if (nx0<0) nx0=0;
06769       if (nx1>=dimx()) nx1=width-1;
06770       if (ny0<0) ny0=0;
06771       if (ny1>=dimy()) ny1=height-1;
06772       const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0);
06773       const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta;
06774       cimg_mapV(*this,k) {
06775         if (opacity>=1) {
06776           (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k)));
06777           (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k)));
06778           (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k)));
06779           (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k)));
06780           (*this)(xc,yc,0,k)  = (T)(0.25*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
06781                                           (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand());
06782         } else {
06783           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06784           (*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));
06785           (*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));
06786           (*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));
06787           (*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));
06788           (*this)(xc,yc,0,k)  = (T)(0.25*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
06789                                            (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity
06790                                     + copacity*(*this)(xc,yc,0,k));
06791         }
06792       }
06793       if (xc!=nx0 || yc!=ny0) { 
06794         draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
06795         draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
06796         draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
06797         draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity); 
06798       }
06799       return *this;
06800     }
06801 
06803 
06808     CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) {
06809       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
06810     }
06811   
06813 
06819     CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) {
06820       cimg_test(*this,"CImg<T>::draw_gaussian");
06821       const double sigma2 = 2*sigma*sigma;
06822       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06823       const unsigned int whz = width*height*depth;
06824       const T *col = color;
06825       cimg_mapX(*this,x) {
06826         const float dx = (x-xc);
06827         const double val = std::exp( -dx*dx/sigma2 );
06828         T *ptrd = ptr(x,0,0,0);
06829         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06830         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } 
06831         col-=dim;
06832       }
06833       return *this;
06834     }
06835 
06837 
06844     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const CImg<t>& tensor,
06845                                              const T *const color,const float opacity=1) {
06846       cimg_test(*this,"CImg<T>::draw_gaussian"); 
06847       if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1) 
06848         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 2x2 matrix,"
06849                                     "given is (%u,%u,%u,%u)",
06850                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
06851       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
06852       const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1);
06853       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06854       const unsigned int whz = width*height*depth;
06855       const T *col = color;
06856       cimg_mapXY(*this,x,y) {
06857         const float dx = (x-xc), dy = (y-yc);
06858         const double val = std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
06859         T *ptrd = ptr(x,y,0,0);
06860         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06861         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
06862         col-=dim;
06863       }
06864       return *this;
06865     }
06866 
06868 
06875     CImg& draw_gaussian(const float xc,const float yc,const float sigma,const T *const color,const float opacity=1) {
06876       return draw_gaussian(xc,yc,CImg<float>::diagonal(sigma,sigma),color,opacity);
06877     }
06878     
06880 
06888     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg<t>& tensor,
06889                                              const T *const color,const float opacity=1) {
06890       cimg_test(*this,"CImg<T>::draw_gaussian");
06891       if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
06892         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 3x3 matrix,"
06893                                     "given is (%u,%u,%u,%u)",
06894                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
06895       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
06896       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);
06897       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
06898       const unsigned int whz = width*height*depth; 
06899       const T *col = color;
06900       cimg_mapXYZ(*this,x,y,z) {
06901         const float dx = (x-xc), dy = (y-yc), dz = (z-zc);
06902         const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
06903         T *ptrd = ptr(x,y,z,0);
06904         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
06905         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
06906         col-=dim;
06907       }
06908       return *this;
06909     }
06910     
06912 
06920     CImg& draw_gaussian(const float xc,const float yc,const float zc,
06921                         const double sigma,const T *const color,const float opacity=1) {
06922       return draw_gaussian(xc,yc,zc,CImg<float>::diagonal(sigma,sigma,sigma),color,opacity);
06923     }
06924     
06926     //---------------------------------------
06927     //---------------------------------------
06928     //
06930 
06931     //---------------------------------------
06932     //---------------------------------------
06933   
06935 
06944     template<typename t> CImg get_correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) const {
06945       cimg_test_scalar(mask,"CImg<T>::get_correlate");
06946       CImg dest(*this,false);
06947       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
06948         // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1)
06949         switch (mask.depth) {
06950         case 3: {
06951           CImg_3x3x3(I,T);
06952           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);
06953           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
06954             const double norm = (double)cimg_squaresum3x3x3(I);
06955             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0;
06956           }
06957         } break;
06958         case 2: {
06959           CImg_2x2x2(I,T);
06960           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);
06961           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
06962             const double norm = (double)cimg_squaresum2x2x2(I);
06963             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0;
06964           }
06965         } break;
06966         default:
06967         case 1:
06968           switch (mask.width) {
06969           case 5: {
06970             CImg_5x5(I,T);
06971             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);
06972             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
06973               const double norm = (double)cimg_squaresum5x5(I);
06974               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0;
06975             }            
06976           } break;          
06977           case 4: {
06978             CImg_4x4(I,T);
06979             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);
06980             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
06981               const double norm = (double)cimg_squaresum4x4(I);
06982               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0;
06983             }            
06984           } break;              
06985           case 3: {
06986             CImg_3x3(I,T);
06987             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);
06988             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
06989               const double norm = (double)cimg_squaresum3x3(I);
06990               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0;
06991             }            
06992           } break;   
06993           case 2: {
06994             CImg_2x2(I,T);
06995             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);
06996             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
06997               const double norm = (double)cimg_squaresum2x2(I);
06998               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0;
06999             }            
07000           } break;  
07001           case 1: dest = mask(0)*(*this); break;
07002           }
07003         }
07004       } else { 
07005         // Generic version for other masks      
07006         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);
07007         cimg_mapV(*this,v) 
07008           if (!weighted_correl) {       // Classical correlation
07009             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07010               double val = 0;
07011               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07012                 val+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07013               dest(x,y,z,v)=(T)val;
07014             }
07015             if (cond) cimg_mapYZV(*this,y,z,v)
07016               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))) {
07017                 double val = 0;
07018                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07019                   val+= neumann_pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07020                 dest(x,y,z,v)=(T)val;
07021               }
07022             else cimg_mapYZV(*this,y,z,v)
07023               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))) {
07024                 double val = 0;
07025                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
07026                   val+= dirichlet_pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
07027                 dest(x,y,z,v)=(T)val;
07028               }
07029           } else {      // Weighted correlation
07030             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07031               double val = 0, norm = 0;
07032               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07033                 const T cval = (*this)(x+xm,y+ym,z+zm,v);
07034                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07035                 norm+= cval*cval;
07036               }
07037               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07038             }
07039             if (cond) cimg_mapYZV(*this,y,z,v)
07040               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))) {
07041                 double val = 0, norm = 0;
07042                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07043                   const T cval = neumann_pix3d(x+xm,y+ym,z+zm,v);
07044                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07045                   norm+=cval*cval;
07046                 }
07047                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07048               }
07049             else cimg_mapYZV(*this,y,z,v)
07050               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))) {
07051                 double val = 0, norm = 0;
07052                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07053                   const T cval = dirichlet_pix3d(x+xm,y+ym,z+zm,v,0);
07054                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07055                   norm+= cval*cval;
07056                 }
07057                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
07058               }
07059           }
07060       }
07061       return dest;
07062     }
07064 
07068     template<typename t> CImg& correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) { 
07069       return get_correlate(mask,cond,weighted_correl).swap(*this); 
07070     }
07071   
07073 
07082     template<typename t> CImg get_convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) const {
07083       cimg_test_scalar(mask,"CImg<T>::get_convolve");
07084       CImg dest(*this,false);
07085       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version
07086         switch (mask.depth) {
07087         case 3: {
07088           CImg_3x3x3(I,T);
07089           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);
07090           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
07091             const double norm = (double)cimg_squaresum3x3x3(I);
07092             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):(T)0;
07093           }
07094         } break;
07095         case 2: {
07096           CImg_2x2x2(I,T);
07097           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);
07098           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
07099             const double norm = (double)cimg_squaresum2x2x2(I);
07100             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):(T)0;
07101           }
07102         } break;
07103         default:
07104         case 1:
07105           switch (mask.width) {
07106           case 5: {
07107             CImg_5x5(I,T);
07108             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);
07109             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
07110               const double norm = (double)cimg_squaresum5x5(I);
07111               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv5x5(I,mask)/std::sqrt(norm)):(T)0;
07112             }            
07113           } break;          
07114           case 4: {
07115             CImg_4x4(I,T);
07116             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);
07117             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
07118               const double norm = (double)cimg_squaresum4x4(I);
07119               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv4x4(I,mask)/std::sqrt(norm)):(T)0;
07120             }
07121           } break;              
07122           case 3: {
07123             CImg_3x3(I,T);
07124             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);
07125             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
07126               const double norm = (double)cimg_squaresum3x3(I);
07127               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3(I,mask)/std::sqrt(norm)):(T)0;
07128             }            
07129           } break;   
07130           case 2: {
07131             CImg_2x2(I,T);
07132             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);
07133             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
07134               const double norm = (double)cimg_squaresum2x2(I);
07135               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2(I,mask)/std::sqrt(norm)):(T)0;
07136             } 
07137           } break;  
07138           case 1: dest = mask(0)*(*this); break;
07139           }
07140         }
07141       } else { // generic version
07142           
07143         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);
07144         cimg_mapV(*this,v) 
07145           if (!weighted_convol) {       // Classical convolution
07146             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07147               double val = 0;
07148               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07149                 val+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07150               dest(x,y,z,v)=(T)val;
07151             }
07152             if (cond) cimg_mapYZV(*this,y,z,v)
07153               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))) {
07154                 double val = 0;
07155                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
07156                   val+= neumann_pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
07157                 dest(x,y,z,v)=(T)val;
07158               }
07159             else cimg_mapYZV(*this,y,z,v)
07160               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))) {
07161                 double val = 0;
07162                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
07163                   val+= dirichlet_pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
07164                 dest(x,y,z,v)=(T)val;
07165               }
07166           } else {      // Weighted convolution
07167             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
07168               double val = 0, norm = 0;
07169               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07170                 const T cval = (*this)(x-xm,y-ym,z-zm,v);
07171                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07172                 norm+= cval*cval;
07173               }
07174               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07175             }
07176             if (cond) cimg_mapYZV(*this,y,z,v)
07177               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))) {
07178                 double val = 0, norm = 0;
07179                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
07180                   const T cval = neumann_pix3d(x-xm,y-ym,z-zm,v);
07181                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07182                   norm+=cval*cval;
07183                 }
07184                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07185               }
07186             else cimg_mapYZV(*this,y,z,v)
07187               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))) {
07188                 double val = 0, norm = 0;
07189                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++) {
07190                   const T cval = dirichlet_pix3d(x-xm,y-ym,z-zm,v,0);
07191                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
07192                   norm+= cval*cval;
07193                 }
07194                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
07195               }
07196           }
07197       }
07198       return dest;
07199     }
07200   
07202 
07206     template<typename t> CImg& convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) {
07207       return get_convolve(mask,cond,weighted_convol).swap(*this); 
07208     }
07209 
07211 
07215     CImg& noise(const double sigma=-20,const unsigned int ntype=0) {
07216       cimg_test(*this,"CImg<T>::noise");
07217       T tmp;
07218       double nsigma = sigma, max = (double)cimg::get_type_max(tmp), min = (double)cimg::get_type_min(tmp);
07219       static bool first_time = true;
07220       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
07221       CImgStats st;
07222       if (nsigma==0) return *this;
07223       if (nsigma<0 || ntype==2) st = CImgStats(*this,false);
07224       if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0;
07225       switch (ntype) {
07226       case 0: { // Gaussian noise
07227         cimg_map(*this,ptr,T) {
07228           double val = *ptr+nsigma*cimg::grand(); 
07229           if (val>max) val = max;
07230           if (val<min) val = min;
07231           *ptr = (T)val;
07232         }
07233       } break;
07234       case 1: { // Uniform noise
07235         cimg_map(*this,ptr,T) {
07236           double val = *ptr+nsigma*cimg::crand();
07237           if (val>max) val = max;
07238           if (val<min) val = min;
07239           *ptr = (T)val;
07240         }
07241       } break;
07242       case 2: { // Salt & Pepper noise
07243         if (st.max==st.min) { st.min=0; st.max=255; }
07244         cimg_map(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr=(T)(cimg::rand()<0.5?st.max:st.min);
07245       } break;
07246       }
07247       return *this;
07248     }
07249     
07251 
07256     CImg get_noise(const double sigma=-20,const unsigned int ntype=0) const { return CImg<T>(*this).noise(sigma,ntype); }
07257 
07258 
07259 #define cimg_deriche_map(x0,y0,z0,k0,nb,offset,T) {                           \
07260     ima = ptr(x0,y0,z0,k0);                                                   \
07261     I2 = *ima; ima+=offset; I1 = *ima; ima+=offset;                           \
07262     Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2;                   \
07263     for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset;                          \
07264         Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2;                          \
07265         I2=I1; Y2=Y1; Y1=Y0; }                                                \
07266     ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \
07267     ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1);                            \
07268     for (i=(nb)-3; i>=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset;      \
07269       I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; }                    \
07270   }
07271 
07273 
07277     CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) {
07278       cimg_test(*this,"CImg<T>::deriche");
07279       if (sigma<0 || order<0 || order>2)
07280         throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order);
07281       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;
07282       float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0;
07283       double *Y,Y0,Y1,Y2;
07284       int i,offset,nb;
07285       T *ima,I1,I2;
07286       switch(order) {
07287       case 1:                 // first derivative
07288         ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0;  a2 = ek*ema; a3 = -ek*ema; parity =-1;\
07289         if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } \
07290         else g0 = sumg0 = sumg1 = 0;
07291         break;
07292       case 2:               // second derivative
07293         ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
07294         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;
07295         if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; }
07296         else g0=sumg0=sumg1=0;
07297         break;
07298       default:              // smoothing
07299         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;
07300         if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; }
07301         else  g0=sumg0=sumg1=0;
07302         break;
07303       }
07304       // filter init
07305       Y = new double[cimg::max(width,height,depth)];
07306       switch(cimg::uncase(axe)) {
07307       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;
07308       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;
07309       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;
07310       default: throw CImgArgumentException("CImg<%s>::deriche() : unknow axe '%c', must be 'x','y' or 'z'",pixel_type(),axe);
07311       }
07312       delete[] Y;
07313       return *this;
07314     }
07316 
07321     CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const {
07322       return CImg<T>(*this).deriche(sigma,order,axe,cond);
07323     }
07324 
07326 
07330     CImg& blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) {
07331       cimg_test(*this,"CImg<T>::blur");
07332       if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
07333       if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
07334       if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
07335       return *this;
07336     }
07337 
07339     CImg& blur(const float sigma=1,const unsigned int cond=1) { return blur(sigma,sigma,sigma,cond); }
07340 
07342 
07345     CImg get_blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) const {
07346       return CImg<T>(*this).blur(sigmax,sigmay,sigmaz,cond); 
07347     }
07348     
07350     CImg get_blur(const float sigma=1,const unsigned int cond=1) const { return CImg<T>(*this).blur(sigma,cond); }
07351 
07353     template<typename t> 
07354     CImg& blur_anisotropic(const CImg<t>& G, const float amplitude=10.0f, const float dl=0.8f,const float da=45.0f,
07355                            const float gauss_prec=2.0f, const bool linear=false) {
07356       
07357       // Check arguments and init variables
07358       cimg_test(*this,"blur_anisotropic");
07359       cimg_test(G,"blur_anisotropic");
07360       if ((G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
07361         throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Input tensor field G has wrong dimensions (%u,%u,%u,%u).",
07362                                 pixel_type(),G.width,G.height,G.depth,G.dim);
07363       
07364       const int dx1 = dimx()-1, dy1 = dimy()-1, dz1 = dimz()-1;
07365       const bool threed = (G.dim>=6);
07366       CImg<t> dest(width,height,depth,dim,0), tmp(dim), W(width,height,depth,threed?3:2);
07367       int N = 0;
07368       
07369       if (threed)
07370         // 3D version of the algorithm
07371         //-----------------------------
07372         for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
07373           const float phir = phi*cimg::PI/180, datmp = da/std::cos(phir), da2 = datmp<1?360:datmp;
07374           for (float theta=0; theta<360; (theta+=da2),N++) {
07375             const float thetar = theta*cimg::PI/180,
07376               vx = (float)std::cos(thetar)*std::cos(phir),
07377               vy = (float)std::sin(thetar)*std::cos(phir),
07378               vz = (float)std::sin(phir);
07379             const t 
07380               *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2),
07381               *pd = G.ptr(0,0,0,3), *pe = G.ptr(0,0,0,4), *pf = G.ptr(0,0,0,5);
07382             t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2);
07383             cimg_mapXYZ(G,xg,yg,zg) {
07384               const t
07385                 a = *(pa++), b = *(pb++), c = *(pc++),
07386                 d = *(pd++), e = *(pe++), f = *(pf++),
07387                 u = a*vx + b*vy + c*vz,
07388                 v = b*vx + d*vy + e*vz,
07389                 w = c*vx + e*vy + f*vz,
07390                 n = dl/std::sqrt(1e-5+u*u+v*v+w*w);
07391               *(pd0++) = u*n;
07392               *(pd1++) = v*n;
07393               *(pd2++) = w*n;
07394             }
07395 
07396             cimg_mapXYZ(*this,x,y,z) {
07397               tmp.fill(0);
07398               const t cu = W(x,y,z,0), cv = W(x,y,z,1), cw = W(x,y,z,2);
07399               const float
07400                 fsigma = (float)(2*std::sqrt((cu*cu+cv*cv+cw*cw)*amplitude)),
07401                 length = gauss_prec*fsigma,
07402                 fsigma2 = 2*fsigma*fsigma;
07403               float l, S=0, pu=cu, pv=cv, pw=cw, X=(float)x, Y=(float)y, Z=z+cw;
07404               if (linear) for (l=0; l<length; l+=dl) {
07405                 const float coef = (float)std::exp(-l*l/fsigma2);
07406                 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));
07407                 if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; }
07408                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*linear_pix3d(X,Y,Z,k));
07409                 X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S+=coef;
07410               } else for (l=0; l<length; l+=dl) {
07411                 const float 
07412                   coef = (float)std::exp(-l*l/fsigma2),
07413                   Xn = X<0?0:(X>=dx1?dx1:X),
07414                   Yn = Y<0?0:(Y>=dy1?dy1:Y),
07415                   Zn = Z<0?0:(Z>=dz1?dz1:Z);
07416                 const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f), zi = (int)(Zn+0.5f);
07417                 t u = W(xi,yi,zi,0), v = W(xi,yi,zi,1), w = W(xi,yi,zi,2);
07418                 if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; }
07419                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,zi,k));
07420                 X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S+=coef;
07421               }
07422               if (S>0) cimg_mapV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
07423               else cimg_mapV(dest,k) dest(x,y,z,k)+=(t)((*this)(x,y,z,k));
07424             }
07425           }
07426         } else
07427           // 2D version of the algorithm
07428           //-----------------------------
07429           for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),N++) {
07430             const float thetar = theta*cimg::PI/180, vx = std::cos(thetar), vy = std::sin(thetar);
07431 
07432             const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2);
07433             t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1);
07434             cimg_mapXY(G,xg,yg) {
07435               const t
07436                 a = *(pa++), b = *(pb++), c = *(pc++), 
07437                 u = a*vx + b*vy, v = b*vx + c*vy,
07438                 n = dl/std::sqrt(1e-5+u*u+v*v);
07439               *(pd0++) = u*n;
07440               *(pd1++) = v*n;
07441             }
07442         
07443             cimg_mapXY(*this,x,y) {
07444               tmp.fill(0);
07445               const t cu = W(x,y,0,0), cv = W(x,y,0,1);
07446               const float
07447                 fsigma = (float)(2*std::sqrt((cu*cu+cv*cv)*amplitude)),
07448                 length = gauss_prec*fsigma,
07449                 fsigma2 = 2*fsigma*fsigma;
07450               float l, S=0, pu=cu, pv=cv, X=(float)x, Y=(float)y;
07451               if (linear) for (l=0; l<length; l+=dl) {
07452                 const float coef = (float)std::exp(-l*l/fsigma2);
07453                 t u = (t)(W.linear_pix2d(X,Y,0,0)), v = (t)(W.linear_pix2d(X,Y,0,1));
07454                 if ((pu*u+pv*v)<0) { u=-u; v=-v; }
07455                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*linear_pix2d(X,Y,0,k));
07456                 X+=(pu=u); Y+=(pv=v); S+=coef;
07457               } else for (l=0; l<length; l+=dl) {
07458                 const float 
07459                   coef = (float)std::exp(-l*l/fsigma2),
07460                   Xn = X<0?0:(X>=dx1?dx1:X),
07461                   Yn = Y<0?0:(Y>=dy1?dy1:Y);
07462                 const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f);
07463                 t u = W(xi,yi,0,0), v = W(xi,yi,0,1);
07464                 if ((pu*u+pv*v)<0) { u=-u; v=-v; }
07465                 cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,0,k));
07466                 X+=(pu=u); Y+=(pv=v); S+=coef;
07467               }
07468               if (S>0) cimg_mapV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
07469               else cimg_mapV(dest,k) dest(x,y,0,k)+=(t)((*this)(x,y,0,k));
07470             }
07471           }
07472       const float *ptrs = dest.data+dest.size(); cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)/N);
07473       return *this;
07474     }
07475 
07477 
07485     template<typename t>
07486     CImg get_blur_anisotropic(const CImg<t>& G, const float amplitude=10.0f, const float dl=0.8f,const float da=45.0f,
07487                               const float gauss_prec=2.0f, const bool linear=false) const {
07488       return CImg<T>(*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,linear);
07489     }
07490 
07492     CImg& blur_anisotropic(const float amplitude, const float sharpness=1.5f, const float anisotropy=0.7f,
07493                            const float alpha=0.2f,const float sigma=0.8f, const float dl=0.8f,const float da=45.0f,
07494                            const float gauss_prec=2.0f, const bool linear=false) {
07495   
07496       cimg_test(*this,"blur_anisotropic");
07497       const bool threed = (depth>1);
07498       CImg<float> G(width,height,depth,(threed?6:3),0);
07499       const float power1 = 0.5f*sharpness, power2 = (1+anisotropy)/(1e-10+1-anisotropy)*power1;
07500       float nmax = 0;
07501 
07502       if (threed) { // Field for 3D volumes    
07503         CImg<float> val(3),vec(3,3);
07504         CImg_3x3x3(I,float);
07505         CImg<T> blurred = get_blur(alpha);
07506         cimg_mapV(*this,k) cimg_map3x3x3(blurred,x,y,z,k,I) {
07507           const float 
07508             ixf = Incc-Iccc, iyf = Icnc-Iccc, izf = Iccn-Iccc,
07509             ixb = Iccc-Ipcc, iyb = Iccc-Icpc, izb = Iccc-Iccp;
07510           G(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
07511           G(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
07512           G(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
07513           G(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
07514           G(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
07515           G(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
07516         }
07517         G.blur(sigma);
07518         cimg_mapXYZ(*this,x,y,z) {
07519           G.get_tensor(x,y,z).symeigen(val,vec);
07520           const float l1 = val[2], l2 = val[1], l3 = val[0],
07521             ux = vec(2,0), uy = vec(2,1), uz = vec(2,2),
07522             vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
07523             wx = vec(0,0), wy = vec(0,1), wz = vec(0,2),
07524             n1 = (float)(1.0/std::pow(1.0f+l1+l2+l3,power1)),
07525             n2 = (float)(1.0/std::pow(1.0f+l1+l2+l3,power2)),
07526             nm = cimg::max(n1,n2);
07527           G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
07528           G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
07529           G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
07530           G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
07531           G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
07532           G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
07533           if (nm>nmax) nmax = nm;
07534         }
07535       } else { // Field for 2D images
07536         CImg<float> val(2),vec(2,2);
07537         CImg_3x3(I,float);
07538         CImg<T> blurred = get_blur(alpha);
07539         cimg_mapV(*this,k) cimg_map3x3(blurred,x,y,0,k,I) {
07540           const float
07541             ixf = Inc-Icc, iyf = Icn-Icc,
07542             ixb = Icc-Ipc, iyb = Icc-Icp;
07543           G(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
07544           G(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
07545           G(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
07546         }
07547         G.blur(sigma);
07548         cimg_mapXY(*this,x,y) {
07549           G.get_tensor(x,y).symeigen(val,vec);
07550           const float l1 = val[0], l2 = val[1],
07551             ux = vec[0], uy = vec[1],
07552             vx = vec[2], vy = vec[3],
07553             n1 = (float)(1.0/std::pow(1.0f+l1+l2,power1)),
07554             n2 = (float)(1.0/std::pow(1.0f+l1+l2,power2)),
07555             nm = cimg::max(n1,n2);
07556           G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
07557           G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
07558           G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
07559           if (nm>nmax) nmax = nm;
07560         }
07561       }
07562       G/=nmax;
07563       return blur_anisotropic(G,amplitude,dl,da,gauss_prec,linear);
07564     }
07565 
07567 
07577     CImg get_blur_anisotropic(const float amplitude, const float sharpness=1.5f, const float anisotropy=0.7f,
07578                               const float alpha=0.2f, const float sigma=0.8f, const float dl=0.8f,
07579                               const float da=45.0f, const float gauss_prec=2.0f, const bool linear=false) const {
07580   
07581       return CImg<T>(*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,linear);
07582     }
07583 
07585     CImg get_erode(const unsigned int n=1) {
07586       CImg_3x3x3(I,T);
07587       if (n==1) {
07588         CImg dest(*this);
07589         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) 
07590           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) dest(x,y,z,k) = 0;
07591         return dest;
07592       }
07593       CImg img1(*this),img2(*this,false);
07594       CImg *src = &img1, *dest = &img2, *tmp = NULL;
07595       for (unsigned int iter=0; iter<n; iter++) {
07596         *dest = *src;
07597         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I) 
07598           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) (*dest)(x,y,z,k) = 0;
07599         tmp = src;
07600         src = dest;
07601         dest = tmp;
07602       }
07603       return *src;      
07604     }
07605     
07607     CImgl<T> get_FFT(const char axe,const bool inverse=false) const {
07608       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(axe,inverse);      
07609     }
07610 
07612     CImgl<T> get_FFT(const bool inverse=false) const {
07613       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(inverse);      
07614     }
07615 
07617     CImg& erode(const unsigned int n=1) { return get_erode(n).swap(*this); }
07618 
07620     CImg get_dilate(const unsigned int n=1) {
07621       CImgStats stats(*this);
07622       const T tmax = stats.max!=0?(T)stats.max:(T)1;
07623       CImg_3x3x3(I,T);
07624       if (n==1) {
07625         CImg dest(*this);
07626         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) 
07627           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) dest(x,y,z,k) = tmax;
07628         return dest;
07629       }
07630       CImg img1(*this),img2(*this,false);
07631       CImg *src = &img1, *dest = &img2, *tmp = NULL;
07632       for (unsigned int iter=0; iter<n; iter++) {
07633         *dest = *src;
07634         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I) 
07635           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) (*dest)(x,y,z,k) = tmax;
07636         tmp = src;
07637         src = dest;
07638         dest = tmp;
07639       }
07640       return *src;      
07641     }
07643     CImg& dilate(const unsigned int n=1) { return get_dilate(n).swap(*this); }
07644 
07646     //------------------------------------------
07647     //------------------------------------------
07648     //
07650 
07651     //------------------------------------------
07652     //------------------------------------------
07653 
07655     static CImg vector(const T& a1) { return CImg<T>(1,1).fill(a1); }
07656     static CImg vector(const T& a1,const T& a2) { return CImg<T>(1,2).fill(a1,a2); }
07657     static CImg vector(const T& a1,const T& a2,const T& a3) { return CImg<T>(1,3).fill(a1,a2,a3); }
07658     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); }
07659     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); }
07660     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); }
07661     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07662                        const T& a5,const T& a6,const T& a7) { return CImg<T>(1,7).fill(a1,a2,a3,a4,a5,a6,a7); }
07663     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07664                        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); }
07665     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
07666                        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); }
07667 
07669     static CImg matrix(const T& a1) { return vector(a1); }
07670     static CImg matrix(const T& a1,const T& a2,
07671                        const T& a3,const T& a4) { return CImg<T>(2,2).fill(a1,a2,a3,a4); }
07672     static CImg matrix(const T& a1,const T& a2,const T& a3,
07673                        const T& a4,const T& a5,const T& a6,
07674                        const T& a7,const T& a8,const T& a9) { return CImg<T>(3,3).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
07675     static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4,
07676                        const T& a5,const T& a6,const T& a7,const T& a8,
07677                        const T& a9,const T& a10,const T& a11,const T& a12,
07678                        const T& a13,const T& a14,const T& a15,const T& a16) {
07679       return CImg<T>(4,4).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
07680     }
07681 
07683     static CImg tensor(const T& a1) { return matrix(a1); }
07684     static CImg tensor(const T& a1,const T& a2,const T& a3) { return matrix(a1,a2,a2,a3); }
07685     static CImg tensor(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) {
07686       return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
07687     }
07688 
07690     static CImg diagonal(const T& a1) { return matrix(a1); }
07691     static CImg diagonal(const T& a1,const T& a2) { return matrix(a1,0,0,a2); }
07692     static CImg diagonal(const T& a1,const T& a2,const T& a3) { return matrix(a1,0,0,0,a2,0,0,0,a3); }
07693     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); }
07695     template<typename t> CImg operator*(const CImg<t>& img) const {
07696       cimg_test_matrix(*this,"CImg<T>::operator*");
07697       cimg_test_matrix(img,"CImg<T>::operator*");
07698       if (width!=img.height) 
07699         throw CImgArgumentException("CImg<%s>::operator*() : can't multiply a matrix *this = (%ux%u) by a matrix (%ux%u)",
07700                                     pixel_type(),width,height,img.width,img.height);
07701       CImg res(img.width,height);
07702       double val;
07703       cimg_mapXY(res,i,j) { val=0; cimg_mapX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = (T)val; }
07704       return res;
07705     }
07707     template<typename t> CImg& operator*=(const CImg<t>& img) { return ((*this)*img).swap(*this); }
07708   
07710     CImg get_vector(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
07711       CImg dest(dim);
07712       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
07713       return dest;
07714     }
07715   
07717     CImg get_matrix(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
07718       const int n = (int)std::sqrt((double)dim);
07719       CImg dest(n,n);
07720       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
07721       return dest;
07722     }
07723   
07725     CImg get_tensor(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {      
07726       if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
07727                                 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
07728       if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
07729       return tensor((*this)(x,y,z,0));
07730     }
07731 
07733     CImg& set_vector(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07734       return draw_point(x,y,z,vec.data,1);
07735     }
07737     CImg& set_matrix(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07738       return set_vector(mat,x,y,z);
07739     }
07741     CImg& set_tensor(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
07742       if (ten.height==2) {
07743         (*this)(x,y,z,0)=ten[0];
07744         (*this)(x,y,z,1)=ten[1];
07745         (*this)(x,y,z,2)=ten[3];
07746       }
07747       else {
07748         (*this)(x,y,z,0)=ten[0];
07749         (*this)(x,y,z,1)=ten[1];
07750         (*this)(x,y,z,2)=ten[2];
07751         (*this)(x,y,z,3)=ten[4];
07752         (*this)(x,y,z,4)=ten[5];
07753         (*this)(x,y,z,5)=ten[8];
07754       }
07755       return *this;
07756     }
07758     CImg& identity_matrix(const unsigned int N) { return get_identity_matrix(N).swap(*this); }
07759       
07761     static CImg get_identity_matrix(const unsigned int N) {
07762       CImg<T> res(N,N,1,1,0);
07763       cimg_mapX(res,x) res(x,x)=1;
07764       return res;
07765     }
07766   
07768     CImg get_transpose() const {
07769       CImg<T> res(height,width,depth,dim);
07770       cimg_mapXYZV(*this,x,y,z,v) res(y,x,z,v) = (*this)(x,y,z,v);      
07771       return res;
07772     }
07773     
07775     CImg& transpose() {
07776       if (width==1) { width=height; height=1; return *this; }
07777       if (height==1) { height=width; width=1; return *this; }
07778       if (width==height) {
07779         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));
07780         return *this;
07781       }
07782       return (*this)=get_transpose();
07783     }
07784 
07786     CImg get_diagonal() const {
07787       cimg_test(*this,"CImg<T>::get_diagonal");
07788       CImg res(size(),size(),1,1,0);
07789       cimg_mapoff(*this,off) res(off,off)=(*this)(off);
07790       return res;
07791     }
07793     CImg& diagonal() { return get_diagonal().swap(*this); }
07794 
07796     CImg& inverse() {
07797       cimg_test_square(*this,"CImg<T>::inverse");
07798       switch (width) {
07799       case 2: {
07800         const double 
07801           a = data[0], c = data[1],
07802           b = data[2], d = data[3],
07803           dete = det();
07804         if (dete) { 
07805           data[0] = (T)(d/dete);  data[1] = (T)(-c/dete);
07806           data[2] = (T)(-b/dete), data[3] = (T)(a/dete); 
07807         } else {
07808           cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07809           fill(0);
07810         }
07811       } break;
07812       case 3: {
07813         const double
07814           a = data[0], d = data[1], g = data[2],
07815           b = data[3], e = data[4], h = data[5],
07816           c = data[6], f = data[7], i = data[8],
07817           dete = det();
07818         if (dete) {
07819           data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
07820           data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
07821           data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
07822         } else {
07823           cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07824           fill(0);
07825         }
07826       } break;
07827       default: {
07828         CImg<T> U(width,width),S(1,width),V(width,width);
07829         SVD(U,S,V,false);
07830         U.transpose();
07831         cimg_mapY(S,k) if (S[k]!=0) S[k]=1/S[k];
07832         else cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
07833         S.diagonal();
07834         *this = V*S*U;
07835       } break;
07836       }
07837       return *this;
07838     }
07839 
07841     CImg get_inverse() const { return CImg<T>(*this).inverse(); }
07842 
07844     double trace() const {
07845       cimg_test_square(*this,"CImg<T>::trace");
07846       double res=0;
07847       cimg_mapX(*this,k) res+=(*this)(k,k);
07848       return res;
07849     }
07851     double dot(const CImg& img) const {
07852       cimg_test(*this,"CImg<T>::dot"); cimg_test(img,"CImg<T>::dot");
07853       const unsigned long nb = cimg::min(size(),img.size());
07854       double res=0;
07855       for (unsigned long off=0; off<nb; off++) res+=data[off]*img[off];
07856       return res;
07857     }
07858         
07860     CImg& cross(const CImg& img) {
07861       if (width!=1 || height<3 || img.width!=1 || img.height<3)
07862         throw CImgInstanceException("CImg<%s>::cross() : cannot get cross product between two matrices (%u,%u) and (%u,%u)",
07863                                     pixel_type(),width,height,img.width,img.height);
07864       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
07865       (*this)[0] = y*img[2]-z*img[1];
07866       (*this)[1] = z*img[0]-x*img[2];
07867       (*this)[2] = x*img[1]-y*img[0];
07868       return *this;
07869     }
07871     CImg get_cross(const CImg& img) const { return CImg<T>(*this).cross(img); }
07872 
07874     double det() const {
07875       cimg_test_square(*this,"CImg<T>::det");
07876       switch (width) {
07877       case 1: return (*this)(0,0);
07878       case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
07879       case 3: 
07880         {
07881           const double
07882             a = data[0], d = data[1], g = data[2],
07883             b = data[3], e = data[4], h = data[5],
07884             c = data[6], f = data[7], i = data[8];
07885           return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
07886         }
07887       }
07888       return 0;
07889     }
07891     double norm(const int ntype=2) const {
07892       cimg_test(*this,"CImg<T>::norm");
07893       double res = 0;
07894       switch (ntype) {
07895       case -1: {
07896         cimg_mapoff(*this,off) {
07897           const double tmp = cimg::abs((double)data[off]);
07898           if (tmp>res) res = tmp;
07899         }
07900         return res; 
07901       } break;
07902       case 1 : { 
07903         cimg_mapoff(*this,off) res+=cimg::abs((double)data[off]); 
07904         return res;
07905       } break;
07906       default: { return std::sqrt(dot(*this)); }
07907       }
07908       return 0;
07909     }
07911     double sum() const {
07912       cimg_test(*this,"CImg<T>::sum");          
07913       double res=0;
07914       cimg_map(*this,ptr,T) res+=*ptr;
07915       return res;
07916     }
07917 
07919     template<typename t> const CImg& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,const bool sorting=true) const {
07920       cimg_test_matrix(*this,"CImg<T>::SVD");
07921       U = *this;
07922       if (S.size()<width) S = CImg<t>(1,width);
07923       if (V.width<width || V.height<height) V = CImg<t>(width,width);
07924       CImg<t> rv1(width);  
07925       t anorm=0,c,f,g=0,h,s,scale=0;
07926       int l=0,nm=0;
07927      
07928       cimg_mapX(U,i) {
07929         l = i+1; rv1[i] = scale*g; g = s = scale = 0;
07930         if (i<dimy()) {
07931           for (int k=i; k<dimy(); k++) scale+= cimg::abs(U(i,k));
07932           if (scale) {
07933             for (int k=i; k<dimy(); k++) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
07934             f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i)=f-g;
07935             for (int j=l; j<dimx(); j++) {
07936               s = 0; for (int k=i; k<dimy(); k++) s+= U(i,k)*U(j,k);
07937               f = s/h;
07938               { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); }
07939             }
07940             { for (int k=i; k<dimy(); k++) U(i,k)*= scale; }
07941           }
07942         }
07943         S[i]=scale*g;
07944         
07945         g = s = scale = 0;
07946         if (i<dimy() && i!=dimx()-1) {
07947           for (int k=l; k<dimx(); k++) scale += cimg::abs(U(k,i));
07948           if (scale) {
07949             for (int k=l; k<dimx(); k++) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
07950             f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
07951             { for (int k=l; k<dimx(); k++) rv1[k]=U(k,i)/h; }
07952             for (int j=l; j<dimy(); j++) {
07953               s=0; for (int k=l; k<dimx(); k++) s+= U(k,j)*U(k,i);
07954               { for (int k=l; k<dimx(); k++) U(k,j)+= s*rv1[k]; }
07955             }
07956             { for (int k=l; k<dimx(); k++) U(k,i)*= scale; }
07957           }
07958         }
07959         anorm=cimg::max((t)anorm,(cimg::abs(S[i])+cimg::abs(rv1[i])));
07960       }
07961       
07962       { for (int i=dimx()-1; i>=0; i--) {
07963         if (i<dimx()-1) {
07964           if (g) {
07965             { for (int j=l; j<dimx(); j++) V(i,j) =(U(j,i)/U(l,i))/g; }
07966             for (int j=l; j<dimx(); j++) {
07967               s=0; for (int k=l; k<dimx(); k++) s+= U(k,i)*V(j,k);
07968               { for (int k=l; k<dimx(); k++) V(j,k)+= s*V(i,k); }
07969             }
07970           }
07971           for (int j=l; j<dimx(); j++) V(j,i)=V(i,j)=0.0;
07972         }
07973         V(i,i) = 1.0; g = rv1[i]; l = i;
07974       }
07975       }
07976       
07977       { for (int i=cimg::min(dimx(),dimy())-1; i>=0; i--) {
07978         l = i+1; g = S[i];
07979         for (int j=l; j<dimx(); j++) U(j,i) = 0;
07980         if (g) {
07981           g = 1/g;
07982           for (int j=l; j<dimx(); j++) {
07983             s=0; for (int k=l; k<dimy(); k++) s+= U(i,k)*U(j,k);
07984             f = (s/U(i,i))*g;
07985             { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); }
07986           }
07987           { for (int j=i; j<dimy(); j++) U(i,j)*= g; }
07988         } else for (int j=i; j<dimy(); j++) U(i,j)=0;
07989         U(i,i)++;
07990       }
07991       }
07992       
07993       for (int k=dimx()-1; k>=0; k--) {
07994         for (int its=0; its<40; its++) {
07995           bool flag = true;
07996           for (l=k; l>=0; l--) {
07997             nm = l-1;
07998             if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
07999             if ((cimg::abs(S[nm])+anorm)==anorm) break;
08000           }
08001           if (flag) {
08002             c = 0; s = 1;
08003             for (int i=l; i<=k; i++) {
08004               f = s*rv1[i]; rv1[i] = c*rv1[i];
08005               if ((cimg::abs(f)+anorm)==anorm) break;
08006               g = S[i]; h = (t)cimg::pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
08007               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; }
08008             }
08009           }
08010           const t& z = S[k];
08011           if (l==k) { if (z<0) { S[k] = -z; cimg_mapX(U,j) V(k,j) = -V(k,j); } break; }
08012           cimg::warn(its>=39,"CImg<%s>::SVD() : SVD failed to converge",pixel_type());
08013           nm = k-1; 
08014           t x = S[l], y = S[nm]; 
08015           g = rv1[nm]; h = rv1[k];
08016           f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
08017           g = (t)cimg::pythagore(f,1.0);
08018           f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
08019           c = s = 1;
08020           for (int j=l; j<=nm; j++) {
08021             const int i = j+1;
08022             g = rv1[i]; h = s*g; g = c*g;
08023             t y = S[i];
08024             t z = (t)cimg::pythagore(f,h); 
08025             rv1[j] = z; c = f/z; s = h/z;
08026             f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
08027             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; }
08028             z = (t)cimg::pythagore(f,h); S[j] = z;
08029             if (z) { z = 1/z; c = f*z; s = h*z; }
08030             f = c*g+s*y; x = c*y-s*g;
08031             { 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; }}
08032           }
08033           rv1[l] = 0; rv1[k]=f; S[k]=x;
08034         }
08035       }
08036       
08037       if (sorting) {
08038         CImg<int> permutations(width);
08039         S.quicksort(permutations,false);
08040         cimg_mapX(permutations,x) {
08041           const int n = permutations(x);
08042           if (x<n) {
08043             cimg_mapY(U,k) cimg::swap(U(x,k),U(n,k));
08044             cimg_mapY(V,l) cimg::swap(V(x,l),V(n,l));
08045           }
08046         }
08047       }
08048       return *this;
08049     }
08050 
08052     template<typename t> const CImg& SVD(CImgl<t>& USV) const {
08053       if (USV.size<3) USV = CImgl<t>(3);
08054       return SVD(USV[0],USV[1],USV[2]);      
08055     }
08056     
08058     CImgl<T> get_SVD(const bool sorting=true) const {
08059       CImgl<T> res(3);
08060       SVD(res[0],res[1],res[2],sorting);
08061       return res;
08062     }
08063         
08065     template<typename t> const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
08066       cimg_test_square(*this,"CImg<T>::eigen");
08067       if (val.size()<width) val = CImg<t>(1,width);
08068       if (vec.size()<width*width) vec = CImg<t>(width,width);
08069       switch(width) {
08070       case 1: { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
08071       case 2: {
08072         const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
08073         double f = e*e-4*(a*d-b*c);
08074         cimg::warn(f<0,"CImg<%s>::eigen() : Complex eigenvalues",pixel_type());
08075         f = std::sqrt(f);
08076         const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
08077         double u, v, n;
08078         val[0]=(t)l2; val[1]=(t)l1;
08079         if (cimg::abs(b)>cimg::abs(a-l2)) { u = 1; v = (l2-a)/b; }
08080         else { if (a-l2!=0) { u = -b/(a-l2); v = 1; } else { u = 0; v = 1; } }
08081         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec(0,0) = (t)u; vec(0,1) = (t)v;
08082         if (cimg::abs(b)>cimg::abs(a-l1)) { u = 1; v = (l1-a)/b; }
08083         else { if (a-l1!=0) { u = -b/(a-l1); v = 1; } else { u = 1; v = 0; } }
08084         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec(1,0) = (t)u; vec(1,1) = (t)v;
08085       } break;
08086       default: 
08087         throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices "
08088                                     "(given is %ux%u)", pixel_type(),width,height);
08089       }
08090       return *this;
08091     }
08092 
08094     CImgl<T> get_eigen() const { CImgl<T> res(2); eigen(res[0],res[1]); return res; }
08095     
08097     template<typename t> const CImg<T>& eigen(CImgl<t>& eig) const {
08098       if (eig.size<2) eig = CImgl<t>(2);
08099       eigen(eig[0],eig[1]);
08100       return *this; 
08101     }
08102     
08104     template<typename t> const CImg<T>& symeigen(CImg<t>& val, CImg<t>& vec) const {
08105       cimg_test_square(*this,"CImg<T>::symeigen");
08106       if (val.size()<width) val = CImg<t>(width);
08107       if (vec.data && vec.size()<width*width) vec = CImg<t>(width,width);
08108       if (width<3) return eigen(val,vec);     
08109       CImg<t> V(width,width);
08110       return SVD(vec,val,V,true);
08111     }
08112 
08114     CImgl<T> get_symeigen() const { CImgl<T> res(2); symeigen(res[0],res[1]); return res; }
08115 
08117     template<typename t> const CImg<T>& symeigen(CImgl<t>& eig) const {
08118       if (eig.size<2) eig = CImgl<t>(2);
08119       symeigen(eig[0],eig[1]);
08120       return *this;
08121     }
08122 
08123     template<typename t> CImg<T>& _quicksort(const int min,const int max,CImg<t>& permutations,const bool increasing) {
08124       if (min<max) {      
08125         const int mid = (min+max)/2;
08126         if (increasing) {
08127           if ((*this)[min]>(*this)[mid]) {
08128             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08129           if ((*this)[mid]>(*this)[max]) {
08130             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
08131           if ((*this)[min]>(*this)[mid]) {
08132             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08133         } else {
08134           if ((*this)[min]<(*this)[mid]) {
08135             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08136           if ((*this)[mid]<(*this)[max]) {
08137             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
08138           if ((*this)[min]<(*this)[mid]) {
08139             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
08140         }
08141         if (max-min>=3) {
08142           const T pivot = (*this)[mid];
08143           int i = min, j = max;
08144           if (increasing) {
08145             do {
08146               while ((*this)[i]<pivot) i++; while ((*this)[j]>pivot) j--;
08147               if (i<=j) {
08148                 cimg::swap((*this)[i],(*this)[j]);
08149                 cimg::swap(permutations[i],permutations[j]);
08150                 i++; j--; }
08151             } while (i<=j);
08152           } else {
08153             do {
08154               while ((*this)[i]>pivot) i++; while ((*this)[j]<pivot) j--;
08155               if (i<=j) {
08156                 cimg::swap((*this)[i],(*this)[j]);
08157                 cimg::swap(permutations[i],permutations[j]);
08158                 i++; j--; }
08159             } while (i<=j);
08160           }
08161           if (min<j) _quicksort(min,j,permutations,increasing);
08162           if (i<max) _quicksort(i,max,permutations,increasing);
08163         }
08164       }
08165       return *this;
08166     }
08167 
08169     template<typename t>
08170     CImg<T>& quicksort(CImg<t>& permutations,const bool increasing=true) {
08171       cimg_test(*this,"CImg<T>::quicksort");
08172       if (permutations.size()!=size()) permutations = CImg<t>(size());
08173       cimg_mapoff(permutations,off) permutations[off] = off;
08174       return _quicksort(0,size()-1,permutations,increasing); 
08175     }
08176 
08178     CImg<T>& quicksort(const bool increasing=true) { CImg<T> foo; return quicksort(foo,increasing); }
08179 
08181     template<typename t> CImg<T>& get_quicksort(CImg<t>& permutations,const bool increasing=true) {
08182       return CImg<T>(*this).quicksort(permutations,increasing);
08183     }
08184 
08186     CImg<T>& get_quicksort(const bool increasing=true) { 
08187       return CImg<T>(*this).quicksort(increasing); 
08188     }
08189     
08191     //------------------------------------------
08192     //------------------------------------------
08193     //
08195 
08196     //------------------------------------------
08197     //------------------------------------------
08198   
08200     const CImg& display(CImgDisplay& disp,const unsigned int ymin=0,const unsigned int ymax=~0) const { disp.display(*this,ymin,ymax); return *this; }
08201 
08203     const CImg& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
08204   
08208     const CImg& display(const char* title,const int min_size=128,const int max_size=1024) const {
08209       cimg_test(*this,"CImg<T>::display");
08210       CImgDisplay *disp;
08211       unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3];
08212       print(title);
08213       const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
08214       if (dmin<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); }
08215       const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
08216       if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); }
08217       disp = new CImgDisplay(CImg<unsigned char>(w,h,1,1,0),title,0,3);
08218       XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2;
08219       while (!disp->closed && !disp->key) feature_selection(NULL,1,*disp,XYZ);
08220       delete disp;
08221       return *this;
08222     }
08223 
08225     const CImg& display(const int min_size=128,const int max_size=1024) const { return display("",min_size,max_size); }
08226   
08228     const CImg& feature_selection(int *const selection, const int feature_type,CImgDisplay &disp,
08229                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
08230       cimg_test(*this,"CImg<T>::feature_selection");
08231       if (disp.events<3) 
08232         throw CImgArgumentException("CImg<%s>::feature_selection() : Input display must be able to catch keyboard"
08233                                     "and mouse events (events>=3). Given display has 'events = %s'.",
08234                                     pixel_type(),disp.events);
08235       unsigned char fgcolor[3]={255,255,105}, bgcolor[3]={0,0,0};
08236       if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv()));
08237       int carea=0,area=0,phase=0,
08238         X0=(XYZ?XYZ[0]:width/2)%width, Y0=(XYZ?XYZ[1]:height/2)%height, Z0=(XYZ?XYZ[2]:depth/2)%depth, 
08239         X=-1,Y=-1,Z=-1,oX=-1,oY=-1,oZ=-1,X1=-1,Y1=-1,Z1=-1;
08240       unsigned int hatch=feature_type?0xF0F0F0F0:~0L;
08241       bool feature_selected = false, ytext = false;
08242       CImg<unsigned char> visu, visu0;
08243       char text[1024];
08244     
08245       while (!disp.key && !disp.closed && !feature_selected) {
08246 
08247         // Init visu0 if necessary
08248         if (disp.resized || !visu0.data) { 
08249           if (disp.resized) disp.resize();
08250           if (depth==1) visu0=get_normalize(0,(T)255); else visu0=get_3dplanes(X0,Y0,Z0).get_normalize(0,(T)255);
08251           visu0.resize(disp.width,disp.height,1,cimg::min(3,dimv()));
08252         }
08253         visu = visu0;      
08254         
08255         // Handle motion and selection
08256         const int mx = disp.mouse_x, my = disp.mouse_y, b = disp.button;
08257         if (mx>=0 && my>=0) {
08258           const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
08259           if (mX<dimx() && mY<dimy())   { area=1; X=mX; Y=mY; Z=phase?Z1:Z0; }
08260           if (mX<dimx() && mY>=dimy())  { area=2; X=mX; Y=phase?Y1:Y0; Z=mY-height; }
08261           if (mX>=dimx() && mY<dimy())  { area=3; X=phase?X1:X0; Y=mY; Z=mX-width;  }
08262           if (mX>=dimx() && mY>=dimy()) { X=X0; Y=Y0; Z=Z0; }
08263           if ((!(phase%2) && (b&1)) || (phase%2 && !(b&1))) { 
08264             if (!carea) carea=area;
08265             if (!(phase++)) { X0=X; Y0=Y; Z0=Z; }
08266           }
08267           if (b&2) { if (!phase) { X0=X; Y0=Y; Z0=Z; } else { X1=Y1=Z1=-1; phase=carea=0; }}
08268           if ((b&2 || phase) && depth>1) 
08269             visu0 = get_3dplanes(X,Y,Z).normalize(0,(T)255).resize(disp.width,disp.height,1,cimg::min(3,dimv()));
08270           if (phase) {
08271             if (!feature_type) feature_selected = phase?true:false;
08272             else {
08273               if (depth>1) feature_selected = (phase==3)?true:false;
08274               else feature_selected = (phase==2)?true:false;
08275             }   
08276             if (!feature_selected) {
08277               if (phase<2) { X1=X; Y1=Y; Z1=Z; }
08278               else switch(carea) {
08279               case 1: Z1=Z; break;
08280               case 2: Y1=Y; break;
08281               case 3: X1=X; break;
08282               }
08283             }
08284           }
08285           if (!phase || !feature_type) {
08286             if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y);
08287             cimg_mapV(*this,k) std::sprintf(text+cimg::strlen(text),"%g ",(double)(*this)(X,Y,Z,k));
08288             std::sprintf(text+cimg::strlen(text),"}");
08289             if (!feature_type) { X1=X0; Y1=Y0; Z1=Z0; }
08290           } else
08291             switch (feature_type) {
08292             case 1: {
08293                 const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
08294                 if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm);
08295                 else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm);
08296             } break;
08297             case 2:
08298               if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)",
08299                                         X0<X1?X0:X1,Y0<Y1?Y0:Y1,Z0<Z1?Z0:Z1,
08300                                         X0<X1?X1:X0,Y0<Y1?Y1:Y0,Z0<Z1?Z1:Z0,
08301                                         1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
08302               else  std::sprintf(text,"Box (%d,%d)-(%d,%d), Size=(%d,%d)",
08303                                  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));
08304               break;
08305             case 3:
08306               if (depth>1) std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii=(%d,%d,%d)",
08307                                         X0,Y0,Z0,X1,Y1,Z1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
08308               else  std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii=(%d,%d)",
08309                                  X0,Y0,X1,Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
08310 
08311               break;
08312             }
08313           if (my<12) ytext=true;
08314           if (my>=visu.dimy()-11) ytext=false;
08315           visu.draw_text(text,0,ytext?visu.dimy()-11:0,fgcolor,bgcolor,0.7f);
08316         } else { X=Y=Z=-1; if (phase) disp.button=phase%2; }
08317         
08318         // Draw image + selection on display window
08319         if (X>=0 && Y>=0 && Z>=0) {
08320           hatch=cimg::ror(hatch);
08321           if (feature_type==1 && phase) {
08322             const int d=(depth>1)?depth:0,
08323               x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)),
08324               x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d));
08325             visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch);
08326             if (d) {
08327               const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)),
08328                 zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d));
08329               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);
08330             }
08331           } else switch(feature_type) {
08332           case 2: {
08333             const bool cond=(phase&&feature_type);
08334             const int d=(depth>1)?depth:0,
08335               nX0=cond?X0:X, nY0=cond?Y0:Y, nZ0=cond?Z0:Z,
08336               nX1=cond?X1:X, nY1=cond?Y1:Y, nZ1=cond?Z1:Z,
08337               x0=(nX0<nX1?nX0:nX1)*disp.width/(width+d),
08338               y0=(nY0<nY1?nY0:nY1)*disp.height/(height+d),
08339               x1=((nX0<nX1?nX1:nX0)+1)*disp.width/(width+d)-1,
08340               y1=((nY0<nY1?nY1:nY0)+1)*disp.height/(height+d)-1;
08341             const unsigned int nhatch=phase?hatch:~0L;
08342             visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,nhatch).
08343               draw_line(x1,y0,x1,y1,fgcolor,nhatch).draw_line(x1,y1,x0,y1,fgcolor,nhatch).draw_line(x0,y1,x0,y0,fgcolor,nhatch);
08344             if (d) {
08345               const int
08346                 zx0=(int)((width+(nZ0<nZ1?nZ0:nZ1))*disp.width/(width+d)),
08347                 zy0=(int)((height+(nZ0<nZ1?nZ0:nZ1))*disp.height/(height+d)),
08348                 zx1=(int)((width+(nZ0<nZ1?nZ1:nZ0)+1)*disp.width/(width+d))-1,
08349                 zy1=(int)((height+(nZ0<nZ1?nZ1:nZ0)+1)*disp.height/(height+d))-1;
08350               visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,nhatch).
08351                 draw_line(zx1,y0,zx1,y1,fgcolor,nhatch).draw_line(zx1,y1,zx0,y1,fgcolor,nhatch).draw_line(zx0,y1,zx0,y0,fgcolor,nhatch);
08352               visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,nhatch).
08353                 draw_line(x1,zy0,x1,zy1,fgcolor,nhatch).draw_line(x1,zy1,x0,zy1,fgcolor,nhatch).draw_line(x0,zy1,x0,zy0,fgcolor,nhatch);
08354             }
08355           } break;
08356           case 3: {
08357             const bool cond=(phase&&feature_type);
08358             const int d=(depth>1)?depth:0,
08359               x0=(cond?X0:X)*disp.width/(width+d),
08360               y0=(cond?Y0:Y)*disp.height/(height+d),
08361               x1=(cond?X1:X)*disp.width/(width+d)-1,
08362               y1=(cond?Y1:Y)*disp.height/(height+d)-1;
08363             const unsigned int nhatch=phase?hatch:~0L;
08364             visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f).
08365                          draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch);
08366             if (d) {
08367               const int
08368                 zx0=(int)((width+(cond?Z0:Z))*disp.width/(width+d)),
08369                 zy0=(int)((height+(cond?Z0:Z))*disp.height/(height+d)),
08370                 zx1=(int)((width+(cond?Z1:Z)+1)*disp.width/(width+d))-1,
08371                 zy1=(int)((height+(cond?Z1:Z)+1)*disp.height/(height+d))-1;
08372               visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f).
08373                                    draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch).
08374                                    draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,0L,0.2f).
08375                                    draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,nhatch);
08376             }
08377           } break;
08378           }
08379         }
08380         visu.display(disp).wait(32);
08381         if ((!feature_selected && !phase && oX==X && oY==Y && oZ==Z) || (X<0 || Y<0 || Z<0)) disp.wait();
08382         oX=X; oY=Y; oZ=Z;
08383       }
08384 
08385       // Return result
08386       if (XYZ) { XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; }
08387       if (feature_selected) {
08388         if (feature_type==2) {
08389           if (X0>X1) cimg::swap(X0,X1);
08390           if (Y0>Y1) cimg::swap(Y0,Y1);
08391           if (Z0>Z1) cimg::swap(Z0,Z1);
08392         }
08393         if (selection) {
08394           if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1;
08395           switch(feature_type) {
08396           case 1:
08397           case 2:  selection[3] = X1; selection[4] = Y1; selection[5] = Z1;
08398           default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0;
08399           }
08400         }
08401       } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1;
08402       disp.button=0;
08403       return *this;
08404     }
08405 
08407     const CImg& feature_selection(int *const selection, const int feature_type,
08408                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
08409       unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0);
08410       const unsigned int dmin = cimg::min(w,h), minsiz = 256;
08411       if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
08412       const unsigned int dmax = cimg::max(w,h), maxsiz = 1024;
08413       if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
08414       CImgDisplay disp(w,h,"",0,3);
08415       return feature_selection(selection,feature_type,disp,XYZ,color);
08416     }
08417   
08419     //------------------------------------------
08420     //------------------------------------------
08421     //
08423 
08424     //------------------------------------------
08425     //------------------------------------------
08426 
08428 
08434     static CImg load(const char *filename) {
08435       if (!filename) throw CImgArgumentException("CImg<%s>::load() : Can't load (null) filename",pixel_type());
08436       const char *ext = cimg::filename_split(filename);
08437       if (!cimg::strcasecmp(ext,"asc")) return load_ascii(filename);
08438       if (!cimg::strcasecmp(ext,"dlm")) return load_dlm(filename);
08439       if (!cimg::strcasecmp(ext,"inr")) return load_inr(filename);
08440       if (!cimg::strcasecmp(ext,"hdr")) return load_analyze(filename);
08441       if (!cimg::strcasecmp(ext,"pan")) return load_pandore(filename);
08442       if (!cimg::strcasecmp(ext,"bmp")) return load_bmp(filename);
08443       if (!cimg::strcasecmp(ext,"png")) return load_png(filename);
08444       if (!cimg::strcasecmp(ext,"jpg") ||
08445           !cimg::strcasecmp(ext,"jpeg")) return load_jpeg(filename);
08446       if (!cimg::strcasecmp(ext,"ppm") || 
08447           !cimg::strcasecmp(ext,"pgm") ||
08448           !cimg::strcasecmp(ext,"pnm")) return load_pnm(filename);
08449       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return load_raw(filename);      
08450       return load_convert(filename);
08451     }
08452 
08454     static CImg load_ascii(const char *filename) {
08455       std::FILE *file = cimg::fopen(filename,"rb");
08456       char line[256] = {0};
08457       std::fscanf(file,"%255[^\n]",line);
08458       unsigned int off;
08459           int err=1, dx=0, dy=1, dz=1, dv=1;
08460       std::sscanf(line,"%d %d %d %d",&dx,&dy,&dz,&dv);
08461       if (!dx || !dy || !dz || !dv)
08462         throw CImgIOException("CImg<%s>::load_ascii() : File '%s' does not appear to be a valid ASC file.\n"
08463                               "Specified image dimensions are (%d,%d,%d,%d)",pixel_type(),filename,dx,dy,dz,dv);
08464       CImg dest(dx,dy,dz,dv);
08465       double val;
08466       T *ptr = dest.data;
08467       for (off=0; off<dest.size() && err==1; off++) {
08468         err = std::fscanf(file,"%lf%*[^0-9.eE+-]",&val); 
08469         *(ptr++)=(T)val; 
08470       }
08471       cimg::warn(off<dest.size(),"CImg<%s>::load_ascii() : File '%s', only %u values read, instead of %u",
08472                  pixel_type(),filename,off,dest.size());
08473       cimg::fclose(file);
08474       return dest;
08475     }
08476 
08478     static CImg load_dlm(const char *filename) {
08479       std::FILE *file = cimg::fopen(filename,"r");
08480       unsigned int cdx=0,dx=0,dy=0;
08481       double val;
08482       char c, delimiter[256]={0}, tmp[256];
08483       int err;
08484       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
08485         c=0;
08486         if (err>0) cdx++;
08487         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { dx = cimg::max(cdx,dx); dy++; cdx=0; }
08488       }
08489       if (!dx || !dy) throw CImgIOException("CImg<%s>::load_dlm() : File '%s' does not appear to be a "
08490                                             "valid DLM file (width = %d, height = %d)\n",pixel_type(),filename,dx,dy);
08491       std::rewind(file);
08492       CImg<T> dest(dx,dy,1,1,0);
08493       unsigned int x = 0, y = 0;
08494       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
08495         c=0;
08496         if (err>0) dest(x++,y) = (T)val;
08497         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { x=0; y++; }
08498       }
08499       cimg::fclose(file);
08500       return dest;
08501     }
08502 
08504     static CImg load_pnm(const char *filename) {
08505       std::FILE *file=cimg::fopen(filename,"rb");
08506       char item[1024]={0};
08507       unsigned int ppm_type,width,height,colormax=255;
08508       int err;
08509       
08510       while ((err=std::fscanf(file,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08511       if(std::sscanf(item," P%u",&ppm_type)!=1) 
08512         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',PPM header 'P?' not found",pixel_type(),filename);
08513       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08514       if (std::sscanf(item," %u %u",&width,&height)!=2)
08515         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',WIDTH and HEIGHT not defined",pixel_type(),filename);
08516       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
08517       std::fgetc(file);
08518       cimg::warn(std::sscanf(item,"%u",&colormax)!=1,
08519                  "CImg<%s>::load_pnm() : file '%s',COLORMAX not defined",pixel_type(),filename);
08520       
08521       CImg dest;
08522       int rval,gval,bval;
08523 
08524       switch (ppm_type) {
08525       case 2: { // Grey Ascii
08526         dest = CImg<T>(width,height,1,1);
08527         T* rdata = dest.ptr();
08528         cimg_mapoff(dest,off) { std::fscanf(file,"%d",&rval); *(rdata++)=(T)rval; }
08529       } break;
08530       case 3: { // Color Ascii
08531         dest = CImg<T>(width,height,1,3);
08532         T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2);
08533         cimg_mapXY(dest,x,y) { 
08534           std::fscanf(file,"%d %d %d",&rval,&gval,&bval);
08535           *(rdata++)=(T)rval; 
08536           *(gdata++)=(T)gval; 
08537           *(bdata++)=(T)bval; }
08538       } break;
08539       case 5: { // Grey Binary
08540         if (colormax<256) { // 8 bits
08541           CImg<unsigned char> raw(width,height,1,1);
08542           cimg::fread(raw.data,sizeof(unsigned char),width*height,file);
08543           dest = CImg<T>(raw);
08544         } else { // 16 bits
08545           CImg<unsigned short> raw(width,height,1,1);
08546           cimg::fread(raw.data,sizeof(unsigned short),width*height,file);
08547           dest = CImg<T>(raw);
08548         }
08549       } break;
08550       case 6: { // Color Binary
08551         if (colormax<256) { // 8 bits
08552           CImg<unsigned char> raw(width,height,1,3);
08553           cimg::fread(raw.data,sizeof(unsigned char),width*height*3,file);
08554           dest = CImg<T>(raw.data,width,height,1,3,true);
08555         } else { // 16 bits
08556           CImg<unsigned short> raw(width,height,1,3);
08557           cimg::fread(raw.data,sizeof(unsigned short),width*height*3,file);
08558           dest = CImg<T>(raw.data,width,height,1,3,true);
08559         }
08560       } break;
08561       default:
08562         cimg::fclose(file);
08563         throw CImgIOException("CImg<%s>::load_pnm() : file '%s', PPM type 'P%d' not supported",pixel_type(),filename,ppm_type);
08564       }
08565       cimg::fclose(file);
08566       return dest;
08567     }
08568 
08570     static CImg load_bmp(const char *filename) {
08571       unsigned char header[64];
08572       std::FILE *file = cimg::fopen(filename,"rb");
08573       cimg::fread(header,sizeof(unsigned char),54,file);
08574       if (header[0]!='B' || header[1]!='M')
08575         throw CImgIOException("CImg<%s>::load_bmp() : filename '%s' does not appear to be a valid BMP file",
08576                               pixel_type(),filename);
08577       
08578       // Read header and pixel buffer
08579       int
08580         file_size   = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
08581         offset      = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
08582         dx          = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
08583         dy          = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
08584         compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
08585         nb_colors   = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
08586         bpp         = header[0x1C] + (header[0x1D]<<8),
08587         *palette    = NULL;
08588       const int 
08589         dx_bytes   = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
08590         align      = (4-dx_bytes%4)%4,
08591         buf_size   = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
08592 
08593       if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors=0;
08594       if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,sizeof(int),nb_colors,file); }
08595       const int xoffset = offset-54-4*nb_colors;      
08596       if (xoffset>0) std::fseek(file,xoffset,SEEK_CUR);
08597       const unsigned char *buffer  = new unsigned char[buf_size], *ptrs = buffer;
08598       cimg::fread(buffer,sizeof(unsigned char),buf_size,file);
08599       cimg::fclose(file);
08600 
08601       // Decompress buffer (if necessary)
08602       if (compression) return load_convert(filename);
08603       
08604       // Read pixel data
08605       CImg res(dx,cimg::abs(dy),1,3);
08606       switch (bpp) {
08607       case 1: { // Monochrome
08608         for (int y=res.height-1; y>=0; y--) { 
08609           unsigned char mask = 0x80, val = 0;
08610           cimg_mapX(res,x) {
08611             if (mask==0x80) val = *(ptrs++);
08612             const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
08613             res(x,y,2) = (T)*(col++);
08614             res(x,y,1) = (T)*(col++);
08615             res(x,y,0) = (T)*(col++);
08616             mask = cimg::ror(mask);
08617           } ptrs+=align; }
08618       } break;
08619       case 4: { // 16 colors
08620         for (int y=res.height-1; y>=0; y--) { 
08621           unsigned char mask = 0xF0, val = 0;
08622           cimg_mapX(res,x) {
08623             if (mask==0xF0) val = *(ptrs++);
08624             const unsigned char color = (mask<16)?(val&mask):((val&mask)>>4);
08625             unsigned char *col = (unsigned char*)(palette+color);
08626             res(x,y,2) = (T)*(col++);
08627             res(x,y,1) = (T)*(col++);
08628             res(x,y,0) = (T)*(col++);
08629             mask = cimg::ror(mask,4);
08630           } ptrs+=align; }
08631       } break;
08632       case 8: { //  256 colors
08633         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08634           const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
08635           res(x,y,2) = (T)*(col++);
08636           res(x,y,1) = (T)*(col++);
08637           res(x,y,0) = (T)*(col++);
08638         } ptrs+=align; }
08639       } break;
08640       case 16: { // 16 bits colors
08641         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08642           const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
08643           const unsigned short col = c1+(c2<<8);
08644           res(x,y,2) = (T)(col&0x1F);
08645           res(x,y,1) = (T)((col>>5)&0x1F);
08646           res(x,y,0) = (T)((col>>10)&0x1F);
08647         } ptrs+=align; }
08648       } break;  
08649       case 24: { // 24 bits colors
08650         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08651           res(x,y,2) = (T)*(ptrs++);
08652           res(x,y,1) = (T)*(ptrs++);
08653           res(x,y,0) = (T)*(ptrs++);
08654         } ptrs+=align; }
08655       } break;
08656       case 32: { // 32 bits colors
08657         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
08658           res(x,y,2) = (T)*(ptrs++);
08659           res(x,y,1) = (T)*(ptrs++);
08660           res(x,y,0) = (T)*(ptrs++);
08661           ptrs++;
08662         } ptrs+=align; }
08663       } break;
08664       }
08665 
08666       if (palette) delete[] palette;
08667       if (dy<0) res.flip('y');
08668       return res;
08669     }
08670     
08672     // Note : Most of this function has been written by Eric Fausett
08673     static CImg load_png(const char *filename) {
08674 #ifndef cimg_use_png
08675       return load_convert(filename);
08676 #else
08677       // Open file and check for PNG validity
08678       unsigned char pngCheck[8];
08679       std::FILE *file = cimg::fopen(filename,"rb");
08680       cimg::fread(pngCheck,sizeof(unsigned char),8,file);
08681       if(png_sig_cmp(pngCheck,0,8)){
08682         cimg::fclose(file);
08683         throw CImgIOException("CImg<%s>::load_png() : filename '%s' does not appear to be a valid PNG file",pixel_type(),filename);
08684       }
08685       
08686       // Setup PNG structures for read
08687       png_voidp user_error_ptr=0;
08688       png_error_ptr user_error_fn=0, user_warning_fn=0;
08689       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,       // Verifies libpng version correct
08690                                                    user_error_ptr, user_error_fn, user_warning_fn);
08691       if(!png_ptr){
08692         cimg::fclose(file);
08693         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'png_ptr' data structure",pixel_type());
08694       }
08695       png_infop info_ptr = png_create_info_struct(png_ptr);
08696       if(!info_ptr){
08697         cimg::fclose(file);
08698         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);                  
08699         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'info_ptr' data structure",pixel_type());
08700       }
08701       png_infop end_info = png_create_info_struct(png_ptr);
08702       if(!end_info){
08703         cimg::fclose(file);
08704         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);                 
08705         throw CImgIOException("CImg<%s>::load_png() : trouble initializing 'end_info' data structure",pixel_type());
08706       }
08707       
08708       // Error handling callback for png file reading
08709       if (setjmp(png_jmpbuf(png_ptr))){
08710         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
08711         cimg::fclose(file);
08712         throw CImgIOException("CImg<%s>::load_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
08713       }      
08714       png_init_io(png_ptr, file);      
08715       png_set_sig_bytes(png_ptr, 8);
08716       
08717       // Get PNG Header Info up to data block
08718       png_read_info(png_ptr, info_ptr);      
08719       png_uint_32 width, height;
08720       int bit_depth, color_type, interlace_type;
08721       png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type,
08722                    int_p_NULL, int_p_NULL);
08723       int new_bit_depth = bit_depth;
08724       int new_color_type = color_type;
08725       
08726       // Transforms to unify image data         
08727       if (new_color_type == PNG_COLOR_TYPE_PALETTE){
08728         png_set_palette_to_rgb(png_ptr);
08729         new_color_type -= PNG_COLOR_MASK_PALETTE;
08730         new_bit_depth = 8;
08731       }
08732       if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
08733         png_set_gray_1_2_4_to_8(png_ptr);
08734         new_bit_depth = 8;
08735       }
08736       if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
08737         png_set_tRNS_to_alpha(png_ptr);
08738       if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
08739         png_set_gray_to_rgb(png_ptr);
08740         new_color_type |= PNG_COLOR_MASK_COLOR;
08741       }
08742       if (new_color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);      
08743       png_read_update_info(png_ptr, info_ptr);      
08744       if (!(new_bit_depth==8 || new_bit_depth==16))
08745         throw CImgIOException("CImg<%s>::load_png() : Wrong bit coding 'bit_depth=%u'",pixel_type(),new_bit_depth);
08746       const int byte_depth = new_bit_depth>>3;
08747       
08748       // Allocate Memory for Image Read
08749       png_bytep *imgData = new png_bytep[height];
08750       for (unsigned int row=0; row < height; row++) imgData[row] = new png_byte[byte_depth * 4 * width];
08751       png_read_image(png_ptr, imgData);
08752       png_read_end(png_ptr, end_info);
08753       
08754       // Read pixel data
08755       if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA))
08756         throw CImgIOException("CImg<%s>::load_png() : Wrong color coding new_color_type=%u",pixel_type(),new_color_type);
08757       const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
08758       CImg res(width,height,1,no_alpha_channel?3:4);
08759       const unsigned long off = width*height;
08760       T *ptr1 = res.data, *ptr2 = ptr1+off, *ptr3 = ptr2+off, *ptr4 = ptr3+off;
08761       switch(new_bit_depth){
08762       case 8: {
08763         cimg_mapY(res,y){
08764           const unsigned char *ptrs = imgData[y];
08765           cimg_mapX(res,x){
08766             *(ptr1++) = (T)*(ptrs++);
08767             *(ptr2++) = (T)*(ptrs++);
08768             *(ptr3++) = (T)*(ptrs++);
08769             if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++);
08770           }
08771         }
08772       } break;
08773       case 16: {
08774         cimg_mapY(res,y){
08775           const unsigned short *ptrs = (unsigned short*)(imgData[y]);
08776           cimg_mapX(res,x){
08777             *(ptr1++) = (T)*(ptrs++);
08778             *(ptr2++) = (T)*(ptrs++);
08779             *(ptr3++) = (T)*(ptrs++);
08780             if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++);
08781           }
08782         }
08783       } break;
08784       }
08785       png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
08786       
08787       // Deallocate Image Read Memory
08788       for (unsigned int n=0; n<height; n++) delete[] imgData[n];
08789       delete[] imgData;      
08790       cimg::fclose(file);
08791       return res;      
08792 #endif      
08793     }
08794 
08795 
08797     static CImg load_jpeg(const char *filename) {
08798 #ifndef cimg_use_jpeg
08799       return load_convert(filename);
08800 #else
08801       struct jpeg_decompress_struct cinfo;
08802       struct jpeg_error_mgr jerr;
08803       std::FILE *file = cimg::fopen(filename,"rb");
08804       cinfo.err = jpeg_std_error(&jerr);
08805       jpeg_create_decompress(&cinfo);
08806       jpeg_stdio_src(&cinfo,file);
08807       jpeg_read_header(&cinfo,TRUE);
08808       jpeg_start_decompress(&cinfo);
08809       
08810       if (cinfo.output_components!=3) {
08811         cimg::warn(true,"CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
08812                    pixel_type(),filename);
08813         return load_convert(filename);
08814       }
08815       
08816       const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
08817       unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*3], *buf2 = buf;
08818       JSAMPROW row_pointer[1];
08819       while (cinfo.output_scanline < cinfo.output_height) {
08820         row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
08821         jpeg_read_scanlines(&cinfo,row_pointer,1);
08822       }
08823       jpeg_finish_decompress(&cinfo);
08824       jpeg_destroy_decompress(&cinfo);
08825       cimg::fclose(file);
08826       
08827       CImg<T> dest(cinfo.output_width,cinfo.output_height,1,3);
08828       T *ptr_r = dest.ptr(0,0,0,0),
08829         *ptr_g = dest.ptr(0,0,0,1),
08830         *ptr_b = dest.ptr(0,0,0,2);
08831       cimg_mapXY(dest,x,y) {
08832         *(ptr_r++) = *(buf2++);
08833         *(ptr_g++) = *(buf2++);
08834         *(ptr_b++) = *(buf2++);
08835       }
08836       delete[] buf;
08837       return dest;
08838 #endif
08839     }
08840     
08842     static CImg load_rgba(const char *filename,const unsigned int dimw,const unsigned int dimh) {
08843       std::FILE *file = cimg::fopen(filename,"rb");
08844       unsigned char *buffer = new unsigned char[dimw*dimh*4];
08845       cimg::fread(buffer,sizeof(unsigned char),dimw*dimh*4,file);
08846       cimg::fclose(file);
08847       CImg res = CImg<T>(buffer,dimw,dimh,1,4,true);
08848       delete[] buffer;
08849       return res;      
08850     }
08851 
08853     static CImg load_rgb(const char *filename,const unsigned int dimw,const unsigned int dimh) {
08854       std::FILE *file = cimg::fopen(filename,"rb");
08855       unsigned char *buffer = new unsigned char[dimw*dimh*3];
08856       cimg::fread(buffer,sizeof(unsigned char),dimw*dimh*3,file);
08857       cimg::fclose(file);
08858       CImg res = CImg<T>(buffer,dimw,dimh,1,3,true);
08859       delete[] buffer;
08860       return res;
08861     }
08862     
08864 #define cimg_load_inr_case(Tf,sign,pixsize,Ts)                            \
08865   if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) {      \
08866       Ts *xval, *val = new Ts[fopt[0]*fopt[3]];                           \
08867       cimg_mapYZ(dest,y,z) {                                              \
08868           cimg::fread(val,pixsize/8,fopt[0]*fopt[3],file);                \
08869           if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]);    \
08870           xval = val; cimg_mapX(dest,x) cimg_mapV(dest,k)                 \
08871                           dest(x,y,z,k) = (T)*(xval++);                   \
08872         }                                                                 \
08873       delete[] val;                                                       \
08874       loaded = true;                                                      \
08875     }
08876     
08877     static void _load_inr(std::FILE *file,int out[8],float *voxsize=NULL) {
08878       char item[1024],tmp1[64],tmp2[64];
08879       out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1;
08880       std::fscanf(file,"%63s",item);
08881       if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) 
08882         throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
08883                               "(INRIMAGE-4 identifier not found)",pixel_type());
08884       while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
08885         std::sscanf(item," XDIM%*[^0-9]%d",out);
08886         std::sscanf(item," YDIM%*[^0-9]%d",out+1);
08887         std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
08888         std::sscanf(item," VDIM%*[^0-9]%d",out+3);
08889         std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
08890         if (voxsize) {
08891           std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize);
08892           std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1);
08893           std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2);
08894         }
08895         if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
08896         switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
08897         case 0: break;
08898         case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
08899         case 1:
08900           if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4]=0;
08901           if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4]=1;
08902           if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4]=2;
08903           if (out[4]>=0) break;
08904         default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
08905         }
08906       }
08907       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
08908         throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
08909                               pixel_type(),out[0],out[1],out[2],out[3]);
08910       if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",pixel_type());
08911       if(out[6]<0) throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",pixel_type());
08912       if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",pixel_type());
08913     }
08914     
08915     static CImg load_inr(const char *filename, float *voxsize = NULL) {
08916       std::FILE *file = cimg::fopen(filename,"rb");
08917           int fopt[8], endian=cimg::endian()?1:0;
08918       bool loaded = false;
08919       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
08920       _load_inr(file,fopt,voxsize);
08921       CImg<T> dest = CImg<T>(fopt[0],fopt[1],fopt[2],fopt[3]);
08922       cimg_load_inr_case(0,0,8, unsigned char);
08923       cimg_load_inr_case(0,1,8, char);
08924       cimg_load_inr_case(0,0,16,unsigned short);
08925       cimg_load_inr_case(0,1,16,short);
08926       cimg_load_inr_case(0,0,32,unsigned int);
08927       cimg_load_inr_case(0,1,32,int);
08928       cimg_load_inr_case(1,0,32,float);
08929       cimg_load_inr_case(1,1,32,float);
08930       cimg_load_inr_case(1,0,64,double);
08931       cimg_load_inr_case(1,1,64,double);
08932       if (!loaded) throw CImgIOException("CImg<%s>::load_inr() : File '%s', can't read images of the type specified in the file",
08933                                          pixel_type(),filename);
08934       cimg::fclose(file);
08935       return dest;
08936     }
08937    
08938 #define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype)  \
08939   case nid: {                                                         \
08940     cimg::fread(dims,sizeof(unsigned int),nbdim,file);                \
08941     if (endian) cimg::endian_swap(dims,nbdim);                        \
08942     dest = CImg<T>(nwidth,nheight,ndepth,ndim);                       \
08943     stype *buffer = new stype[dest.size()];                           \
08944     cimg::fread(buffer,sizeof(stype),dest.size(),file);               \
08945     if (endian) cimg::endian_swap(buffer,dest.size());                \
08946     T *ptrd = dest.ptr();                                             \
08947     cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));               \
08948     buffer-=dest.size();                                              \
08949     delete[] buffer;                                                  \
08950    }                                                                  \
08951    break;
08952     
08953     static CImg load_pandore(const char *filename) {
08954       std::FILE *file = cimg::fopen(filename,"rb");
08955       typedef unsigned char uchar;
08956       typedef unsigned short ushort;
08957       typedef unsigned int uint;  
08958       typedef unsigned long ulong; 
08959       CImg dest;
08960       char tmp[16];
08961       cimg::fread(tmp,sizeof(char),12,file);
08962       if (cimg::strncasecmp("PANDORE",tmp,7)) 
08963         throw CImgIOException("CImg<%s>::load_pandore() : File '%s' does not appear to be a valid PANDORE file.\n"
08964                               "(PANDORE identifier not found)",pixel_type(),filename);
08965       unsigned int id,dims[8];
08966       long ptbuf[4];
08967       cimg::fread(&id,sizeof(int),1,file);
08968       const bool endian = (id>255);
08969       if (endian) cimg::endian_swap(id);
08970       cimg::fread(tmp,sizeof(char),20,file);
08971       switch (id) {
08972         cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
08973         cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
08974         cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
08975         cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
08976         cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
08977         cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
08978         cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
08979         cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
08980         cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
08981       case 11: { // Region 1D
08982         cimg::fread(dims,sizeof(unsigned int),3,file);
08983         if (endian) cimg::endian_swap(dims,3);
08984         dest = CImg<T>(dims[1],1,1,1);
08985         if (dims[2]<256) {
08986           unsigned char *buffer = new unsigned char[dest.size()];
08987           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
08988           T *ptrd = dest.ptr();
08989           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
08990           buffer-=dest.size();
08991           delete[] buffer;
08992         } else {
08993           if (dims[2]<65536) {
08994             unsigned short *buffer = new unsigned short[dest.size()];
08995             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
08996             if (endian) cimg::endian_swap(buffer,dest.size());
08997             T *ptrd = dest.ptr();
08998             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
08999             buffer-=dest.size();
09000             delete[] buffer;
09001           } else {
09002             unsigned long *buffer = new unsigned long[dest.size()];
09003             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09004             if (endian) cimg::endian_swap(buffer,dest.size());
09005             T *ptrd = dest.ptr();
09006             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09007             buffer-=dest.size();
09008             delete[] buffer;
09009           }
09010         }       
09011       }
09012         break;
09013       case 12: { // Region 2D
09014         cimg::fread(dims,sizeof(unsigned int),4,file);
09015         if (endian) cimg::endian_swap(dims,4);
09016         dest = CImg<T>(dims[2],dims[1],1,1);
09017         if (dims[3]<256) {
09018           unsigned char *buffer = new unsigned char[dest.size()];
09019           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
09020           T *ptrd = dest.ptr();
09021           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09022           buffer-=dest.size();
09023           delete[] buffer;
09024         } else {
09025           if (dims[3]<65536) {
09026             unsigned short *buffer = new unsigned short[dest.size()];
09027             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
09028             if (endian) cimg::endian_swap(buffer,dest.size());
09029             T *ptrd = dest.ptr();
09030             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09031             buffer-=dest.size();
09032             delete[] buffer;
09033           } else {
09034             unsigned long *buffer = new unsigned long[dest.size()];
09035             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09036             if (endian) cimg::endian_swap(buffer,dest.size());
09037             T *ptrd = dest.ptr();
09038             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09039             buffer-=dest.size();
09040             delete[] buffer;
09041           }
09042         }       
09043       }
09044         break;
09045       case 13: { // Region 3D
09046         cimg::fread(dims,sizeof(unsigned int),5,file);
09047         if (endian) cimg::endian_swap(dims,5);
09048         dest = CImg<T>(dims[3],dims[2],dims[1],1);
09049         if (dims[4]<256) {
09050           unsigned char *buffer = new unsigned char[dest.size()];
09051           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
09052           T *ptrd = dest.ptr();
09053           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09054           buffer-=dest.size();
09055           delete[] buffer;
09056         } else {
09057           if (dims[4]<65536) {
09058             unsigned short *buffer = new unsigned short[dest.size()];
09059             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
09060             if (endian) cimg::endian_swap(buffer,dest.size());
09061             T *ptrd = dest.ptr();
09062             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09063             buffer-=dest.size();
09064             delete[] buffer;
09065           } else {
09066             unsigned long *buffer = new unsigned long[dest.size()];
09067             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
09068             if (endian) cimg::endian_swap(buffer,dest.size());
09069             T *ptrd = dest.ptr();
09070             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
09071             buffer-=dest.size();
09072             delete[] buffer;
09073           }
09074         }       
09075       }
09076         break;
09077         cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
09078         cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
09079         cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
09080         cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
09081         cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
09082         cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
09083         cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
09084         cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
09085         cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
09086         cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
09087         cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
09088         cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
09089         cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
09090         cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
09091         cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
09092         cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
09093         cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
09094         cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);     
09095       case 34: // Points 1D     
09096         cimg::fread(ptbuf,sizeof(long),1,file);
09097         if (endian) cimg::endian_swap(ptbuf,1);
09098         dest = CImg<T>(1); dest[0]=(T)ptbuf[0];
09099         break;
09100       case 35: // Points 2D
09101         cimg::fread(ptbuf,sizeof(long),2,file);
09102         if (endian) cimg::endian_swap(ptbuf,2);
09103         dest = CImg<T>(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0];
09104         break;
09105       case 36: // Points 3D
09106         cimg::fread(ptbuf,sizeof(long),3,file);
09107         if (endian) cimg::endian_swap(ptbuf,3);
09108         dest = CImg<T>(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0];
09109         break;
09110       default:
09111         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', can't read images with ID_type=%d",pixel_type(),filename,id);
09112       }
09113       return dest;
09114     }
09115 
09116 
09118     static CImg load_analyze(const char *filename, float *voxsize = NULL) {
09119       
09120       // Open header and data files
09121       std::FILE *file_header=NULL, *file=NULL;
09122       char body[1024];
09123       const char *ext = cimg::filename_split(filename,body);
09124       if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"img")) {
09125         std::sprintf(body+cimg::strlen(body),".hdr");
09126         file_header = cimg::fopen(body,"rb");
09127         std::sprintf(body+cimg::strlen(body)-3,"img");
09128         file = cimg::fopen(body,"rb");
09129       } else throw CImgIOException("CImg<%s>::load_analyze() : Cannot load filename '%s' as an analyze format",pixel_type(),filename);
09130 
09131       // Read header
09132       bool endian = false;
09133       unsigned int header_size;
09134       cimg::fread(&header_size,sizeof(int),1,file_header);
09135       if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); }
09136       unsigned char *header = new unsigned char[header_size];
09137       cimg::fread(header+sizeof(int),sizeof(char),header_size-sizeof(int),file_header);
09138       cimg::fclose(file_header);
09139       if (endian) {
09140         cimg::endian_swap((short*)(header+40),5);
09141         cimg::endian_swap((short*)(header+70),1);
09142         cimg::endian_swap((short*)(header+72),1);
09143         cimg::endian_swap((float*)(header+76),4);
09144         cimg::endian_swap((float*)(header+112),1);
09145       }
09146       unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1;
09147       cimg::warn(!dim[0],"CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type());
09148       cimg::warn(dim[0]>4,"CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions",
09149                  pixel_type(),dim[0]);
09150       if (dim[0]>=1) dimx = dim[1];
09151       if (dim[0]>=2) dimy = dim[2];
09152       if (dim[0]>=3) dimz = dim[3];
09153       if (dim[0]>=4) dimv = dim[4];
09154       
09155       float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
09156       const unsigned short datatype = *(short*)(header+70);
09157       if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
09158       delete[] header;
09159 
09160       // Read pixel data
09161       CImg dest(dimx,dimy,dimz,dimv);
09162       switch (datatype) {
09163       case 2: {
09164         unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
09165         cimg::fread(buffer,sizeof(unsigned char),dimx*dimy*dimz*dimv,file);
09166         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09167         delete[] buffer;
09168       } break;
09169       case 4: {
09170         short *buffer = new short[dimx*dimy*dimz*dimv];
09171         cimg::fread(buffer,sizeof(short),dimx*dimy*dimz*dimv,file);
09172         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
09173         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
09174         delete[] buffer;
09175       } break;
09176       case 8: {
09177         int *buffer = new int[dimx*dimy*dimz*dimv];
09178         cimg::fread(buffer,sizeof(int),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 16: {
09184         float *buffer = new float[dimx*dimy*dimz*dimv];
09185         cimg::fread(buffer,sizeof(float),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 64: {
09191         double *buffer = new double[dimx*dimy*dimz*dimv];
09192         cimg::fread(buffer,sizeof(double),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       default: throw CImgIOException("CImg<%s>::load_analyze() : Cannot read images width 'datatype = %d'",pixel_type(),datatype);
09198       }
09199       cimg::fclose(file);
09200       return dest;
09201     }
09202 
09204     static CImg load_raw(const char *filename,const char axe='v',const char align='p') { 
09205       return CImgl<T>(filename).get_append(axe,align); 
09206     }
09207 
09211     static CImg load_convert(const char *filename) {
09212       static bool first_time = true;
09213       char command[512], filetmp[512];     
09214       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
09215       std::FILE *file = NULL;
09216       do { 
09217         if (file) std::fclose(file);
09218         std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),std::rand()%10000);
09219         file = std::fopen(filetmp,"rb");
09220       } while (file);
09221       std::sprintf(command,"\"%s\" \"%s\" %s",cimg::convert_path(),filename,filetmp);
09222       cimg::system(command);
09223       file = std::fopen(filetmp,"rb");
09224       if (!file) {
09225         std::fclose(cimg::fopen(filename,"r"));
09226         throw CImgIOException("CImg<%s>::load_convert() : Failed to open image '%s' with 'convert'.\n"
09227                               "Check that you have installed the ImageMagick package in a standart directory.",
09228                               pixel_type(),filename);
09229       } else cimg::fclose(file);
09230       const CImg dest(filetmp);
09231       std::remove(filetmp);
09232       return dest;
09233     }
09234 
09236 
09241     const CImg& save(const char *filename,const int number=-1) const {
09242       cimg_test(*this,"CImg<T>::save");
09243       if (!filename) throw CImgArgumentException("CImg<%s>::save() : Can't save with (null) filename",pixel_type());
09244       const char *ext = cimg::filename_split(filename);
09245       char nfilename[1024];
09246       if (number>=0) filename = cimg::filename_number(filename,number,6,nfilename);
09247       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(filename);
09248       if (!cimg::strcasecmp(ext,"dlm")) return save_dlm(filename);
09249       if (!cimg::strcasecmp(ext,"inr")) return save_inr(filename);
09250       if (!cimg::strcasecmp(ext,"hdr")) return save_analyze(filename);
09251       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(filename);
09252       if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(filename);
09253       if (!cimg::strcasecmp(ext,"png")) return save_png(filename);
09254       if (!cimg::strcasecmp(ext,"jpg") ||
09255           !cimg::strcasecmp(ext,"jpeg")) return save_jpeg(filename);
09256       if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(filename);
09257       if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(filename);
09258       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return save_raw(filename);
09259       if (!cimg::strcasecmp(ext,"pgm") || 
09260           !cimg::strcasecmp(ext,"ppm") || 
09261           !cimg::strcasecmp(ext,"pnm")) return save_pnm(filename);
09262       return save_convert(filename);
09263     }
09264   
09266     const CImg& save_ascii(const char *filename) const {
09267       cimg_test(*this,"CImg<T>::save_ascii");
09268       std::FILE *file = cimg::fopen(filename,"w");
09269       std::fprintf(file,"%u %u %u %u\n",width,height,depth,dim);
09270       const T* ptrs = data;
09271       cimg_mapYZV(*this,y,z,v) {
09272         cimg_mapX(*this,x) std::fprintf(file,"%g ",(double)*(ptrs++));
09273         std::fputc('\n',file);
09274       }
09275       cimg::fclose(file);
09276       return *this;
09277     }
09278 
09280     const CImg& save_dlm(const char *filename) const {
09281       cimg_test(*this,"CImg<T>::save_dlm");
09282       std::FILE *file = cimg::fopen(filename,"w");
09283       const T* ptrs = data;
09284       cimg_mapYZV(*this,y,z,v) {
09285         cimg_mapX(*this,x) std::fprintf(file,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":",");
09286         std::fputc('\n',file);
09287       }
09288       cimg::fclose(file);
09289       return *this;
09290     }
09291 
09293     const CImg& save_pnm(const char *filename) const {
09294       cimg_test(*this,"CImg<T>::save_pnm");
09295       const char *ext = cimg::filename_split(filename);
09296       const CImgStats st(*this,false);
09297 
09298       if (dim>1 && !cimg::strcasecmp(ext,"pgm")) {
09299                         get_norm_pointwise().normalize(0.0f,(float)st.max).save_pnm(filename); 
09300                         return *this; 
09301       }
09302       std::FILE *file = cimg::fopen(filename,"wb");
09303       const T 
09304         *ptrR = ptr(0,0,0,0),
09305         *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR,
09306         *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR;
09307       const unsigned int buf_size = width*height*(dim==1?1:3);
09308 
09309       std::fprintf(file,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n",
09310                    (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535);
09311       
09312       switch(dim) {
09313       case 1: {
09314         if ((st.max)<256) { // Binary PGM 8 bits
09315           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
09316           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
09317           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
09318           delete[] ptrd;
09319         } else {             // Binary PGM 16 bits
09320           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
09321           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
09322           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
09323           delete[] ptrd;
09324         }
09325       } break;
09326       default: {
09327         if ((st.max)<256) { // Binary PPM 8 bits
09328           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
09329           cimg_mapXY(*this,x,y) {
09330             *(xptrd++) = (unsigned char)*(ptrR++);
09331             *(xptrd++) = (unsigned char)*(ptrG++);
09332             *(xptrd++) = (unsigned char)*(ptrB++);
09333           }
09334           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
09335           delete[] ptrd;
09336         } else {             // Binary PPM 16 bits
09337           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
09338           cimg_mapXY(*this,x,y) {
09339             *(xptrd++) = (unsigned short)*(ptrR++);
09340             *(xptrd++) = (unsigned short)*(ptrG++);
09341             *(xptrd++) = (unsigned short)*(ptrB++);
09342           }
09343           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
09344           delete[] ptrd;
09345         }
09346       } break;
09347       }
09348       cimg::fclose(file);
09349       
09350       return *this;
09351     }
09352     
09354     const CImg& save_analyze(const char *filename,const float *const voxsize=NULL) const {
09355       cimg_test(*this,"CImg<T>::save_analyze");
09356       std::FILE *file;
09357       char header[348],hname[1024],iname[1024];
09358       const char *ext = cimg::filename_split(filename);
09359       short datatype=-1;
09360       std::memset(header,0,348);
09361       if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
09362       if (!cimg::strncasecmp(ext,"hdr",3)) { 
09363         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img"); 
09364       }
09365       if (!cimg::strncasecmp(ext,"img",3)) {
09366         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr"); 
09367       }
09368       ((int*)(header))[0] = 348;
09369       std::sprintf(header+4,"CImg");
09370       std::sprintf(header+14," ");
09371       ((short*)(header+36))[0] = 4096;
09372       ((char*)(header+38))[0] = 114;
09373       ((short*)(header+40))[0] = 4;
09374       ((short*)(header+40))[1] = width;
09375       ((short*)(header+40))[2] = height;
09376       ((short*)(header+40))[3] = depth;
09377       ((short*)(header+40))[4] = dim;
09378       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
09379       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
09380       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
09381       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
09382       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
09383       ((short*)(header+70))[0] = datatype;
09384       ((short*)(header+72))[0] = sizeof(T);
09385       ((float*)(header+112))[0] = 1;
09386       ((float*)(header+76))[0] = 0;
09387       if (voxsize) {
09388         ((float*)(header+76))[1] = voxsize[0];
09389         ((float*)(header+76))[2] = voxsize[1];
09390         ((float*)(header+76))[3] = voxsize[2];
09391       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
09392       file = cimg::fopen(hname,"wb");
09393       cimg::fwrite(header,sizeof(char),348,file);
09394       cimg::fclose(file);
09395       file = cimg::fopen(iname,"wb");
09396       cimg::fwrite(data,sizeof(T),size(),file);
09397       cimg::fclose(file);
09398       return *this;
09399     }
09400 
09402     const CImg& save_raw(const char *filename) const {
09403       cimg_test(*this,"CImg<T>::save_raw");      
09404       CImgl<T> shared(1);
09405       shared[0].width = width;
09406       shared[0].height = height;
09407       shared[0].depth = depth;
09408       shared[0].dim = dim;
09409       shared[0].data = data;
09410       shared.save_raw(filename);
09411       shared[0].width = shared[0].height = shared[0].depth = shared[0].dim = 0;
09412       shared[0].data = NULL;
09413       return *this;
09414     }
09415  
09417 
09423     const CImg& save_convert(const char *filename) const {
09424       cimg_test(*this,"CImg<T>::save_convert");
09425       static bool first_time = true;
09426       char command[512],filetmp[512];
09427       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
09428       std::FILE *file = NULL;
09429       do {
09430         if (file) std::fclose(file);
09431         std::sprintf(filetmp,"%s/CImg%.4d.rgba",cimg::temporary_path(),std::rand()%10000);
09432         file = std::fopen(filetmp,"rb");
09433       } while (file);
09434       save_rgba(filetmp);
09435       std::sprintf(command,"\"%s\" -depth 8 -size %ux%u -quality 100%% \"%s\" %s",
09436                    cimg::convert_path(),width,height,filetmp,filename);
09437       cimg::system(command);
09438       file = std::fopen(filename,"rb");
09439       if (!file) throw CImgIOException("CImg<%s>::save_convert() : Failed to save image '%s' with 'convert'.\n"
09440                                        "Check that you have installed the ImageMagick package in a standart directory.",
09441                                        pixel_type(),filename);
09442       if (file) cimg::fclose(file);
09443       std::remove(filetmp);
09444       return *this;
09445     }
09446     
09448     const CImg& save_inr(const char *filename,const float *const voxsize = NULL) const {
09449       cimg_test(*this,"CImg<T>::save_inr");
09450       int inrpixsize=-1;
09451       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
09452       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
09453       if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
09454       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
09455       if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
09456       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
09457       if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
09458       if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
09459       if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
09460       if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",pixel_type(),pixel_type());
09461       std::FILE *file = cimg::fopen(filename,"wb");
09462       char header[257];      
09463       int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
09464       if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
09465       err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm");
09466       std::memset(header+err,'\n',252-err);
09467       std::memcpy(header+252,"##}\n",4);
09468       cimg::fwrite(header,sizeof(char),256,file);
09469       cimg_mapXYZ(*this,x,y,z) cimg_mapV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),inrpixsize,1,file);
09470       cimg::fclose(file);
09471       return *this;
09472     }
09473 
09474 #define cimg_save_pandore_case(sy,sz,sv,stype,id)                           \
09475    if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
09476       unsigned int *iheader = (unsigned int*)(header+12);                   \
09477       nbdims = _save_pandore_header_length((*iheader=id),dims);             \
09478       cimg::fwrite(header,sizeof(unsigned char),36,file);                   \
09479       cimg::fwrite(dims,sizeof(unsigned int),nbdims,file);                  \
09480       if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
09481         unsigned char *buffer = new unsigned char[size()];                  \
09482         T *ptrs = ptr();                                                    \
09483         cimg_mapoff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++));      \
09484         buffer-=size();                                                     \
09485         cimg::fwrite(buffer,sizeof(unsigned char),size(),file);             \
09486         delete[] buffer;                                                    \
09487       }                                                                     \
09488       if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
09489         unsigned long *buffer = new unsigned long[size()];                  \
09490         T *ptrs = ptr();                                                    \
09491         cimg_mapoff(*this,off) *(buffer++)=(long)(*(ptrs++));               \
09492         buffer-=size();                                                     \
09493         cimg::fwrite(buffer,sizeof(long),size(),file);                      \
09494         delete[] buffer;                                                    \
09495       }                                                                     \
09496       if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
09497         float *buffer = new float[size()];                                  \
09498         T *ptrs = ptr();                                                    \
09499         cimg_mapoff(*this,off) *(buffer++)=(float)(*(ptrs++));              \
09500         buffer-=size();                                                     \
09501         cimg::fwrite(buffer,sizeof(float),size(),file);                     \
09502         delete[] buffer;                                                    \
09503       }                                                                     \
09504       saved = true;                                                         \
09505     }
09506 
09507     unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims) const {
09508       unsigned int nbdims=0;
09509       if (id==2 || id==3 || id==4)    { dims[0]=1; dims[1]=width; nbdims=2; }
09510       if (id==5 || id==6 || id==7)    { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; }
09511       if (id==8 || id==9 || id==10)   { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
09512       if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=1; nbdims=4; }
09513       if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=0; nbdims=5; }
09514       if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; }
09515       if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; }
09516       if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
09517       return nbdims;
09518     }    
09519 
09521     const CImg& save_pandore(const char* filename) const {
09522       cimg_test(*this,"CImg<T>::save_pandore");
09523       std::FILE *file = cimg::fopen(filename,"wb");
09524       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
09525                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,
09526                                    '2','0','0','0','/','0','1','/','0','1',
09527                                    0 };
09528       unsigned int nbdims,dims[5];
09529       bool saved=false;
09530       cimg_save_pandore_case(1,1,1,"unsigned char",2);
09531       cimg_save_pandore_case(1,1,1,"char",3);
09532       cimg_save_pandore_case(1,1,1,"short",3);
09533       cimg_save_pandore_case(1,1,1,"unsigned short",3);
09534       cimg_save_pandore_case(1,1,1,"unsigned int",3);
09535       cimg_save_pandore_case(1,1,1,"int",3);
09536       cimg_save_pandore_case(1,1,1,"unsigned long",4);
09537       cimg_save_pandore_case(1,1,1,"long",3);
09538       cimg_save_pandore_case(1,1,1,"float",4);
09539       cimg_save_pandore_case(1,1,1,"double",4);
09540  
09541       cimg_save_pandore_case(0,1,1,"unsigned char",5);
09542       cimg_save_pandore_case(0,1,1,"char",6);
09543       cimg_save_pandore_case(0,1,1,"short",6);
09544       cimg_save_pandore_case(0,1,1,"unsigned short",6);
09545       cimg_save_pandore_case(0,1,1,"unsigned int",6);
09546       cimg_save_pandore_case(0,1,1,"int",6);
09547       cimg_save_pandore_case(0,1,1,"unsigned long",7);
09548       cimg_save_pandore_case(0,1,1,"long",6);
09549       cimg_save_pandore_case(0,1,1,"float",7);
09550       cimg_save_pandore_case(0,1,1,"double",7);
09551 
09552       cimg_save_pandore_case(0,0,1,"unsigned char",8);
09553       cimg_save_pandore_case(0,0,1,"char",9);
09554       cimg_save_pandore_case(0,0,1,"short",9);
09555       cimg_save_pandore_case(0,0,1,"unsigned short",9);
09556       cimg_save_pandore_case(0,0,1,"unsigned int",9);
09557       cimg_save_pandore_case(0,0,1,"int",9);
09558       cimg_save_pandore_case(0,0,1,"unsigned long",10);
09559       cimg_save_pandore_case(0,0,1,"long",9);
09560       cimg_save_pandore_case(0,0,1,"float",10);
09561       cimg_save_pandore_case(0,0,1,"double",10);
09562       
09563       cimg_save_pandore_case(0,1,3,"unsigned char",16);
09564       cimg_save_pandore_case(0,1,3,"char",17);
09565       cimg_save_pandore_case(0,1,3,"short",17);
09566       cimg_save_pandore_case(0,1,3,"unsigned short",17);
09567       cimg_save_pandore_case(0,1,3,"unsigned int",17);
09568       cimg_save_pandore_case(0,1,3,"int",17);
09569       cimg_save_pandore_case(0,1,3,"unsigned long",18);
09570       cimg_save_pandore_case(0,1,3,"long",17);
09571       cimg_save_pandore_case(0,1,3,"float",18);
09572       cimg_save_pandore_case(0,1,3,"double",18);
09573 
09574       cimg_save_pandore_case(0,0,3,"unsigned char",19);
09575       cimg_save_pandore_case(0,0,3,"char",20);
09576       cimg_save_pandore_case(0,0,3,"short",20);
09577       cimg_save_pandore_case(0,0,3,"unsigned short",20);
09578       cimg_save_pandore_case(0,0,3,"unsigned int",20);
09579       cimg_save_pandore_case(0,0,3,"int",20);
09580       cimg_save_pandore_case(0,0,3,"unsigned long",21);
09581       cimg_save_pandore_case(0,0,3,"long",20);
09582       cimg_save_pandore_case(0,0,3,"float",21);
09583       cimg_save_pandore_case(0,0,3,"double",21);
09584      
09585       cimg_save_pandore_case(1,1,0,"unsigned char",22);
09586       cimg_save_pandore_case(1,1,0,"char",23);
09587       cimg_save_pandore_case(1,1,0,"short",23);
09588       cimg_save_pandore_case(1,1,0,"unsigned short",23);
09589       cimg_save_pandore_case(1,1,0,"unsigned int",23);
09590       cimg_save_pandore_case(1,1,0,"int",23);
09591       cimg_save_pandore_case(1,1,0,"unsigned long",25);
09592       cimg_save_pandore_case(1,1,0,"long",23);
09593       cimg_save_pandore_case(1,1,0,"float",25);
09594       cimg_save_pandore_case(1,1,0,"double",25);
09595  
09596       cimg_save_pandore_case(0,1,0,"unsigned char",26);
09597       cimg_save_pandore_case(0,1,0,"char",27);
09598       cimg_save_pandore_case(0,1,0,"short",27);
09599       cimg_save_pandore_case(0,1,0,"unsigned short",27);
09600       cimg_save_pandore_case(0,1,0,"unsigned int",27);
09601       cimg_save_pandore_case(0,1,0,"int",27);
09602       cimg_save_pandore_case(0,1,0,"unsigned long",29);
09603       cimg_save_pandore_case(0,1,0,"long",27);
09604       cimg_save_pandore_case(0,1,0,"float",29);
09605       cimg_save_pandore_case(0,1,0,"double",29);
09606 
09607       cimg_save_pandore_case(0,0,0,"unsigned char",30);
09608       cimg_save_pandore_case(0,0,0,"char",31);
09609       cimg_save_pandore_case(0,0,0,"short",31);
09610       cimg_save_pandore_case(0,0,0,"unsigned short",31);
09611       cimg_save_pandore_case(0,0,0,"unsigned int",31);
09612       cimg_save_pandore_case(0,0,0,"int",31);
09613       cimg_save_pandore_case(0,0,0,"unsigned long",33);
09614       cimg_save_pandore_case(0,0,0,"long",31);
09615       cimg_save_pandore_case(0,0,0,"float",33);
09616       cimg_save_pandore_case(0,0,0,"double",33);
09617 
09618       cimg::fclose(file);
09619       return *this;
09620     }
09621 
09623     const CImg& save_bmp(const char* filename) const {
09624       cimg_test(*this,"CImg<T>::save_bmp");
09625       std::FILE *file = cimg::fopen(filename,"wb");
09626       
09627       unsigned char header[54]={0}, align_buf[4]={0};
09628       const unsigned int 
09629         align     = (4-(3*width)%4)%4,
09630         buf_size  = (3*width+align)*dimy(),
09631         file_size = 54+buf_size;
09632       header[0] = 'B'; header[1] = 'M';
09633       header[0x02]=file_size&0xFF; header[0x03]=(file_size>>8)&0xFF;
09634       header[0x04]=(file_size>>16)&0xFF; header[0x05]=(file_size>>24)&0xFF;
09635       header[0x0A]=0x36;
09636       header[0x0E]=0x28;
09637       header[0x12]=width&0xFF; header[0x13]=(width>>8)&0xFF;
09638       header[0x14]=(width>>16)&0xFF; header[0x15]=(width>>24)&0xFF;
09639       header[0x16]=height&0xFF; header[0x17]=(height>>8)&0xFF;
09640       header[0x18]=(height>>16)&0xFF; header[0x19]=(height>>24)&0xFF;
09641       header[0x1A]=1;  header[0x1B]=0;
09642       header[0x1C]=24; header[0x1D]=0;
09643       header[0x22]=buf_size&0xFF; header[0x23]=(buf_size>>8)&0xFF;
09644       header[0x24]=(buf_size>>16)&0xFF; header[0x25]=(buf_size>>24)&0xFF;
09645       header[0x27]=0x1; header[0x2B]=0x1;
09646       cimg::fwrite(header,sizeof(unsigned char),54,file);
09647 
09648       const T
09649         *pR = ptr(0,height-1,0,0),
09650         *pG = (dim>=2)?ptr(0,height-1,0,1):pR, 
09651         *pB = (dim>=3)?ptr(0,height-1,0,2):pR;
09652 
09653       cimg_mapY(*this,y) {
09654         cimg_mapX(*this,x) {
09655           std::fputc((unsigned char)(*(pB++)),file);
09656           std::fputc((unsigned char)(*(pG++)),file);
09657           std::fputc((unsigned char)(*(pR++)),file);
09658         }
09659         std::fwrite(align_buf,sizeof(unsigned char),align,file);
09660         pR-=2*width; pG-=2*width; pB-=2*width;  
09661       }      
09662       cimg::fclose(file);
09663       return *this;
09664     }
09665     
09667     // Most of this function has been written by Eric Fausett
09682     const CImg& save_png(const char* filename, const bool png16=false) const {
09683       cimg_test(*this,"CImg<T>::save_png");
09684 #ifndef cimg_use_png
09685       return save_convert(filename);
09686 #else
09687       std::FILE *file = cimg::fopen(filename,"wb");
09688       
09689       // Setup PNG structures for write
09690       png_voidp user_error_ptr=0;
09691       png_error_ptr user_error_fn=0, user_warning_fn=0;
09692       png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
09693                                                     user_error_ptr, user_error_fn, user_warning_fn);
09694       if(!png_ptr){
09695         cimg::fclose(file);
09696         throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'png_ptr' data structure",pixel_type());
09697       }
09698       png_infop info_ptr = png_create_info_struct(png_ptr);
09699       if(!info_ptr){
09700         png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
09701         cimg::fclose(file);
09702         throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'info_ptr' data structure",pixel_type());
09703       }
09704       if (setjmp(png_jmpbuf(png_ptr))){
09705         png_destroy_write_struct(&png_ptr, &info_ptr);
09706         cimg::fclose(file);
09707         throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
09708       }
09709       
09710       png_init_io(png_ptr, file);      
09711       png_uint_32 width = dimx();
09712       png_uint_32 height = dimy();
09713       const int bit_depth = png16?16:8;
09714       int color_type;
09715       switch (dimv()) {
09716       case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
09717       case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
09718       case 3: color_type = PNG_COLOR_TYPE_RGB; break;
09719       default: color_type = PNG_COLOR_TYPE_RGB_ALPHA;
09720       }
09721       const int interlace_type = PNG_INTERLACE_NONE;
09722       const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
09723       const int filter_method = PNG_FILTER_TYPE_DEFAULT;
09724       png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,
09725                    compression_type, filter_method);
09726       png_write_info(png_ptr, info_ptr);
09727       const int byte_depth = bit_depth>>3;
09728       const int numChan = dimv()>4?4:dimv();
09729       const int pixel_bit_depth_flag = numChan * (bit_depth-1);
09730       
09731       // Allocate Memory for Image Save and Fill pixel data
09732       png_bytep *imgData = new png_byte*[height];
09733       for(unsigned int row=0; row<height; row++) imgData[row] = new png_byte[byte_depth * numChan * width];
09734       const T *pC0 = ptr(0,0,0,0);
09735       switch(pixel_bit_depth_flag) {
09736       case 7 :  { // Gray 8-bit
09737         cimg_mapY(*this,y) {
09738           unsigned char *ptrs = imgData[y];
09739           cimg_mapX(*this,x) *(ptrs++) = (unsigned char)*(pC0++);
09740         }
09741       } break;
09742       case 14: { // Gray w/ Alpha 8-bit
09743         const T *pC1 = ptr(0,0,0,1);
09744         cimg_mapY(*this,y) {
09745           unsigned char *ptrs = imgData[y];
09746           cimg_mapX(*this,x) {
09747             *(ptrs++) = (unsigned char)*(pC0++);
09748             *(ptrs++) = (unsigned char)*(pC1++);
09749           }
09750         }
09751       } break;
09752       case 21:  { // RGB 8-bit
09753         const T *pC1 = ptr(0,0,0,1);
09754         const T *pC2 = ptr(0,0,0,2);
09755         cimg_mapY(*this,y) {
09756           unsigned char *ptrs = imgData[y];
09757           cimg_mapX(*this,x) {
09758             *(ptrs++) = (unsigned char)*(pC0++);
09759             *(ptrs++) = (unsigned char)*(pC1++);
09760             *(ptrs++) = (unsigned char)*(pC2++);
09761           }
09762         }
09763       } break;
09764       case 28: { // RGB x/ Alpha 8-bit
09765         const T *pC1 = ptr(0,0,0,1);
09766         const T *pC2 = ptr(0,0,0,2);
09767         const T *pC3 = ptr(0,0,0,3);
09768         cimg_mapY(*this,y){
09769           unsigned char *ptrs = imgData[y];
09770           cimg_mapX(*this,x){
09771             *(ptrs++) = (unsigned char)*(pC0++);
09772             *(ptrs++) = (unsigned char)*(pC1++);
09773             *(ptrs++) = (unsigned char)*(pC2++);
09774             *(ptrs++) = (unsigned char)*(pC3++);
09775           }
09776         }
09777       } break;
09778       case 15: { // Gray 16-bit
09779         cimg_mapY(*this,y){
09780           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09781           cimg_mapX(*this,x) *(ptrs++) = (unsigned short)*(pC0++);
09782         }
09783       } break;
09784       case 30: { // Gray w/ Alpha 16-bit
09785         const T *pC1 = ptr(0,0,0,1);
09786         cimg_mapY(*this,y){
09787           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09788           cimg_mapX(*this,x) {
09789             *(ptrs++) = (unsigned short)*(pC0++);
09790             *(ptrs++) = (unsigned short)*(pC1++);
09791           }
09792         }
09793       } break;
09794       case 45: { // RGB 16-bit
09795         const T *pC1 = ptr(0,0,0,1);
09796         const T *pC2 = ptr(0,0,0,2);
09797         cimg_mapY(*this,y) {
09798           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09799           cimg_mapX(*this,x) {
09800             *(ptrs++) = (unsigned short)*(pC0++);
09801             *(ptrs++) = (unsigned short)*(pC1++);
09802             *(ptrs++) = (unsigned short)*(pC2++);
09803           }
09804         }
09805       } break;
09806       case 60: { // RGB x/ Alpha 16-bit
09807         const T *pC1 = ptr(0,0,0,1);
09808         const T *pC2 = ptr(0,0,0,2);
09809         const T *pC3 = ptr(0,0,0,3);
09810         cimg_mapY(*this,y) {
09811           unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
09812           cimg_mapX(*this,x) {
09813             *(ptrs++) = (unsigned short)*(pC0++);
09814             *(ptrs++) = (unsigned short)*(pC1++);
09815             *(ptrs++) = (unsigned short)*(pC2++);
09816             *(ptrs++) = (unsigned short)*(pC3++);
09817           }
09818         }
09819       } break;
09820       default:
09821         throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename);
09822         break;
09823       }
09824       png_write_image(png_ptr, imgData);      
09825       png_write_end(png_ptr, info_ptr);      
09826       png_destroy_write_struct(&png_ptr, &info_ptr);
09827       
09828       // Deallocate Image Write Memory
09829       for (unsigned int n=0; n<height; n++) delete[] imgData[n];
09830       delete[] imgData;      
09831       cimg::fclose(file);
09832       return *this;
09833 #endif
09834     }
09835 
09837     const CImg<T>& save_jpeg(const char *filename,const unsigned int quality=100) const {
09838       cimg_test(*this,"CImg<T>::save_jpeg");
09839 #ifndef cimg_use_jpeg
09840       return save_convert(filename);
09841 #else
09842       
09843       unsigned char *buf = new unsigned char[width*height*3], *buf2 = buf;
09844       const T *ptr_r = ptr(0,0,0,0),
09845         *ptr_g = ptr(0,0,0,dim>1?1:0),
09846         *ptr_b = ptr(0,0,0,dim>2?2:0);
09847       cimg_mapXY(*this,x,y) {
09848         *(buf2++) = (unsigned char)*(ptr_r++);
09849         *(buf2++) = (unsigned char)*(ptr_g++);
09850         *(buf2++) = (unsigned char)*(ptr_b++);
09851       }
09852       
09853       struct jpeg_compress_struct cinfo;
09854       struct jpeg_error_mgr jerr;
09855       cinfo.err = jpeg_std_error(&jerr);
09856       jpeg_create_compress(&cinfo);
09857       std::FILE *file = cimg::fopen(filename,"wb");
09858       jpeg_stdio_dest(&cinfo,file);
09859       cinfo.image_width = width;
09860       cinfo.image_height = height;
09861       cinfo.input_components = 3;
09862       cinfo.in_color_space = JCS_RGB;
09863       jpeg_set_defaults(&cinfo);
09864       jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
09865       jpeg_start_compress(&cinfo,TRUE);
09866       
09867       const unsigned int row_stride = width*3;
09868       JSAMPROW row_pointer[1];
09869       while (cinfo.next_scanline < cinfo.image_height) {
09870         row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
09871         jpeg_write_scanlines(&cinfo,row_pointer,1);
09872       }
09873       jpeg_finish_compress(&cinfo);
09874       delete[] buf;
09875       cimg::fclose(file);
09876       jpeg_destroy_compress(&cinfo);
09877       return *this;
09878 #endif
09879     }
09880 
09882     const CImg& save_rgba(const char *filename) const {
09883       cimg_test(*this,"CImg<T>::save_rgba");
09884       std::FILE *file = cimg::fopen(filename,"wb");
09885       const unsigned int wh = width*height;
09886       unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
09887       const T 
09888         *ptr1 = ptr(0,0,0,0),
09889         *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
09890         *ptr3 = dim>2?ptr(0,0,0,2):ptr1,
09891         *ptr4 = dim>3?ptr(0,0,0,3):NULL;
09892       for (unsigned int k=0; k<wh; k++) {
09893         *(nbuffer++) = (unsigned char)(*(ptr1++));
09894         *(nbuffer++) = (unsigned char)(*(ptr2++));
09895         *(nbuffer++) = (unsigned char)(*(ptr3++));
09896         *(nbuffer++) = (unsigned char)(ptr4?(*(ptr4++)):255);
09897       }
09898       cimg::fwrite(buffer,sizeof(unsigned char),4*wh,file);
09899       cimg::fclose(file);
09900       delete[] buffer;
09901       return *this;
09902     }
09903     
09904 
09906     const CImg& save_rgb(const char *filename) const {
09907       cimg_test(*this,"CImg<T>::save_rgb");
09908       std::FILE *file = cimg::fopen(filename,"wb");
09909       const unsigned int wh = width*height;
09910       unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
09911       const T 
09912         *ptr1 = ptr(0,0,0,0),
09913         *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
09914         *ptr3 = dim>2?ptr(0,0,0,2):ptr1;
09915       for (unsigned int k=0; k<wh; k++) {
09916         *(nbuffer++) = (unsigned char)(*(ptr1++));
09917         *(nbuffer++) = (unsigned char)(*(ptr2++));
09918         *(nbuffer++) = (unsigned char)(*(ptr3++));
09919       }
09920       cimg::fwrite(buffer,sizeof(unsigned char),3*wh,file);
09921       cimg::fclose(file);
09922       delete[] buffer;
09923       return *this;
09924     }
09925     
09927     static CImg get_logo40x38() { 
09928       static bool first_time = true;
09929       static CImg<T> res(40,38,1,3);
09930       if (first_time) {
09931         const unsigned char *ptrs = cimg::logo40x38;
09932         T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
09933         for (unsigned int off = 0; off<res.width*res.height;) {
09934           const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
09935           for (unsigned int l=0; l<n; off++,l++) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
09936         }
09937         first_time = false;
09938       }      
09939       return res;
09940     }
09941        
09943     //------------------------------------------
09944     //------------------------------------------
09945     //
09947 
09948     //------------------------------------------
09949     //------------------------------------------
09950     CImg& swap(CImg& img) {
09951       cimg::swap(width,img.width);
09952       cimg::swap(height,img.height);
09953       cimg::swap(depth,img.depth);
09954       cimg::swap(dim,img.dim);
09955       cimg::swap(data,img.data);
09956       return img;
09957     }
09958 
09959 #ifdef cimg_plugin
09960 #include cimg_plugin
09961 #endif
09962     
09964   };
09965 
09966 
09967   /*-------------------------------------------------------
09968     
09969 
09970 
09971 
09972   Definition of the CImgl<> structure
09973 
09974 
09975 
09976 
09977   ------------------------------------------------------*/
09978 
09980   template<typename T> struct CImgl {       
09982 
09985     unsigned int size;
09986     
09988 
09992     CImg<T> *data;                      
09993     
09994     //------------------------------------------
09995     //------------------------------------------
09996     //
09998 
09999     //------------------------------------------
10000     //------------------------------------------
10001     
10003     static const char* pixel_type() { T val; return cimg::get_type(val); }
10004     
10006     CImgl(const unsigned int n=0,const unsigned int width=0,const unsigned int height=1,
10007           const unsigned int depth=1, const unsigned int dim=1):size(n) {
10008       if (n) {
10009         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10010         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim);
10011       } else data = NULL;
10012     }
10013 
10015     CImgl(const unsigned int n,const unsigned int width,const unsigned int height,
10016           const unsigned int depth, const unsigned int dim,const T& val):size(n) {
10017       if (n) {
10018         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10019         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim,val);
10020       } else data = NULL;
10021     }
10022     
10023     // ! Create a list of \p n copy of the input image.
10024     template<typename t> CImgl(const unsigned int n, const CImg<t>& img):size(n) {
10025       if (n) {
10026         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
10027         cimgl_map(*this,l) data[l]=img;
10028       } else data = NULL;
10029     }
10030     
10032     template<typename t> CImgl(const CImgl<t>& list):size(list.size) {
10033       if (size) {
10034         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
10035         cimgl_map(*this,l) data[l] = list[l];
10036       } else data = NULL;
10037     }
10038     CImgl(const CImgl<T>& list):size(list.size) {
10039       if (size>0) {
10040         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
10041         cimgl_map(*this,l) data[l] = list[l];
10042       } else data = NULL;
10043     }
10044 
10046     CImgl(const char* filename):size(0),data(NULL) { load(filename).swap(*this); }
10047     
10049     CImgl(const CImg<T>& img):size(0),data(NULL) { CImgl<T>(1,img).swap(*this); }
10050 
10052     CImgl(const CImg<T>& img1,const CImg<T>& img2):size(2) {
10053       data = new CImg<T>[cimg::lblock];
10054       data[0] = img1;
10055       data[1] = img2;
10056     }
10057 
10059     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3):size(3) {
10060       data = new CImg<T>[cimg::lblock];
10061       data[0] = img1;
10062       data[1] = img2;
10063       data[2] = img3;
10064     }
10065 
10067     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3,const CImg<T>& img4):size(4) {
10068       data = new CImg<T>[cimg::lblock];
10069       data[0] = img1;
10070       data[1] = img2;
10071       data[2] = img3;
10072       data[3] = img4;
10073     }
10074     
10076     template<typename t> CImgl& operator=(const CImgl<t>& list) { 
10077       if (list.size>size) return CImgl<T>(list).swap(*this); 
10078       size = list.size;
10079       cimgl_map(*this,l) data[l] = list[l];
10080       return *this;
10081     }
10082 
10083     CImgl& operator=(const CImgl<T>& list) { 
10084       if (&list==this) return *this; 
10085       if (list.size>size) return CImgl<T>(list).swap(*this);
10086       size = list.size;
10087       cimgl_map(*this,l) data[l] = list[l];
10088       return *this;
10089     }
10090     
10092     ~CImgl() { if (data) delete[] data; }
10093     
10095     CImgl& empty() { return CImgl<T>().swap(*this); }
10096     
10098     //------------------------------------------
10099     //------------------------------------------
10100     //
10102 
10103     //------------------------------------------
10104     //------------------------------------------
10105     
10107     template<typename t> CImgl& operator+=(const CImgl<t>& list) {
10108       const unsigned int sizemax = min(size,list.size);
10109       for (unsigned int l=0; l<sizemax; l++) (*this)[l]+=list[l];
10110       return *this;
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     CImgl& operator+=(const T& val) { cimgl_map(*this,l) (*this)[l]+=val; return *this; }
10122     
10124     CImgl& operator-=(const T& val) { cimgl_map(*this,l) (*this)[l]-=val; return *this; }
10125     
10127     CImgl& operator*=(const double val) { cimgl_map(*this,l) (*this)[l]*=val; return *this; }
10128     
10130     CImgl& operator/=(const double val) { cimgl_map(*this,l) (*this)[l]/=val; return *this; }
10131     
10133     CImgl operator+(const T& val) const { return CImgl<T>(*this)+=val;  }
10134     
10136     CImgl operator*(const double val) const { return CImgl<T>(*this)*=val;  }
10137     
10139     CImgl operator-(const T& val) const { return CImgl<T>(*this)-=val;  }
10140     
10142     CImgl operator/(const double val) const { return CImgl<T>(*this)/=val;  }
10143     
10145     CImgl operator+(const CImgl& list) const { return CImgl<T>(*this)+=list; }
10146 
10148     CImgl operator-(const CImgl& list) const { return CImgl<T>(*this)-=list; }
10149     
10151     friend CImgl operator+(const T& val, const CImgl& list) { return CImgl<T>(list)+=val; }
10152     
10154     friend CImgl operator*(const double val, const CImgl& list) { return CImgl<T>(list)*=val; }
10155   
10157     //------------------------------------------
10158     //------------------------------------------
10159     //
10161 
10162     //------------------------------------------
10163     //------------------------------------------
10164     
10166     CImg<T>& operator[](const unsigned int pos) const {
10167 #if cimg_debug>1
10168       if (pos>=size) {
10169         cimg::warn(true,"CImgl<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size);
10170         return *data;
10171       }
10172 #endif
10173       return data[pos];
10174     }
10175     
10177     CImg<T>& operator()(const unsigned int pos) const { return (*this)[pos]; }
10178     
10180     CImgl& insert(const CImg<T>& img,const unsigned int pos) {
10181       if (pos>size) 
10182         throw CImgArgumentException("CImgl<%s>::insert() : Can't insert at position %u into a list with %u elements",
10183                                     pixel_type(),pos,size);
10184       CImg<T> *new_data = (!((++size)%cimg::lblock) || !data)?new CImg<T>[(size/cimg::lblock+1)*cimg::lblock]:NULL;
10185       if (!data) { data=new_data; *data=img; }
10186       else {
10187         if (new_data) {
10188           std::memcpy(new_data,data,sizeof(CImg<T>)*pos);
10189           if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
10190           std::memset(data,0,sizeof(CImg<T>)*(size-1));
10191           delete[] data;
10192           data = new_data;
10193         }
10194         else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
10195         data[pos].data = NULL;
10196         data[pos] = img;
10197       }
10198       return *this;
10199     }
10200     
10202     CImgl& insert(const CImg<T>& img) { return insert(img,size); }
10203     
10205     CImgl& insert(const CImgl<T>& list,const unsigned int pos) { 
10206       if (this!=&list) cimgl_map(list,l) insert(list[l],pos+l);
10207       else insert(CImgl<T>(list),pos);
10208       return *this; 
10209     }
10210     
10212     CImgl& insert(const CImgl<T>& list) { return insert(list,size); }
10213     
10215     CImgl& remove(const unsigned int pos) {
10216       if (pos>=size) { 
10217         cimg::warn(true,"CImgl<%s>::remove() : Can't remove an image from a list (%p,%u), at position %u",
10218                    pixel_type(),data,size,pos);
10219         return *this;
10220       }
10221       CImg<T> tmp; tmp.swap(data[pos]); // the image to remove will be freed
10222       size--;
10223       if (pos!=size) { 
10224         memmove(data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
10225         CImg<T> &tmp = data[size];
10226         tmp.width = tmp.height = tmp.depth = tmp.dim = 0;
10227         tmp.data = NULL;
10228       }
10229       return *this;
10230     }
10231 
10233     CImgl& remove() { 
10234       if (size) return remove(size-1); 
10235       cimg::warn(true,"CImgl<%s>::remove() : List is empty",pixel_type());
10236       return *this;
10237     }
10238 
10240     CImgl& reverse() {
10241       for (unsigned int l=0; l<size/2; l++) (*this)[l].swap((*this)[size-1-l]);
10242       return *this;
10243     }
10244     
10246     CImgl& get_reverse() { return CImgl<T>(*this).reverse(); }
10247 
10249     //------------------------------------------
10250     //------------------------------------------
10251     //
10253 
10254     //------------------------------------------
10255     //------------------------------------------
10256     
10258     CImgl& FFT(const char axe, const bool inverse=false) {
10259       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
10260       CImg<T> &Ir = data[0], &Ii = data[1];
10261       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
10262       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
10263         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
10264                                     pixel_type());
10265       switch (cimg::uncase(axe)) {
10266       case 'x': { // Fourier along X
10267         const unsigned int N = Ir.width, N2 = (N>>1);
10268         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
10269                                                            pixel_type(),N);
10270         for (unsigned int i=0,j=0; i<N2; i++) {
10271           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));
10272           if (j<N2) { 
10273             const unsigned int ri = N-1-i, rj = N-1-j;
10274             cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v)); 
10275           }}
10276           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10277         }
10278         for (unsigned int delta=2; delta<=N; delta<<=1) {
10279           const unsigned int delta2 = (delta>>1);
10280           for (unsigned int i=0; i<N; i+=delta) {
10281             float wr = 1, wi = 0;
10282             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10283                         ca = (float)std::cos(angle),
10284                         sa = (float)std::sin(angle);
10285             for (unsigned int k=0; k<delta2; k++) {
10286               const unsigned int j = i + k, nj = j + delta2;
10287               cimg_mapYZV(Ir,y,z,k) {
10288                 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);              
10289                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10290                 nir = ir - tmpr; nii = ii - tmpi;
10291                 ir += tmpr; ii += tmpi;
10292               }
10293               const float nwr = wr*ca-wi*sa;
10294               wi = wi*ca + wr*sa;
10295               wr = nwr;       
10296             }
10297           }       
10298         }
10299         if (inverse) (*this)/=N;
10300       } break;
10301 
10302       case 'y': { // Fourier along Y
10303         const unsigned int N = Ir.height, N2 = (N>>1);
10304         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
10305                                                            pixel_type(),N);
10306         for (unsigned int i=0,j=0; i<N2; i++) {
10307           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));
10308           if (j<N2) { 
10309             const unsigned int ri = N-1-i, rj = N-1-j;
10310             cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v)); 
10311           }}
10312           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10313         }
10314         for (unsigned int delta=2; delta<=N; delta<<=1) {
10315           const unsigned int delta2 = (delta>>1);
10316           for (unsigned int i=0; i<N; i+=delta) {
10317             float wr = 1, wi = 0;
10318             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10319                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
10320             for (unsigned int k=0; k<delta2; k++) {
10321               const unsigned int j = i + k, nj = j + delta2;
10322               cimg_mapXZV(Ir,x,z,k) {
10323                 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);              
10324                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10325                 nir = ir - tmpr; nii = ii - tmpi;
10326                 ir += tmpr; ii += tmpi;
10327               }
10328               const float nwr = wr*ca-wi*sa;
10329               wi = wi*ca + wr*sa;
10330               wr = nwr;       
10331             }
10332           }       
10333         }
10334         if (inverse) (*this)/=N;
10335       } break;
10336 
10337       case 'z': { // Fourier along Z
10338         const unsigned int N = Ir.depth, N2 = (N>>1);
10339         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
10340                                                            pixel_type(),N);
10341         for (unsigned int i=0,j=0; i<N2; i++) {
10342           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));
10343           if (j<N2) { 
10344             const unsigned int ri = N-1-i, rj = N-1-j;
10345             cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v)); 
10346           }}
10347           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
10348         }
10349         for (unsigned int delta=2; delta<=N; delta<<=1) {
10350           const unsigned int delta2 = (delta>>1);
10351           for (unsigned int i=0; i<N; i+=delta) {
10352             float wr = 1, wi = 0;
10353             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
10354                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
10355             for (unsigned int k=0; k<delta2; k++) {
10356               const unsigned int j = i + k, nj = j + delta2;
10357               cimg_mapXYV(Ir,x,y,k) {
10358                 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);              
10359                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
10360                 nir = ir - tmpr; nii = ii - tmpi;
10361                 ir += tmpr; ii += tmpi;
10362               }
10363               const float nwr = wr*ca-wi*sa;
10364               wi = wi*ca + wr*sa;
10365               wr = nwr;       
10366             }
10367           }       
10368         }
10369         if (inverse) (*this)/=N;
10370       } break;
10371 
10372       default: throw CImgArgumentException("CImg<%s>::FFT() : unknown axe '%c', must be 'x','y' or 'z'");
10373       }
10374       return *this; 
10375     }
10376 
10378     CImgl& FFT(const bool inverse=false) {
10379       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
10380       CImg<T> &Ir = data[0], &Ii = data[1];
10381       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
10382       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
10383         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
10384                                     pixel_type());
10385       if (Ir.depth>1)  FFT('z',inverse);
10386       if (Ir.height>1) FFT('y',inverse);
10387       if (Ir.width>1)  FFT('x',inverse);
10388       return *this;
10389     }
10390     
10392     CImgl get_FFT(const bool inverse=false) const { return CImgl<T>(*this).FFT(inverse); }
10393 
10395     CImgl get_FFT(const char axe,const bool inverse=false) const { return CImgl<T>(*this).FFT(axe,inverse); }
10396         
10398     //------------------------------------------
10399     //------------------------------------------
10400     //
10402 
10403     //------------------------------------------
10404     //------------------------------------------
10405     
10407     const CImgl& print(const char* title=NULL,const int print_flag=1) const { 
10408       char tmp[1024];
10409       std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p }\n",title?title:"CImgl",(void*)this,size,(void*)data);
10410       if (print_flag>0) cimgl_map(*this,l) {
10411         std::sprintf(tmp,"%s[%d]",title?title:"CImgl",l);
10412         data[l].print(tmp,print_flag);
10413       }
10414       return *this;
10415     }
10417 #define cimg_load_raw_case(Ts,Tss)                                               \
10418   if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l<n; l++) {  \
10419       const bool endian = cimg::endian();                               \
10420       j=0; while((i=std::fgetc(file))!='\n') tmp[j++]=(char)i; tmp[j]='\0';  \
10421       std::sscanf(tmp,"%u %u %u %u",&w,&h,&z,&k);                       \
10422       if (w*h*z*k>0) {                                                  \
10423         Tss *buf = new Tss[w*h*z*k]; cimg::fread(buf,sizeof(Tss),w*h*z*k,file);\
10424         if (endian) cimg::endian_swap(buf,w*h*z*k);                     \
10425         CImg<T> idest(w,h,z,k); cimg_mapoff(idest,off)                  \
10426                           idest[off] = (T)(buf[off]); idest.swap(res[l]); \
10427         delete[] buf;                                                   \
10428        }                                                                \
10429       loaded = true;                                                    \
10430     }
10431 
10432     static CImgl load_raw(const char *filename) {
10433       typedef unsigned char uchar;
10434       typedef unsigned short ushort;
10435       typedef unsigned int uint;  
10436       typedef unsigned long ulong; 
10437       std::FILE *file = cimg::fopen(filename,"rb");
10438       char tmp[256],tmp2[256];
10439       int i;
10440       bool loaded = false;
10441       unsigned int n,j,w,h,z,k,err;
10442       j=0; while((i=std::fgetc(file))!='\n' && i!=EOF) tmp[j++]=i; tmp[j]='\0';
10443       err=std::sscanf(tmp,"%u#%255[A-Za-z ]",&n,tmp2);
10444       if (err!=2) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', Unknow .raw header",pixel_type(),filename);
10445       CImgl<T> res(n);
10446       cimg_load_raw_case("unsigned char",uchar);
10447       cimg_load_raw_case("uchar",uchar);
10448       cimg_load_raw_case("char",char);
10449       cimg_load_raw_case("unsigned short",ushort);
10450       cimg_load_raw_case("ushort",ushort);
10451       cimg_load_raw_case("short",short);
10452       cimg_load_raw_case("unsigned int",uint);
10453       cimg_load_raw_case("uint",uint);
10454       cimg_load_raw_case("int",int);
10455       cimg_load_raw_case("unsigned long",ulong);
10456       cimg_load_raw_case("ulong",ulong);
10457       cimg_load_raw_case("long",long);
10458       cimg_load_raw_case("float",float);
10459       cimg_load_raw_case("double",double);
10460       if (!loaded) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', can't read images of %s",pixel_type(),filename,tmp2);
10461       cimg::fclose(file);
10462       return res;
10463     }
10464 
10466     static CImgl load(const char *filename) {
10467       CImgl res;
10468       const char *ext = cimg::filename_split(filename);
10469       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return load_raw(filename); else return CImg<T>(filename);
10470     }
10471 
10472 
10474 
10477     const CImgl& save(const char *filename) const {
10478       cimgl_test(*this,"CImgl<T>::save");
10479       const char *ext = cimg::filename_split(filename);
10480       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return save_raw(filename);
10481       else {
10482         if (size==1) data[0].save(filename,-1);
10483         else cimgl_map(*this,l) data[l].save(filename,l);
10484       }
10485       return *this;
10486     }
10487 
10489 
10494     const CImgl& save_raw(const char *filename) const {
10495       cimgl_test(*this,"CImgl<T>::save_raw");
10496       std::FILE *file = cimg::fopen(filename,"wb");
10497       std::fprintf(file,"%u#%s\n",size,pixel_type());
10498       cimgl_map(*this,l) {
10499         const CImg<T>& img = data[l];
10500         std::fprintf(file,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim);
10501         if (img.data) {
10502           if (cimg::endian()) {
10503             CImg<T> tmp(img);
10504             cimg::endian_swap(tmp.data,tmp.size());
10505             cimg::fwrite(tmp.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
10506           } else cimg::fwrite(img.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
10507         }
10508       }
10509       cimg::fclose(file);
10510       return *this;
10511     }  
10512 
10514 
10519     CImg<T> get_append(const char axe='x',const char align='c') const {
10520       cimgl_test(*this,"CImgl<T>::get_append");
10521       unsigned int dx=0,dy=0,dz=0,dv=0,pos=0;
10522       CImg<T> res;
10523       switch(cimg::uncase(axe)) {
10524       case 'x': {
10525         cimgl_map(*this,l) {
10526           const CImg<T>& img = (*this)[l];
10527           dx += img.width;
10528           dy = cimg::max(dy,img.height);
10529           dz = cimg::max(dz,img.depth);
10530           dv = cimg::max(dv,img.dim);
10531         }
10532         res = CImg<T>(dx,dy,dz,dv,0);
10533         switch (cimg::uncase(align)) {
10534         case 'p' : { cimgl_map(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break;
10535         case 'n' : { cimgl_map(*this,ll) { 
10536               res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width;
10537             }} break;
10538         default  : { cimgl_map(*this,ll) {
10539               res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
10540               pos+=(*this)[ll].width; 
10541             }} break;
10542         }
10543       } break;
10544       case 'y': {
10545         cimgl_map(*this,l) {
10546           const CImg<T>& img = (*this)[l];
10547           dx = cimg::max(dx,img.width);
10548           dy += img.height;
10549           dz = cimg::max(dz,img.depth);
10550           dv = cimg::max(dv,img.dim);
10551         }
10552         res = CImg<T>(dx,dy,dz,dv,0);
10553         switch (cimg::uncase(align)) {
10554         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break;
10555         case 'n': { cimgl_map(*this,ll) { 
10556               res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height;
10557             }} break;
10558         default : { cimgl_map(*this,ll) { 
10559               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
10560               pos+=(*this)[ll].height; 
10561             }} break;
10562         }
10563       } break;
10564       case 'z': {
10565         cimgl_map(*this,l) {
10566           const CImg<T>& img = (*this)[l];
10567           dx = cimg::max(dx,img.width);
10568           dy = cimg::max(dy,img.height);
10569           dz += img.depth;
10570           dv = cimg::max(dv,img.dim);
10571         }
10572         res = CImg<T>(dx,dy,dz,dv,0);
10573         switch (cimg::uncase(align)) {
10574         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break;
10575         case 'n': { cimgl_map(*this,ll) { 
10576               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth;
10577             }} break;
10578         case 'c': { cimgl_map(*this,ll) { 
10579               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2);
10580               pos+=(*this)[ll].depth; 
10581             }} break;
10582         }
10583       } break;
10584       case 'v': {
10585         cimgl_map(*this,l) {
10586           const CImg<T>& img = (*this)[l];
10587           dx = cimg::max(dx,img.width);
10588           dy = cimg::max(dy,img.height);
10589           dz = cimg::max(dz,img.depth);
10590           dv += img.dim;
10591         }
10592         res = CImg<T>(dx,dy,dz,dv,0);
10593         switch (cimg::uncase(align)) {
10594         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break;
10595         case 'n': { cimgl_map(*this,ll) { 
10596               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim;
10597             }} break;
10598         case 'c': { cimgl_map(*this,ll) { 
10599               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos);
10600               pos+=(*this)[ll].dim; 
10601             }} break;
10602         }
10603       } break;
10604       default: throw CImgArgumentException("CImg<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
10605       }
10606       return res;
10607     }
10608 
10609     // Create an auto-cropped font (along the X axis) from a input font \p font.
10610     CImgl<T> get_crop_font(const unsigned int padding=1) const {
10611       CImgl<T> res;
10612       cimgl_map(*this,l) {
10613         const CImg<T>& letter = (*this)[l];
10614         int xmin=letter.width, xmax = 0;
10615         cimg_mapXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
10616         if (xmin>xmax) res.insert(CImg<T>(4*padding,(*this)[' '].height,1,(*this)[' '].dim,0));
10617         else res.insert(letter.get_crop(xmin,0,xmax+padding,letter.height));
10618       }
10619       return res;
10620     }
10621     
10622     CImgl<T>& crop_font(const unsigned int padding=1) {
10623       return get_crop_font(padding).swap(*this);
10624     }
10625 
10627 
10631     static CImgl<T> get_font(const unsigned int *const font,const unsigned int w,const unsigned int h,
10632                              const int padding=1) {
10633       CImgl<T> res = CImgl<T>(256,w,h,1,3).insert(CImgl<T>(256,w,h,1,1));
10634       const unsigned int *ptr = font;
10635       unsigned long m = 0, val = 0;
10636       for (unsigned int y=0; y<h; y++)
10637         for (unsigned int x=0; x<256*w; x++) {
10638           m>>=1; if (!m) { m=0x80000000; val = *(ptr++); }
10639           CImg<T>& img = res[x/w], &mask = res[x/w+256];
10640           unsigned int xm = x%w;
10641           img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
10642         }
10643       if (padding>=0) return res.get_crop_font(padding);
10644       return res;
10645     }
10646 
10647     static CImgl<T> get_font10x13(const bool fixed_size = false) {
10648       static CImgl<T> nfixed, fixed;
10649       if (fixed_size) {
10650         if (!fixed.size) fixed = get_font(cimg::font10x13,10,13,-1);
10651         return fixed;
10652       } 
10653       if (!nfixed.size) nfixed = get_font(cimg::font10x13,10,13,1);
10654       return nfixed;
10655     }
10656 
10657     static CImgl<T> get_font7x11(const bool fixed_size = false) {
10658       static CImgl<T> nfixed, fixed;
10659       if (fixed_size) {
10660         if (!fixed.size) fixed = get_font(cimg::font7x11,7,11,-1);
10661         return fixed;
10662       } 
10663       if (!nfixed.size) nfixed = get_font(cimg::font7x11,7,11,1);
10664       return nfixed;
10665     }
10666     
10668 
10677     const CImgl& display(CImgDisplay& disp,const char axe='x',const char align='c') const { 
10678       get_append(axe,align).display(disp); return *this; 
10679     }
10680 
10682 
10691     const CImgl& display(CImgDisplay* disp,const char axe='x',const char align='c') const { 
10692       if (!disp) throw CImgArgumentException("CImgl<%s>::display() : given display pointer is (null)",pixel_type());
10693       else display(*disp,axe,align);
10694       return *this;
10695     }
10696 
10698 
10711     const CImgl& display(const char* title,const char axe='x',const char align='c',
10712                          const int min_size=128,const int max_size=1024) const {
10713       get_append(axe,align).display(title,min_size,max_size);
10714       return *this;
10715     }
10716 
10718 
10730     const CImgl& display(const char axe='x',const char align='c',
10731                          const int min_size=128,const int max_size=1024) const {
10732       return display("",axe,align,min_size,max_size); 
10733     }
10734 
10736 
10739     const CImgl& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
10740     
10741     // Swap fields of two CImgl instances.
10742     CImgl& swap(CImgl& list) {
10743       cimg::swap(size,list.size);
10744       cimg::swap(data,list.data);
10745       return list;
10746     }
10747 
10748 #ifdef cimgl_plugin
10749 #include cimgl_plugin
10750 #endif
10751    
10753   };
10754 
10755 
10757 
10763   template<typename T> struct CImgROI : public CImg<T> {
10764     CImgROI(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,T *const pdata) {
10765       CImg<T>::width = dx; CImg<T>::height = dy; CImg<T>::depth = dz; CImg<T>::dim = dv; CImg<T>::data = pdata;
10766     }
10767     CImgROI(const CImgROI& roi):CImg<T>() {
10768       CImg<T>::width = roi.width; CImg<T>::height = roi.height; CImg<T>::depth = roi.depth; CImg<T>::dim = roi.dim; 
10769       CImg<T>::data = roi.data;
10770     }
10771     ~CImgROI() { CImg<T>::width=CImg<T>::height=CImg<T>::depth=CImg<T>::dim=0; CImg<T>::data=NULL;}
10772     
10773     template<typename t> CImgROI<T>& operator=(const CImg<t>& img) { 
10774       if (img.width!=CImg<T>::width || img.height!=CImg<T>::height ||
10775           img.depth!=CImg<T>::depth || img.dim!=CImg<T>::dim)
10776         throw CImgArgumentException("CImgROI<%s>::operator=() : Affectation to CImgROI instances must supply "
10777                                     "data with same dimensions",CImg<T>::pixel_type());
10778       const t* ptrs = img.data + CImg<T>::size();
10779       for (T *ptrd = CImg<T>::data+CImg<T>::size(); ptrd>CImg<T>::data; ) *(--ptrd) = (T)*(--ptrs);
10780       return *this;
10781     }
10782 
10783     CImgROI& operator=(const CImg<T>& img) {
10784       if (&img==this) return *this;
10785       if (img.width!=CImg<T>::width || img.height!=CImg<T>::height ||
10786           img.depth!=CImg<T>::depth || img.dim!=CImg<T>::dim)
10787         throw CImgArgumentException("CImgROI<%s>::operator=() : Affectation to CImgROI instances must supply "
10788                                     "data with same dimensions",CImg<T>::pixel_type());
10789       std::memcpy(CImg<T>::data,img.data,sizeof(T)*CImg<T>::size());
10790       return *this;
10791     }
10792     
10793   };
10794 
10795 namespace cimg {
10796   
10798 
10814   template<typename t>
10815   static int dialog(const char *title,const char *msg,
10816                     const char *button1_txt,const char *button2_txt,
10817                     const char *button3_txt,const char *button4_txt,
10818                     const char *button5_txt,const char *button6_txt,
10819                     const CImg<t>& logo) {
10820 #if cimg_display_type!=0
10821     const unsigned char
10822       black[3]={0,0,0}, white[3]={255,255,255}, gray[3]={200,200,200}, gray2[3]={150,150,150};
10823       
10824       // Create buttons and canvas graphics
10825       CImgl<unsigned char> buttons, cbuttons, sbuttons;
10826       const CImgl<unsigned char> tahoma = CImgl<unsigned char>::get_font10x13(false);
10827       if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(button1_txt,0,0,black,gray,tahoma));
10828       if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(button2_txt,0,0,black,gray,tahoma));
10829       if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(button3_txt,0,0,black,gray,tahoma));
10830       if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(button4_txt,0,0,black,gray,tahoma));
10831       if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(button5_txt,0,0,black,gray,tahoma));
10832       if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(button6_txt,0,0,black,gray,tahoma));
10833       }}}}}}
10834       if (!buttons.size) throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
10835       
10836       unsigned int bw=0, bh=0;
10837       cimgl_map(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
10838       bw+=8; bh+=8;
10839       if (bw<64) bw=64;
10840       if (bw>128) bw=128;
10841       if (bh<24) bh=24;
10842       if (bh>48) bh=48;
10843       
10844       CImg<unsigned char> button = CImg<unsigned char>(bw,bh,1,3).
10845         draw_rectangle(0,0,bw-1,bh-1,gray).
10846         draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white).
10847         draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black).
10848         draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
10849       CImg<unsigned char> sbutton = CImg<unsigned char>(bw,bh,1,3).
10850         draw_rectangle(0,0,bw-1,bh-1,gray).
10851         draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black).
10852         draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black).
10853         draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white).
10854         draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black).
10855         draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2).
10856         draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA).
10857         draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA);
10858       CImg<unsigned char> cbutton = CImg<unsigned char>(bw,bh,1,3).
10859         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).
10860         draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA).
10861         draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA);
10862 
10863         cimgl_map(buttons,ll) {
10864           cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(buttons[ll],1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2));
10865           sbuttons.insert(CImg<unsigned char>(sbutton).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2));
10866           buttons[ll] = CImg<unsigned char>(button).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2);
10867         }
10868         
10869         CImg<unsigned char> canvas;
10870         if (msg) canvas = CImg<unsigned char>().draw_text(msg,0,0,black,gray,tahoma);
10871         const unsigned int 
10872           bwall = (buttons.size-1)*(12+bw) + bw,
10873           w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
10874           h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
10875           lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
10876           ly = (h-12-bh-logo.height)/2,
10877           tx = lx+logo.width+12,
10878           ty = (h-12-bh-canvas.height)/2,
10879           bx = (w-bwall)/2,
10880           by = h-12-bh;
10881         
10882         if (canvas.data)
10883           canvas = CImg<unsigned char>(w,h,1,3).
10884             draw_rectangle(0,0,w-1,h-1,gray).
10885             draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
10886             draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
10887             draw_image(canvas,tx,ty);
10888         else 
10889           canvas = CImg<unsigned char>(w,h,1,3).
10890             draw_rectangle(0,0,w-1,h-1,gray).
10891             draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
10892             draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
10893         if (logo.data) canvas.draw_image(logo,lx,ly);
10894         
10895         unsigned int xbuttons[6];
10896         cimgl_map(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(buttons[lll],xbuttons[lll],by); }
10897         
10898         // Open window and enter events loop  
10899         CImgDisplay disp(canvas,title?title:"",0,3);
10900         bool stopflag = false, refresh = false;
10901         int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
10902         while (!disp.closed && !stopflag) {
10903           if (refresh) {
10904             if (clicked>=0) CImg<unsigned char>(canvas).draw_image(cbuttons[clicked],xbuttons[clicked],by).display(disp);
10905             else {
10906               if (selected>=0) CImg<unsigned char>(canvas).draw_image(sbuttons[selected],xbuttons[selected],by).display(disp);
10907               else canvas.display(disp);
10908             }
10909             refresh = false;
10910           }
10911           disp.wait(40);
10912           if (disp.resized) disp.resize(disp);
10913           
10914           if (disp.button&1)  {
10915             oclicked = clicked;
10916             clicked = -1;
10917             cimgl_map(buttons,l)
10918               if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
10919                   disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
10920                 clicked = selected = l;
10921                 refresh = true;
10922               }
10923             if (clicked!=oclicked) refresh = true;
10924           } else if (clicked>=0) stopflag = true;
10925           
10926           if (disp.key) {
10927             oselected = selected;
10928             switch (disp.key) {
10929             case cimg::keyESC: selected=-1; stopflag=true; break;
10930             case cimg::keyENTER: if (selected<0) selected=0; stopflag = true; break;
10931             case cimg::keyTAB:
10932             case cimg::keyARROWRIGHT:
10933             case cimg::keyARROWDOWN: selected = (selected+1)%buttons.size; break;
10934             case cimg::keyARROWLEFT:
10935             case cimg::keyARROWUP: selected = (selected+buttons.size-1)%buttons.size; break;
10936             }
10937             disp.key=0;
10938             if (selected!=oselected) refresh = true;
10939           }
10940         }
10941         if (disp.closed) selected = -1;
10942         return selected;
10943 #else
10944         std::fprintf(stderr,"<%s>\n\n%s\n\n",title,msg);
10945         return -1;
10946 #endif
10947   }
10948   
10949   static int dialog(const char *title,const char *msg,const char *button1_txt,const char *button2_txt,
10950                     const char *button3_txt,const char *button4_txt,const char *button5_txt,const char *button6_txt) {
10951     return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
10952                   CImg<unsigned char>::get_logo40x38());
10953   }
10954 }
10955 
10956 }
10957 
10958 // Overcome VisualC++ 6.0 and DMC compilers namespace bug
10959 #if ( defined(_MSC_VER) || defined(__DMC__) ) && defined(std)
10960 #undef std
10961 #endif
10962 
10963 /*--------------------------------------------------------------------------------------
10964 
10965 
10966 
10967   Additional documentation for the generation of the reference page (using doxygen)
10968 
10969 
10970 
10971   -------------------------------------------------------------------------------------*/
10990 //---------------------------------------------------------------------------------------------------------------
10992 
11131 
11132 //--------------------------------------------------------------------------------------------------------------------
11134 
11205 
11206 //--------------------------------------------------------------------------------------------------------------------
11208 
11306 
11307 //----------------------------------------------------------------------------------------------------
11309 
11331 
11332 //----------------------------------------------------------------------------------------------------
11334 
11570 
11571 //----------------------------------------------------------------------------------------------------
11573 
11594 
11595 
11596 //----------------------------------------------------------------------------------------------------
11598 
11604 
11605 
11606 
11607 
11608 //----------------------------------------------------------------------------------------------------
11610 
11627 
11628 //----------------------------------------------------------------------------------------------------
11630 
11716 //----------------------------------------------------------------------------------------------------
11717 #endif
11718 
11719 // Local Variables:
11720 // mode: c++
11721 // End:

Generated on Tue Jun 21 09:19:28 2005 for The CImg Library by  doxygen 1.3.9