The C++ Template Image Processing Library. |

[Introduction]- [News]- [Download]- [Screenshots]- [Tutorial]- [Forums]- [Reference]- [SourceForge Repository ]

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

# CImg.h

    00001 /*------------------------------------------------------------------------------------------------------
    00002
    00003   File        : CImg.h
    00004
    00005   Description : The C++ Template Image Processing Library
    00006                 ( http://cimg.sourceforge.net )
    00007
    00008   Author      : 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.08
    00041 #include <cstdio>
    00042 #include <cstdlib>
    00043 #include <cstdarg>
    00044 #include <cmath>
    00045 #include <cstring>
    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   Auto-detect and set CImg Library 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)
    00065 // Sun Unix
    00066 #define cimg_OS            0
    00067 #ifndef cimg_display_type
    00068 #define cimg_display_type  1
    00069 #endif
    00070 #ifndef cimg_color_terminal
    00071 #define cimg_color_terminal
    00072 #endif
    00073 #elif defined(linux) || defined(__linux) || defined(__CYGWIN__) || defined(__FreeBSD__)
    00074 // PC Unix (including Linux and FreeBSD)
    00075 #define cimg_OS            1
    00076 #ifndef cimg_display_type
    00077 #define cimg_display_type  1
    00078 #endif
    00079 #ifndef cimg_color_terminal
    00080 #define cimg_color_terminal
    00081 #endif
    00082 #elif defined(_WIN32) || defined(__WIN32__)
    00083 // PC Windows
    00084 #define cimg_OS            2
    00085 #ifndef cimg_display_type
    00086 #define cimg_display_type  2
    00087 #endif
    00088 #elif defined(__MACOSX__) || defined(__APPLE__)
    00089 // Mac OS X
    00090 #define cimg_OS            3
    00091 #ifndef cimg_display_type
    00092 #define cimg_display_type  1
    00093 #endif
    00094 #else
    00095 // Unknown configuration : compile without dependencies.
    00096 #define cimg_OS           -1
    00097 #ifndef cimg_display_type
    00098 #define cimg_display_type  0
    00099 #endif
    00100 #endif
    00101 #endif
    00102
    00103 // Debug configuration.
    00104 //--------------------
    00105 // Define 'cimg_debug' to : 0 to remove dynamic debug messages (exceptions are still thrown)
    00106 //                          1 to display dynamic debug messages (default behavior).
    00107 //                          2 to add extra memory access controls (may slow down the code)
    00108 #ifndef cimg_debug
    00109 #define cimg_debug         1
    00110 #endif
    00111
    00112 // Architecture-dependent includes
    00113 //---------------------------------
    00114 #if cimg_OS!=2
    00115 #include <sys/time.h>
    00116 #include <unistd.h>
    00117 #else
    00118 #include <windows.h>
    00119 // Discard unuseful macros in windows.h
    00120 #ifdef min
    00121 #undef min
    00122 #undef max
    00123 #undef abs
    00124 #endif
    00125 #endif
    00126 #if cimg_display_type==1
    00127 #include <X11/Xlib.h>
    00128 #include <X11/Xutil.h>
    00129 #include <X11/keysym.h>
    00130 #include <pthread.h>
    00131 #endif
    00132
    00133 /*-----------------------------------------------------------------------------------
    00134
    00135
    00136    Define some macros. Macros of the CImg Library are prefixed by 'cimg_'
    00137    Documented macros below may be safely used in your own code.
    00138
    00139
    00140    ---------------------------------------------------------------------------------*/
    00141
    00142 // Macros used to describe the program usage, and retrieve command line arguments
    00143 // (See corresponding module 'Retrieving command line arguments' in the generated documentation).
    00144 #define cimg_usage(usage) cimg_library::cimg::option((char*)NULL,(unsigned int)argc,(char**)argv,(char*)NULL,(char*)usage)
    00145 #define cimg_option(name,defaut,usage) cimg_library::cimg::option((char*)name,(unsigned int)argc,(char**)argv,defaut,(char*)usage)
    00146
    00147 // Macros used for dynamic debug messages. Shouldn't be used in your own source code.
    00148 #define cimg_test(x,func)                                               \
    00149   if(!(x).width || !(x).height || !(x).depth || !(x).dim || !(x).data)  \
    00150     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is empty", \
    00151                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00152 #define cimgl_test(x,func) \
    00153   if(!(x).size || !(x).data) \
    00154     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImgl<%s> %s = (%d,%p) is empty", \
    00155                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).size,(x).data)
    00156 #define cimg_test_scalar(x,func) \
    00157   if(!(x).width || !(x).height || !(x).depth || (x).dim!=1 || !(x).data) \
    00158     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not scalar", \
    00159                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00160 #define cimg_test_matrix(x,func) \
    00161   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || !(x).data) \
    00162     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a matrix", \
    00163                                 func,__FILE__,__LINE__,(x).pixel_type(),#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00164 #define cimg_test_square(x,func) \
    00165   if(!(x).width || !(x).height || (x).depth!=1 || (x).dim!=1 || (x).width!=(x).height || !(x).data) \
    00166     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', line %d), CImg<%s> %s = (%d,%d,%d,%d,%p) is not a square matrix", \
    00167                                 func,__FILE__,__LINE__,(x).pixel_type,#x,(x).width,(x).height,(x).depth,(x).dim,(x).data)
    00168 #define cimg_test_display(x,func) \
    00169   if (!(x).width || !(x).height) \
    00170     throw CImgInstanceException("(Instance error) : In function '%s()' ('%s', l.%d), CImgDisplay %s = (%d,%d) is not a valid display", \
    00171                                 func,__FILE__,__LINE__,#x,(x).width,(x).height)
    00172
    00173 // Macros used for neighborhood definitions and manipulations (see module 'Using Image Loops' in the generated documentation).
    00174 #define CImg_2x2(I,T)     T I##cc,I##nc=0,I##cn,I##nn=0
    00175 #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
    00176 #define CImg_4x4(I,T)     T I##pp,I##cp,I##np=0,I##ap=0, \
    00177                             I##pc,I##cc,I##nc=0,I##ac=0, \
    00178                             I##pn,I##cn,I##nn=0,I##an=0, \
    00179                             I##pa,I##ca,I##na=0,I##aa=0
    00180 #define CImg_5x5(I,T)     T I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \
    00181                             I##bp,I##pp,I##cp,I##np=0,I##ap=0, \
    00182                             I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \
    00183                             I##bn,I##pn,I##cn,I##nn=0,I##an=0, \
    00184                             I##ba,I##pa,I##ca,I##na=0,I##aa=0
    00185 #define CImg_2x2x2(I,T)   T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \
    00186                             I##ccn,I##ncn=0,I##cnn,I##nnn=0
    00187 #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, \
    00188                             I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \
    00189                             I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0
    00190
    00191 #define CImg_2x2_ref(I,T,tab)   T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3];
    00192 #define CImg_3x3_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \
    00193                                   &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \
    00194                                   &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8]
    00195 #define CImg_4x4_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2],&I##ap=(tab)[3], \
    00196                                   &I##pc=(tab)[4],&I##cc=(tab)[5],&I##nc=(tab)[6],&I##ap=(tab)[7], \
    00197                                   &I##pn=(tab)[8],&I##cn=(tab)[9],&I##nn=(tab)[10],&I##aa=(tab)[11], \
    00198                                   &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15]
    00199 #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], \
    00200                                   &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \
    00201                                   &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \
    00202                                   &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \
    00203                                   &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24]
    00204 #define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \
    00205                                   &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7]
    00206 #define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \
    00207                                   &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \
    00208                                   &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \
    00209                                   &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \
    00210                                   &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \
    00211                                   &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \
    00212                                   &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \
    00213                                   &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \
    00214                                   &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26]
    00215
    00216 #define cimg_squaresum2x2(I) ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn )
    00217 #define cimg_squaresum3x3(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \
    00218                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \
    00219                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn )
    00220 #define cimg_squaresum4x4(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
    00221                                I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
    00222                                I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
    00223                                I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
    00224 #define cimg_squaresum5x5(I) ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \
    00225                                I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
    00226                                I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
    00227                                I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
    00228                                I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
    00229 #define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \
    00230                                  I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn )
    00231 #define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \
    00232                                  I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \
    00233                                  I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \
    00234                                  I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \
    00235                                  I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \
    00236                                  I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \
    00237                                  I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \
    00238                                  I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \
    00239                                  I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn )
    00240
    00241 #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) )
    00242 #define cimg_corr3x3(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \
    00243                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \
    00244                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) )
    00245 #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) + \
    00246                             I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \
    00247                             I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \
    00248                             I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) )
    00249 #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) + \
    00250                             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) + \
    00251                             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) + \
    00252                             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) + \
    00253                             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) )
    00254 #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) + \
    00255                               I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) )
    00256 #define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \
    00257                               I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \
    00258                               I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \
    00259                               I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \
    00260                               I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \
    00261                               I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \
    00262                               I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \
    00263                               I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \
    00264                               I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) )
    00265
    00266 #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) )
    00267 #define cimg_conv3x3(I,m) ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \
    00268                             I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \
    00269                             I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
    00270 #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) + \
    00271                             I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
    00272                             I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
    00273                             I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
    00274 #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) + \
    00275                             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) + \
    00276                             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) + \
    00277                             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) + \
    00278                             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) )
    00279 #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) + \
    00280                               I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
    00281 #define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \
    00282                               I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \
    00283                               I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \
    00284                               I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \
    00285                               I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \
    00286                               I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
    00287                               I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \
    00288                               I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \
    00289                               I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
    00290
    00291 #define cimg_get2x2(img,x,y,z,v,I) I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
    00292     I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
    00293 #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), \
    00294     I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
    00295     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)
    00296 #define cimg_get4x4(img,x,y,z,v,I)                                      \
    00297   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), \
    00298     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), \
    00299     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), \
    00300     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)
    00301 #define cimg_get5x5(img,x,y,z,v,I)                                      \
    00302   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), \
    00303     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), \
    00304     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), \
    00305     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), \
    00306     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)
    00307 #define cimg_get2x2x2(img,x,y,z,v,I)                                    \
    00308   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), \
    00309     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)
    00310 #define cimg_get3x3x3(img,x,y,z,v,I)                                    \
    00311   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), \
    00312     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), \
    00313     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), \
    00314     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), \
    00315     I##pcc=(img)(_p##x,    y,    z,v), I##ccc=(img)(x,    y,    z,v), I##ncc=(img)(_n##x,    y,    z,v), \
    00316     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), \
    00317     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), \
    00318     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), \
    00319     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)
    00320
    00321 #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, \
    00322     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), \
    00323     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), \
    00324     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)
    00325
    00326 // Macros used to define special image loops (see module 'Using Image Loops' in the generated documentation).
    00327 #define cimg_map(img,ptr,T_ptr)   for (T_ptr *ptr=(img).data+(img).size()-1; ptr>=(img).data; ptr--)
    00328 #define cimgl_map(list,l)         for (unsigned int l=0; l<(list).size; l++)
    00329 #define cimg_mapoff(img,off)      for (unsigned int off=0; off<(img).size(); off++)
    00330 #define cimg_mapX(img,x)          for (int x=0; x<(int)((img).width); x++)
    00331 #define cimg_mapY(img,y)          for (int y=0; y<(int)((img).height);y++)
    00332 #define cimg_mapZ(img,z)          for (int z=0; z<(int)((img).depth); z++)
    00333 #define cimg_mapV(img,v)          for (int v=0; v<(int)((img).dim);   v++)
    00334 #define cimg_mapXY(img,x,y)       cimg_mapY(img,y) cimg_mapX(img,x)
    00335 #define cimg_mapXZ(img,x,z)       cimg_mapZ(img,z) cimg_mapX(img,x)
    00336 #define cimg_mapYZ(img,y,z)       cimg_mapZ(img,z) cimg_mapY(img,y)
    00337 #define cimg_mapXV(img,x,v)       cimg_mapV(img,v) cimg_mapX(img,x)
    00338 #define cimg_mapYV(img,y,v)       cimg_mapV(img,v) cimg_mapY(img,y)
    00339 #define cimg_mapZV(img,z,v)       cimg_mapV(img,v) cimg_mapZ(img,z)
    00340 #define cimg_mapXYZ(img,x,y,z)    cimg_mapZ(img,z) cimg_mapXY(img,x,y)
    00341 #define cimg_mapXYV(img,x,y,v)    cimg_mapV(img,v) cimg_mapXY(img,x,y)
    00342 #define cimg_mapXZV(img,x,z,v)    cimg_mapV(img,v) cimg_mapXZ(img,x,z)
    00343 #define cimg_mapYZV(img,y,z,v)    cimg_mapV(img,v) cimg_mapYZ(img,y,z)
    00344 #define cimg_mapXYZV(img,x,y,z,v) cimg_mapV(img,v) cimg_mapXYZ(img,x,y,z)
    00345 #define cimg_imapX(img,x,n)       for (int x=n; x<(int)((img).width-n); x++)
    00346 #define cimg_imapY(img,y,n)       for (int y=n; y<(int)((img).height-n); y++)
    00347 #define cimg_imapZ(img,z,n)       for (int z=n; z<(int)((img).depth-n); z++)
    00348 #define cimg_imapV(img,v,n)       for (int v=n; v<(int)((img).dim-n); v++)
    00349 #define cimg_imapXY(img,x,y,n)    cimg_imapY(img,y,n) cimg_imapX(img,x,n)
    00350 #define cimg_imapXYZ(img,x,y,z,n) cimg_imapZ(img,z,n) cimg_imapXY(img,x,y,n)
    00351 #define cimg_bmapX(img,x,n)       for (int x=0; x<(int)((img).width);  x==(n)-1?(x=(img).width-(n)): x++)
    00352 #define cimg_bmapY(img,y,n)       for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++)
    00353 #define cimg_bmapZ(img,z,n)       for (int z=0; z<(int)((img).depth);  z==(n)-1?(x=(img).depth-(n)): z++)
    00354 #define cimg_bmapV(img,v,n)       for (int v=0; v<(int)((img).dim);    v==(n)-1?(x=(img).dim-(n)):   v++)
    00355 #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++: \
    00356                                                           ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
    00357 #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++: \
    00358                                                              ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
    00359 #define cimg_2mapX(img,x)         for (int x=0,_n##x=1; _n##x<(int)((img).width)   || x==--_n##x; x++, _n##x++)
    00360 #define cimg_2mapY(img,y)         for (int y=0,_n##y=1; _n##y<(int)((img).height)  || y==--_n##y; y++, _n##y++)
    00361 #define cimg_2mapZ(img,z)         for (int z=0,_n##z=1; _n##z<(int)((img).depth)   || z==--_n##z; z++, _n##z++)
    00362 #define cimg_2mapXY(img,x,y)      cimg_2mapY(img,y) cimg_2mapX(img,x)
    00363 #define cimg_2mapXZ(img,x,z)      cimg_2mapZ(img,z) cimg_2mapX(img,x)
    00364 #define cimg_2mapYZ(img,y,z)      cimg_2mapZ(img,z) cimg_2mapY(img,y)
    00365 #define cimg_2mapXYZ(img,x,y,z)   cimg_2mapZ(img,z) cimg_2mapXY(img,x,y)
    00366 #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++)
    00367 #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++)
    00368 #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++)
    00369 #define cimg_3mapXY(img,x,y)      cimg_3mapY(img,y) cimg_3mapX(img,x)
    00370 #define cimg_3mapXZ(img,x,z)      cimg_3mapZ(img,z) cimg_3mapX(img,x)
    00371 #define cimg_3mapYZ(img,y,z)      cimg_3mapZ(img,z) cimg_3mapY(img,y)
    00372 #define cimg_3mapXYZ(img,x,y,z)   cimg_3mapZ(img,z) cimg_3mapXY(img,x,y)
    00373 #define cimg_4mapX(img,x)         for (int _p##x=0,x=0,_n##x=1,_a##x=2; \
    00374                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00375                                        _p##x=x++,_n##x++,_a##x++)
    00376 #define cimg_4mapY(img,y)         for (int _p##y=0,y=0,_n##y=1,_a##y=2; \
    00377                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
    00378                                        _p##y=y++,_n##y++,_a##y++)
    00379 #define cimg_4mapZ(img,z)         for (int _p##z=0,z=0,_n##z=1,_a##z=2; \
    00380                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
    00381                                        _p##z=z++,_n##z++,_a##z++)
    00382 #define cimg_4mapXY(img,x,y)      cimg_4mapY(img,y) cimg_4mapX(img,x)
    00383 #define cimg_4mapXZ(img,x,z)      cimg_4mapZ(img,z) cimg_4mapX(img,x)
    00384 #define cimg_4mapYZ(img,y,z)      cimg_4mapZ(img,z) cimg_4mapY(img,y)
    00385 #define cimg_4mapXYZ(img,x,y,z)   cimg_4mapZ(img,z) cimg_4mapXY(img,x,y)
    00386 #define cimg_5mapX(img,x)         for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \
    00387                                        _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00388                                        _b##x=_p##x,_p##x=x++,_n##x++,_a##x++)
    00389 #define cimg_5mapY(img,y)         for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \
    00390                                        _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
    00391                                        _b##y=_p##y,_p##y=y++,_n##y++,_a##y++)
    00392 #define cimg_5mapZ(img,z)         for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \
    00393                                        _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
    00394                                        _b##z=_p##z,_p##z=z++,_n##z++,_a##z++)
    00395 #define cimg_5mapXY(img,x,y)      cimg_5mapY(img,y) cimg_5mapX(img,x)
    00396 #define cimg_5mapXZ(img,x,z)      cimg_5mapZ(img,z) cimg_5mapX(img,x)
    00397 #define cimg_5mapYZ(img,y,z)      cimg_5mapZ(img,z) cimg_5mapY(img,y)
    00398 #define cimg_5mapXYZ(img,x,y,z)   cimg_5mapZ(img,z) cimg_5mapXY(img,x,y)
    00399
    00400 #define cimg_map2x2(img,x,y,z,v,I) cimg_2mapY(img,y)                    \
    00401        for (int _n##x=1, x=((int)(I##cc=(img)(0,  y,z,v),               \
    00402                                   I##cn=(img)(0,_n##y,z,v)),0);         \
    00403             (_n##x<(int)((img).width) && (                              \
    00404                                           I##nc=(img)(_n##x,    y,z,v), \
    00405                                           I##nn=(img)(_n##x,_n##y,z,v), \
    00406                                           1)) || x==--_n##x;            \
    00407             I##cc=I##nc, I##cn=I##nn,                                   \
    00408               x++,_n##x++ )
    00409
    00410 #define cimg_map3x3(img,x,y,z,v,I) cimg_3mapY(img,y)                    \
    00411        for (int _n##x=1, _p##x=(int)(I##cp=I##pp=(img)(0,_p##y,z,v),    \
    00412                                      I##cc=I##pc=(img)(0,  y,z,v),      \
    00413                                      I##cn=I##pn=(img)(0,_n##y,z,v)     \
    00414                                      ), x=_p##x=0;                      \
    00415             (_n##x<(int)((img).width) && (                              \
    00416                                           I##np=(img)(_n##x,_p##y,z,v), \
    00417                                           I##nc=(img)(_n##x,    y,z,v), \
    00418                                           I##nn=(img)(_n##x,_n##y,z,v), \
    00419                                           1)) || x==--_n##x;            \
    00420             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn,                      \
    00421               I##cp=I##np, I##cc=I##nc, I##cn=I##nn,                    \
    00422               _p##x=x++,_n##x++ )
    00423
    00424 #define cimg_map4x4(img,x,y,z,v,I) cimg_4mapY(img,y)                    \
    00425        for (int _a##x=2, _n##x=1, x=((int)(I##cp=I##pp=(img)(0,_p##y,z,v), \
    00426                                            I##cc=I##pc=(img)(0,    y,z,v), \
    00427                                            I##cn=I##pn=(img)(0,_n##y,z,v), \
    00428                                            I##ca=I##pa=(img)(0,_a##y,z,v), \
    00429                                            I##np=(img)(_n##x,_p##y,z,v), \
    00430                                            I##nc=(img)(_n##x,    y,z,v), \
    00431                                            I##nn=(img)(_n##x,_n##y,z,v), \
    00432                                            I##na=(img)(_n##x,_a##y,z,v)),0), \
    00433               _p##x=0;                                                  \
    00434             (_a##x<(int)((img).width) && (                              \
    00435                                           I##ap=(img)(_a##x,_p##y,z,v), \
    00436                                           I##ac=(img)(_a##x,    y,z,v), \
    00437                                           I##an=(img)(_a##x,_n##y,z,v), \
    00438                                           I##aa=(img)(_a##x,_a##y,z,v), \
    00439                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00440             I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca,         \
    00441               I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na,       \
    00442               I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa,       \
    00443               _p##x=x++, _n##x++, _a##x++ )
    00444
    00445 #define cimg_map5x5(img,x,y,z,v,I) cimg_5mapY(img,y)                    \
    00446        for (int _a##x=2, _n##x=1, _b##x=(int)(I##cb=I##pb=I##bb=(img)(0,_b##y,z,v), \
    00447                                               I##cp=I##pp=I##bp=(img)(0,_p##y,z,v), \
    00448                                               I##cc=I##pc=I##bc=(img)(0,    y,z,v), \
    00449                                               I##cn=I##pn=I##bn=(img)(0,_n##y,z,v), \
    00450                                               I##ca=I##pa=I##ba=(img)(0,_a##y,z,v), \
    00451                                               I##nb=(img)(_n##x,_b##y,z,v), \
    00452                                               I##np=(img)(_n##x,_p##y,z,v), \
    00453                                               I##nc=(img)(_n##x,   y,z,v), \
    00454                                               I##nn=(img)(_n##x,_n##y,z,v), \
    00455                                               I##na=(img)(_n##x,_a##y,z,v)), \
    00456               x=0, _p##x=_b##x=0;                                       \
    00457             (_a##x<(int)((img).width) && (                              \
    00458                                           I##ab=(img)(_a##x,_b##y,z,v), \
    00459                                           I##ap=(img)(_a##x,_p##y,z,v), \
    00460                                           I##ac=(img)(_a##x,    y,z,v), \
    00461                                           I##an=(img)(_a##x,_n##y,z,v), \
    00462                                           I##aa=(img)(_a##x,_a##y,z,v), \
    00463                                           1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
    00464             I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \
    00465               I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \
    00466               I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \
    00467               I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \
    00468               _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ )
    00469
    00470 #define cimg_map2x2x2(img,x,y,z,v,I) cimg_2mapYZ(img,y,z)               \
    00471        for (int _n##x=1, x=((int)(I##ccc=(img)(0,    y,    z,v),        \
    00472                                   I##cnc=(img)(0,_n##y,    z,v),        \
    00473                                   I##ccn=(img)(0,    y,_n##z,v),        \
    00474                                   I##cnn=(img)(0,_n##y,_n##z,v)),0);    \
    00475             (_n##x<(int)((img).width) && (                              \
    00476                                           I##ncc=(img)(_n##x,    y,    z,v), \
    00477                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
    00478                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
    00479                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
    00480                                           1)) || x==--_n##x;            \
    00481             I##ccc=I##ncc, I##cnc=I##nnc,                               \
    00482               I##ccn=I##ncn, I##cnn=I##nnn,                             \
    00483               x++, _n##x++ )
    00484
    00485 #define cimg_map3x3x3(img,x,y,z,v,I) cimg_3mapYZ(img,y,z)               \
    00486        for (int _n##x=1, _p##x=(int)(I##cpp=I##ppp=(img)(0,_p##y,_p##z,v), \
    00487                                      I##ccp=I##pcp=(img)(0,    y,_p##z,v), \
    00488                                      I##cnp=I##pnp=(img)(0,_n##y,_p##z,v), \
    00489                                      I##cpc=I##ppc=(img)(0,_p##y,    z,v), \
    00490                                      I##ccc=I##pcc=(img)(0,    y,    z,v), \
    00491                                      I##cnc=I##pnc=(img)(0,_n##y,    z,v), \
    00492                                      I##cpn=I##ppn=(img)(0,_p##y,_n##z,v), \
    00493                                      I##ccn=I##pcn=(img)(0,    y,_n##z,v), \
    00494                                      I##cnn=I##pnn=(img)(0,_n##y,_n##z,v)),\
    00495               x=_p##x=0;                                                \
    00496             (_n##x<(int)((img).width) && (                              \
    00497                                           I##npp=(img)(_n##x,_p##y,_p##z,v), \
    00498                                           I##ncp=(img)(_n##x,    y,_p##z,v), \
    00499                                           I##nnp=(img)(_n##x,_n##y,_p##z,v), \
    00500                                           I##npc=(img)(_n##x,_p##y,    z,v), \
    00501                                           I##ncc=(img)(_n##x,    y,    z,v), \
    00502                                           I##nnc=(img)(_n##x,_n##y,    z,v), \
    00503                                           I##npn=(img)(_n##x,_p##y,_n##z,v), \
    00504                                           I##ncn=(img)(_n##x,    y,_n##z,v), \
    00505                                           I##nnn=(img)(_n##x,_n##y,_n##z,v), \
    00506                                           1)) || x==--_n##x;            \
    00507             I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp,                \
    00508               I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp,              \
    00509               I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc,              \
    00510               I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc,              \
    00511               I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn,              \
    00512               I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn,              \
    00513               _p##x=x++, _n##x++ )
    00514
    00515 /*-------------------------------------------------
    00516   -------------------------------------------------
    00517
    00518
    00519     Definition of the cimg_library:: namespace
    00520
    00521
    00522   -------------------------------------------------
    00523   -------------------------------------------------*/
    00524
    00526
    00536 namespace cimg_library {
    00537   struct CImgStats;
    00538   struct CImgDisplay;
    00539   struct CImgException;
    00540   template<typename T=float> struct CImg;
    00541   template<typename T=float> struct CImgl;
    00542   template<typename T=float> struct CImgROI;
    00543
    00544   /*----------------------------------------------------
    00545
    00546
    00547
    00548   Definition of the CImgException structures
    00549
    00550
    00551
    00552   -------------------------------------------------*/
    00553
    00554 #if cimg_debug>=1
    00555 #if cimg_display_type!=2
    00556 #define cimg_exception_print(str) std::fprintf(stderr,"<CImg Error> %s",str);
    00557 #else
    00558 #define cimg_exception_print(str) MessageBox(NULL,(LPCTSTR)str,"<CImg Error>",MB_OK);
    00559 #endif
    00560 #else
    00561 #define cimg_exception_print(str)
    00562 #endif
    00563 #define cimg_exception_err(etype)                                 \
    00564   char tmp[1024];                                                 \
    00565   va_list ap;                                                     \
    00566   va_start(ap,format);                                            \
    00567   std::vsprintf(message,format,ap);                               \
    00568   va_end(ap);                                                     \
    00569   std::sprintf(tmp,"==> %s \n\nGeneral : %s\n\n", message,etype); \
    00570   cimg_exception_print(tmp)
    00571
    00573
    00608   struct CImgException {
    00609     char message[1024];
    00610     CImgException() { message[0]='\0'; }
    00611     CImgException(const char *format,...) {
    00612       cimg_exception_err("This error has been generated by a 'CImgException' throw,"
    00613                          "corresponding to a general exception problem.");
    00614     }
    00615   };
    00616
    00619
    00630   struct CImgInstanceException : CImgException {
    00631     CImgInstanceException(const char *format,...) {
    00632       cimg_exception_err("This error has been generated by a 'CImgInstanceException' throw.\n"
    00633                          "The instance passed through the function above has a bad structure"
    00634                          "(perhaps an empty image, list or display object ?)");
    00635     }};
    00636
    00639
    00650   struct CImgArgumentException : CImgException {
    00651     CImgArgumentException(const char *format,...) {
    00652       cimg_exception_err("This error has been generated by a 'CImgArgumentException' throw.\n"
    00653                          "At least one argument passed to the function above has been considered as not valid.");
    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 encountered a problem.");
    00672     }};
    00673
    00676
    00684   struct CImgDisplayException : CImgException {
    00685     CImgDisplayException(const char *format,...) {
    00686       cimg_exception_err("This error has been generated by a 'CImgDisplayException' throw.\n"
    00687                          "When trying to operate on a CImgDisplay instance, the function above encountered a problem.");
    00688     }};
    00689
    00690
    00691   /*-------------------------------------------------------------------------
    00692
    00693     Add LAPACK support to the library.
    00694
    00695     Define the macro 'cimg_lapack' before including 'CImg.h'
    00696     will activate the support of LAPACK. You'll have then to link
    00697     your code with the Lapack library to get it working.
    00698
    00699     -----------------------------------------------------------------------*/
    00700 #ifdef cimg_lapack
    00701   extern "C" {
    00702     extern void dgeev_(char*,char*, int*,double*,int*,double*,double*,double*,int*,double*,int*,double*,int*,int*);
    00703     extern void dsyev_(char*,char*,int*,double*,int*,double*,double*,int*,int*);
    00704     extern void dgetrf_(int*,int*,double*,int*,int*,int*);
    00705     extern void dgetri_(int*,double*,int*,int*,double*,int*,int*);
    00706   }
    00707 #else
    00708   inline void cimg_nolapack() {
    00709     throw CImgException("a LAPACK call : A LAPACK function has been required, but the LAPACK library"
    00710                         "hasn't been linked.\nPlease define the compilation flag '#define cimg_lapack'"
    00711                         "before including 'CImg.h' and link your code with LAPACK.");
    00712   }
    00713   inline void dgeev_ (char*,char*, int*,double*,int*,double*,double*,double*,int*,double*,int*,double*,int*,int*) { cimg_nolapack(); }
    00714   inline void dsyev_ (char*, char*, int*, double*, int*, double*, double*, int*, int*) { cimg_nolapack(); }
    00715   inline void dgetrf_(int*,int*,double*,int*,int*,int*) { cimg_nolapack(); }
    00716   inline void dgetri_(int*,double*,int*,int*,double*,int*,int*) { cimg_nolapack(); }
    00717 #endif
    00718
    00719
    00720   /*----------------------------------------
    00721
    00722
    00723
    00724     Definition of the namespace 'cimg'
    00725
    00726
    00727
    00728   --------------------------------------*/
    00729
    00731
    00739   namespace cimg {
    00740
    00741     // Define internal library variables.
    00742     const unsigned int lblock=1024;
    00743 #if cimg_display_type==1
    00744     static pthread_mutex_t*      X11_mutex = NULL;
    00745     static pthread_t*            X11_event_thread = NULL;
    00746     static CImgDisplay*          X11_wins[1024];
    00747     static Display*              X11_display = NULL;
    00748     static volatile unsigned int X11_nb_wins = 0;
    00749     static volatile bool         X11_thread_finished = false;
    00750     static unsigned int          X11_nb_bits = 0;
    00751     static GC*                   X11_gc = NULL;
    00752     static bool                  X11_endian = false;
    00753 #endif
    00754 #ifdef cimg_color_terminal
    00755     const char t_normal[9]  = {0x1b,'[','0',';','0',';','0','m','\0'};
    00756     const char t_red[11]    = {0x1b,'[','4',';','3','1',';','5','9','m','\0'};
    00757     const char t_bold[5]    = {0x1b,'[','1','m','\0'};
    00758     const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'};
    00759 #else
    00760     const char t_normal[1]  = {'\0'};
    00761     static const char *t_red = t_normal, *t_bold = t_normal, *t_purple = t_normal;
    00762 #endif
    00763
    00764 #if cimg_display_type!=0 && ( cimg_OS==0 || cimg_OS==1 || cimg_OS==3 )
    00765     // Keycodes for X11-based graphical systems
    00766     const unsigned int keyESC        = XK_Escape;
    00767     const unsigned int keyF1         = XK_F1;
    00768     const unsigned int keyF2         = XK_F2;
    00769     const unsigned int keyF3         = XK_F3;
    00770     const unsigned int keyF4         = XK_F4;
    00771     const unsigned int keyF5         = XK_F5;
    00772     const unsigned int keyF6         = XK_F6;
    00773     const unsigned int keyF7         = XK_F7;
    00774     const unsigned int keyF8         = XK_F8;
    00775     const unsigned int keyF9         = XK_F9;
    00776     const unsigned int keyF10        = XK_F10;
    00777     const unsigned int keyF11        = XK_F11;
    00778     const unsigned int keyF12        = XK_F12;
    00779     const unsigned int keyPAUSE      = XK_Pause;
    00780     const unsigned int key1          = XK_1;
    00781     const unsigned int key2          = XK_2;
    00782     const unsigned int key3          = XK_3;
    00783     const unsigned int key4          = XK_4;
    00784     const unsigned int key5          = XK_5;
    00785     const unsigned int key6          = XK_6;
    00786     const unsigned int key7          = XK_7;
    00787     const unsigned int key8          = XK_8;
    00788     const unsigned int key9          = XK_9;
    00789     const unsigned int key0          = XK_0;
    00790     const unsigned int keyBACKSPACE  = XK_BackSpace;
    00791     const unsigned int keyINSERT     = XK_Insert;
    00792     const unsigned int keyHOME       = XK_Home;
    00793     const unsigned int keyPAGEUP     = XK_Page_Up;
    00794     const unsigned int keyTAB        = XK_Tab;
    00795     const unsigned int keyQ          = XK_q;
    00796     const unsigned int keyW          = XK_w;
    00797     const unsigned int keyE          = XK_e;
    00798     const unsigned int keyR          = XK_r;
    00799     const unsigned int keyT          = XK_t;
    00800     const unsigned int keyY          = XK_y;
    00801     const unsigned int keyU          = XK_u;
    00802     const unsigned int keyI          = XK_i;
    00803     const unsigned int keyO          = XK_o;
    00804     const unsigned int keyP          = XK_p;
    00805     const unsigned int keyDELETE     = XK_Delete;
    00806     const unsigned int keyEND        = XK_End;
    00807     const unsigned int keyPAGEDOWN   = XK_Page_Down;
    00808     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
    00809     const unsigned int keyA          = XK_a;
    00810     const unsigned int keyS          = XK_s;
    00811     const unsigned int keyD          = XK_d;
    00812     const unsigned int keyF          = XK_f;
    00813     const unsigned int keyG          = XK_g;
    00814     const unsigned int keyH          = XK_h;
    00815     const unsigned int keyJ          = XK_j;
    00816     const unsigned int keyK          = XK_k;
    00817     const unsigned int keyL          = XK_l;
    00818     const unsigned int keyENTER      = XK_Return;
    00819     const unsigned int keySHIFTLEFT  = XK_Shift_L;
    00820     const unsigned int keyZ          = XK_z;
    00821     const unsigned int keyX          = XK_x;
    00822     const unsigned int keyC          = XK_c;
    00823     const unsigned int keyV          = XK_v;
    00824     const unsigned int keyB          = XK_b;
    00825     const unsigned int keyN          = XK_n;
    00826     const unsigned int keyM          = XK_m;
    00827     const unsigned int keySHIFTRIGHT = XK_Shift_R;
    00828     const unsigned int keyARROWUP    = XK_Up;
    00829     const unsigned int keyCTRLLEFT   = XK_Control_L;
    00830     const unsigned int keyAPPLEFT    = XK_Super_L;
    00831     const unsigned int keySPACE      = XK_space;
    00832     const unsigned int keyALTGR      = XK_Alt_R;
    00833     const unsigned int keyAPPRIGHT   = XK_Super_R;
    00834     const unsigned int keyMENU       = XK_Menu;
    00835     const unsigned int keyCTRLRIGHT  = XK_Control_R;
    00836     const unsigned int keyARROWLEFT  = XK_Left;
    00837     const unsigned int keyARROWDOWN  = XK_Down;
    00838     const unsigned int keyARROWRIGHT = XK_Right;
    00839 #endif
    00840
    00841 #if cimg_display_type!=0 && cimg_OS==2
    00842     // Keycodes for Windows-OS
    00844
    00845
    00853     const unsigned int keyESC        = 27;
    00854     const unsigned int keyF1         = 112;
    00855     const unsigned int keyF2         = 113;
    00856     const unsigned int keyF3         = 114;
    00857     const unsigned int keyF4         = 115;
    00858     const unsigned int keyF5         = 116;
    00859     const unsigned int keyF6         = 117;
    00860     const unsigned int keyF7         = 118;
    00861     const unsigned int keyF8         = 119;
    00862     const unsigned int keyF9         = 120;
    00863     const unsigned int keyF10        = 121;
    00864     const unsigned int keyF11        = 122;
    00865     const unsigned int keyF12        = 123;
    00866     const unsigned int keyPAUSE      = 19;
    00867     const unsigned int key1          = 49;
    00868     const unsigned int key2          = 50;
    00869     const unsigned int key3          = 51;
    00870     const unsigned int key4          = 52;
    00871     const unsigned int key5          = 53;
    00872     const unsigned int key6          = 54;
    00873     const unsigned int key7          = 55;
    00874     const unsigned int key8          = 56;
    00875     const unsigned int key9          = 57;
    00876     const unsigned int key0          = 48;
    00877     const unsigned int keyBACKSPACE  = 8;
    00878     const unsigned int keyINSERT     = 45;
    00879     const unsigned int keyHOME       = 36;
    00880     const unsigned int keyPAGEUP     = 33;
    00881     const unsigned int keyTAB        = 9;
    00882     const unsigned int keyQ          = 81;
    00883     const unsigned int keyW          = 87;
    00884     const unsigned int keyE          = 69;
    00885     const unsigned int keyR          = 82;
    00886     const unsigned int keyT          = 84;
    00887     const unsigned int keyY          = 89;
    00888     const unsigned int keyU          = 85;
    00889     const unsigned int keyI          = 73;
    00890     const unsigned int keyO          = 79;
    00891     const unsigned int keyP          = 80;
    00892     const unsigned int keyDELETE     = 8;
    00893     const unsigned int keyEND        = 35;
    00894     const unsigned int keyPAGEDOWN   = 34;
    00895     const unsigned int keyCAPSLOCK   = 20;
    00896     const unsigned int keyA          = 65;
    00897     const unsigned int keyS          = 83;
    00898     const unsigned int keyD          = 68;
    00899     const unsigned int keyF          = 70;
    00900     const unsigned int keyG          = 71;
    00901     const unsigned int keyH          = 72;
    00902     const unsigned int keyJ          = 74;
    00903     const unsigned int keyK          = 75;
    00904     const unsigned int keyL          = 76;
    00905     const unsigned int keyENTER      = 13;
    00906     const unsigned int keySHIFTLEFT  = 16;
    00907     const unsigned int keyZ          = 90;
    00908     const unsigned int keyX          = 88;
    00909     const unsigned int keyC          = 67;
    00910     const unsigned int keyV          = 86;
    00911     const unsigned int keyB          = 66;
    00912     const unsigned int keyN          = 78;
    00913     const unsigned int keyM          = 77;
    00914     const unsigned int keySHIFTRIGHT = 16;
    00915     const unsigned int keyARROWUP    = 38;
    00916     const unsigned int keyCTRLLEFT   = 17;
    00917     const unsigned int keyAPPLEFT    = 91;
    00918     const unsigned int keySPACE      = 32;
    00919     const unsigned int keyALTGR      = 17;
    00920     const unsigned int keyAPPRIGHT   = 92;
    00921     const unsigned int keyMENU       = 93;
    00922     const unsigned int keyCTRLRIGHT  = 17;
    00923     const unsigned int keyARROWLEFT  = 37;
    00924     const unsigned int keyARROWDOWN  = 40;
    00925     const unsigned int keyARROWRIGHT = 39;
    00926 #endif
    00927
    00928
    00929 #ifdef PI
    00930 #undef PI
    00931 #endif
    00932     const double PI = 3.14159265358979323846;
    00933
    00934     // Definition of a 7x11x1x3 font, used to return a default font for drawing text.
    00935     const unsigned int font7x11[7*11*256/8] =
    00936       {0x00000000,
    00937        0x00000000,0x00000000,0x00000002,0x04081020,0x00800000,0x24489000,0x00000000,0x000000a1,
    00938        0x4f8a7e50,0xa0000002,0x0f287030,0x50a78200,0x00008695,0x454552c2,0x00000002,0x0a143193,
    00939        0x19f00000,0x04081000,0x00000000,0x00001841,0x02040810,0x20203006,0x02020408,0x1020410c,
    00940        0x000010d8,0xc1400000,0x00000000,0x01021f08,0x10200000,0x00000000,0x00018302,0x08000000,
    00941        0x0007c000,0x00000000,0x00000000,0x0060c000,0x0000820c,0x1040820c,0x10400000,0xe2244891,
    00942        0x22380000,0x00061408,0x102043e0,0x00000070,0x10208208,0x1e000000,0x03c0810c,0x0408e000,
    00943        0x0000020c,0x2891f040,0x80000000,0xf1020701,0x02380000,0x0001c410,0x2c6488e0,0x0000003e,
    00944        0x08104102,0x08000000,0x00e22487,0x11223800,0x00000711,0x223c0823,0x80000000,0x0060c000,
    00945        0x060c0000,0x00000306,0x00003060,0x41000000,0x0218c180,0xc0400000,0x000007f0,0x1fc00000,
    00946        0x00000010,0x180c18c2,0x00000000,0x3c440820,0x80020000,0x0000f229,0xd4afa038,0x00000002,
    00947        0x0a1444f9,0x14100000,0x00788913,0xc4489e00,0x000001e4,0x10204040,0x78000000,0x1e224489,
    00948        0x12278000,0x0000f902,0x0788103e,0x00000007,0xc8103c40,0x81000000,0x001e4102,0x34244780,
    00949        0x00000112,0x244f9122,0x44000000,0x0f840810,0x2043e000,0x00003810,0x2040811c,0x00000002,
    00950        0x248a1828,0x48880000,0x00102040,0x810207c0,0x0000019b,0x36ab56a9,0x42000000,0x044c9d2a,
    00951        0x4c991000,0x00003c85,0x0a14284f,0x00000001,0xe2244f10,0x20400000,0x000f2142,0x850a13c0,
    00952        0xc0c000f1,0x12278911,0x21000000,0x01e4080e,0x0204f000,0x00003f88,0x10204081,0x00000000,
    00953        0x89122448,0x911c0000,0x00082891,0x22285040,0x00000041,0x9325ab64,0xc8800000,0x020a2282,
    00954        0x0a228200,0x00001051,0x14102040,0x80000000,0xfc082082,0x083f0000,0x00e10204,0x08102040,
    00955        0x81c01010,0x20202040,0x40808080,0x70204081,0x02040810,0xe0008105,0x1b228200,0x00000000,
    00956        0x00000000,0x00003f80,0x20200000,0x00000000,0x00000000,0x0e023c89,0x11f00000,0x2040b192,
    00957        0x24489e00,0x00000003,0xc8102040,0x78000000,0x811e4489,0x1223c000,0x000000e2,0x27c8101e,
    00958        0x00000071,0x0fc40810,0x20400000,0x00003c89,0x12244781,0x1c008102,0xe6489122,0x44000001,
    00959        0x001c0810,0x20408000,0x00040070,0x20408102,0x04700102,0x04491c28,0x48880000,0x0e040810,
    00960        0x20408100,0x00000002,0xded93264,0xc9000000,0x000b9922,0x44891000,0x00000038,0x89122447,
    00961        0x00000000,0x02c64891,0x22788100,0x00000f22,0x448911e0,0x40800000,0xb9920408,0x10000000,
    00962        0x00078818,0x0c08e000,0x0000083e,0x20408101,0xc0000000,0x01122448,0x933a0000,0x00001051,
    00963        0x22285040,0x00000000,0x8326ad56,0xc8800000,0x00042486,0x0c248400,0x00000020,0xa24450a0,
    00964        0x831c0000,0x00f81041,0x041f0000,0x00308102,0x0c081020,0x40600204,0x08102040,0x81020400,
    00965        0x60204081,0x82040810,0xe0000000,0x00399c00,0x00000000,0x00000000,0x00000000,0x00000000,
    00966        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00967        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00968        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00969        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00970        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00971        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00972        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00973        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00974        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    00975        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04001020,
    00976        0x40810000,0x00107142,0x85070400,0x000000c2,0x041c1020,0xf0000000,0x213c4891,0xe4200000,
    00977        0x00010511,0x47c21f08,0x00000081,0x02000000,0x00408100,0x001c40c1,0x62428302,0x38480000,
    00978        0x00000000,0x00000000,0x0f215aa5,0x6a13c000,0x00007871,0x23e00000,0x00000000,0x00028a28,
    00979        0x28280000,0x00000001,0xf8102000,0x00000000,0x0007c000,0x00000000,0x07113a44,0x70000000,
    00980        0x1fc00000,0x00000000,0x00000000,0x41410000,0x00000000,0x00000408,0x7c2043e0,0x0000003c,
    00981        0x30f00000,0x00000000,0x01c10700,0x00000000,0x00820000,0x00000000,0x00000000,0x01122448,
    00982        0x933a4080,0x0007ce9d,0x1a142850,0xa1400000,0x0000c180,0x00000000,0x00000000,0x00000010,
    00983        0x60000604,0x08000000,0x00000000,0x30912180,0x00000000,0x0000000a,0x0a0a28a0,0x00000032,
    00984        0x28505952,0xf8400000,0x01914282,0xe8514700,0x00000e38,0xba0e34be,0x10000000,0x00100040,
    00985        0x8208111e,0x40404142,0x889f2282,0x00004102,0x0a1444f9,0x1410000c,0x241050a2,0x27c8a080,
    00986        0x0028a082,0x85113e45,0x04000480,0x04142889,0xf2282000,0x082820a1,0x444f9141,0x00000001,
    00987        0xc60c2c50,0xe2700000,0x001e4102,0x04040782,0x0c2021f2,0x040f1020,0x7c000020,0x8f902078,
    00988        0x8103e000,0x0c247c81,0x03c4081f,0x00009003,0xe4081e20,0x40f80002,0x021f0810,0x204087c0,
    00989        0x000410f8,0x40810204,0x3e0000c2,0x47c20408,0x1021f000,0x09003e10,0x2040810f,0x80000001,
    00990        0xe2245c91,0x22780000,0xa288993a,0x54993220,0x00080879,0x0a142850,0x9e000010,0x43c850a1,
    00991        0x4284f000,0x03091e42,0x850a1427,0x80000a28,0xf2142850,0xa13c0001,0x200790a1,0x428509e0,
    00992        0x00000000,0x8490c184,0x90800000,0x01f66954,0xa966f800,0x01010891,0x22448911,0xc0000104,
    00993        0x44891224,0x488e0000,0x61222448,0x91224470,0x00048011,0x22448912,0x23800002,0x09051141,
    00994        0x02040800,0x0000040f,0x112244f1,0x0000000e,0x2448a142,0x444b8000,0x202001c0,0x4791223e,
    00995        0x00004100,0x0e023c89,0x11f0000c,0x24007011,0xe4488f80,0x0028a003,0x808f2244,0x7c000005,
    00996        0x001c0479,0x1223e000,0x082820e0,0x23c8911f,0x00000000,0x1d853e91,0x21b00000,0x00003c81,
    00997        0x02040782,0x0c202001,0xc44f9020,0x3c000041,0x000e227c,0x8101e000,0x0c240071,0x13e4080f,
    00998        0x000000a0,0x03889f20,0x40780002,0x02003810,0x20408100,0x00041001,0xc0810204,0x080000c2,
    00999        0x400e0408,0x10204000,0x000a0070,0x20408102,0x000000e1,0x21c44891,0x22380000,0xa2801732,
    01000        0x44891220,0x00080800,0x71122448,0x8e000020,0x80038891,0x22447000,0x0309001c,0x44891223,
    01001        0x80000a28,0x00e22448,0x911c0000,0x01400711,0x224488e0,0x00000000,0x2003f000,0x04000000,
    01002        0x0001e4ca,0x99327800,0x01010011,0x22448933,0xa0000410,0x00891224,0x499d0000,0x61200448,
    01003        0x91224ce8,0x00000500,0x22448912,0x67400004,0x10020a24,0x450a0831,0xc002040b,0x19224489,
    01004        0xe204000a,0x00828911,0x42820c70,0x00000000,0x00000000,0x00000002,0x04081020,0x00800000,
    01005        0x24489000,0x00000000,0x000000a1,0x4f8a7e50,0xa0000002,0x0f287030,0x50a78200,0x00008695,
    01006        0x454552c2,0x00000002,0x0a143193,0x19f00000,0x04081000,0x00000000,0x00001841,0x02040810,
    01007        0x20203006,0x02020408,0x1020410c,0x000010d8,0xc1400000,0x00000000,0x01021f08,0x10200000,
    01008        0x00000000,0x00018302,0x08000000,0x0007c000,0x00000000,0x00000000,0x0060c000,0x0000820c,
    01009        0x1040820c,0x10400000,0xe2244891,0x22380000,0x00061408,0x102043e0,0x00000070,0x10208208,
    01010        0x1e000000,0x03c0810c,0x0408e000,0x0000020c,0x2891f040,0x80000000,0xf1020701,0x02380000,
    01011        0x0001c410,0x2c6488e0,0x0000003e,0x08104102,0x08000000,0x00e22487,0x11223800,0x00000711,
    01012        0x223c0823,0x80000000,0x0060c000,0x060c0000,0x00000306,0x00003060,0x41000000,0x0218c180,
    01013        0xc0400000,0x000007f0,0x1fc00000,0x00000010,0x180c18c2,0x00000000,0x3c440820,0x80020000,
    01014        0x0000f229,0xd4afa038,0x00000002,0x0a1444f9,0x14100000,0x00788913,0xc4489e00,0x000001e4,
    01015        0x10204040,0x78000000,0x1e224489,0x12278000,0x0000f902,0x0788103e,0x00000007,0xc8103c40,
    01016        0x81000000,0x001e4102,0x34244780,0x00000112,0x244f9122,0x44000000,0x0f840810,0x2043e000,
    01017        0x00003810,0x2040811c,0x00000002,0x248a1828,0x48880000,0x00102040,0x810207c0,0x0000019b,
    01018        0x36ab56a9,0x42000000,0x044c9d2a,0x4c991000,0x00003c85,0x0a14284f,0x00000001,0xe2244f10,
    01019        0x20400000,0x000f2142,0x850a13c0,0xc0c000f1,0x12278911,0x21000000,0x01e4080e,0x0204f000,
    01020        0x00003f88,0x10204081,0x00000000,0x89122448,0x911c0000,0x00082891,0x22285040,0x00000041,
    01021        0x9325ab64,0xc8800000,0x020a2282,0x0a228200,0x00001051,0x14102040,0x80000000,0xfc082082,
    01022        0x083f0000,0x00e10204,0x08102040,0x81c01010,0x20202040,0x40808080,0x70204081,0x02040810,
    01023        0xe0008105,0x1b228200,0x00000000,0x00000000,0x00003f80,0x20200000,0x00000000,0x00000000,
    01024        0x0e023c89,0x11f00000,0x2040b192,0x24489e00,0x00000003,0xc8102040,0x78000000,0x811e4489,
    01025        0x1223c000,0x000000e2,0x27c8101e,0x00000071,0x0fc40810,0x20400000,0x00003c89,0x12244781,
    01026        0x1c008102,0xe6489122,0x44000001,0x001c0810,0x20408000,0x00040070,0x20408102,0x04700102,
    01027        0x04491c28,0x48880000,0x0e040810,0x20408100,0x00000002,0xded93264,0xc9000000,0x000b9922,
    01028        0x44891000,0x00000038,0x89122447,0x00000000,0x02c64891,0x22788100,0x00000f22,0x448911e0,
    01029        0x40800000,0xb9920408,0x10000000,0x00078818,0x0c08e000,0x0000083e,0x20408101,0xc0000000,
    01030        0x01122448,0x933a0000,0x00001051,0x22285040,0x00000000,0x8326ad56,0xc8800000,0x00042486,
    01031        0x0c248400,0x00000020,0xa24450a0,0x831c0000,0x00f81041,0x041f0000,0x00308102,0x0c081020,
    01032        0x40600204,0x08102040,0x81020400,0x60204081,0x82040810,0xe0000000,0x00399c00,0x00000000,
    01033        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01034        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01035        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01036        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01037        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01038        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01039        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01040        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01041        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01042        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01043        0x00000000,0x00000000,0x04001020,0x40810000,0x00107142,0x85070400,0x000000c2,0x041c1020,
    01044        0xf0000000,0x213c4891,0xe4200000,0x00010511,0x47c21f08,0x00000081,0x02000000,0x00408100,
    01045        0x001c40c1,0x62428302,0x38480000,0x00000000,0x00000000,0x0f215aa5,0x6a13c000,0x00007871,
    01046        0x23e00000,0x00000000,0x00028a28,0x28280000,0x00000001,0xf8102000,0x00000000,0x0007c000,
    01047        0x00000000,0x07113a44,0x70000000,0x1fc00000,0x00000000,0x00000000,0x41410000,0x00000000,
    01048        0x00000408,0x7c2043e0,0x0000003c,0x30f00000,0x00000000,0x01c10700,0x00000000,0x00820000,
    01049        0x00000000,0x00000000,0x01122448,0x933a4080,0x0007ce9d,0x1a142850,0xa1400000,0x0000c180,
    01050        0x00000000,0x00000000,0x00000010,0x60000604,0x08000000,0x00000000,0x30912180,0x00000000,
    01051        0x0000000a,0x0a0a28a0,0x00000032,0x28505952,0xf8400000,0x01914282,0xe8514700,0x00000e38,
    01052        0xba0e34be,0x10000000,0x00100040,0x8208111e,0x40404142,0x889f2282,0x00004102,0x0a1444f9,
    01053        0x1410000c,0x241050a2,0x27c8a080,0x0028a082,0x85113e45,0x04000480,0x04142889,0xf2282000,
    01054        0x082820a1,0x444f9141,0x00000001,0xc60c2c50,0xe2700000,0x001e4102,0x04040782,0x0c2021f2,
    01055        0x040f1020,0x7c000020,0x8f902078,0x8103e000,0x0c247c81,0x03c4081f,0x00009003,0xe4081e20,
    01056        0x40f80002,0x021f0810,0x204087c0,0x000410f8,0x40810204,0x3e0000c2,0x47c20408,0x1021f000,
    01057        0x09003e10,0x2040810f,0x80000001,0xe2245c91,0x22780000,0xa288993a,0x54993220,0x00080879,
    01058        0x0a142850,0x9e000010,0x43c850a1,0x4284f000,0x03091e42,0x850a1427,0x80000a28,0xf2142850,
    01059        0xa13c0001,0x200790a1,0x428509e0,0x00000000,0x8490c184,0x90800000,0x01f66954,0xa966f800,
    01060        0x01010891,0x22448911,0xc0000104,0x44891224,0x488e0000,0x61222448,0x91224470,0x00048011,
    01061        0x22448912,0x23800002,0x09051141,0x02040800,0x0000040f,0x112244f1,0x0000000e,0x2448a142,
    01062        0x444b8000,0x202001c0,0x4791223e,0x00004100,0x0e023c89,0x11f0000c,0x24007011,0xe4488f80,
    01063        0x0028a003,0x808f2244,0x7c000005,0x001c0479,0x1223e000,0x082820e0,0x23c8911f,0x00000000,
    01064        0x1d853e91,0x21b00000,0x00003c81,0x02040782,0x0c202001,0xc44f9020,0x3c000041,0x000e227c,
    01065        0x8101e000,0x0c240071,0x13e4080f,0x000000a0,0x03889f20,0x40780002,0x02003810,0x20408100,
    01066        0x00041001,0xc0810204,0x080000c2,0x400e0408,0x10204000,0x000a0070,0x20408102,0x000000e1,
    01067        0x21c44891,0x22380000,0xa2801732,0x44891220,0x00080800,0x71122448,0x8e000020,0x80038891,
    01068        0x22447000,0x0309001c,0x44891223,0x80000a28,0x00e22448,0x911c0000,0x01400711,0x224488e0,
    01069        0x00000000,0x2003f000,0x04000000,0x0001e4ca,0x99327800,0x01010011,0x22448933,0xa0000410,
    01070        0x00891224,0x499d0000,0x61200448,0x91224ce8,0x00000500,0x22448912,0x67400004,0x10020a24,
    01071        0x450a0831,0xc002040b,0x19224489,0xe204000a,0x00828911,0x42820c70,0x00000000,0x00000000,
    01072        0x00000002,0x04081020,0x00800000,0x24489000,0x00000000,0x000000a1,0x4f8a7e50,0xa0000002,
    01073        0x0f287030,0x50a78200,0x00008695,0x454552c2,0x00000002,0x0a143193,0x19f00000,0x04081000,
    01074        0x00000000,0x00001841,0x02040810,0x20203006,0x02020408,0x1020410c,0x000010d8,0xc1400000,
    01075        0x00000000,0x01021f08,0x10200000,0x00000000,0x00018302,0x08000000,0x0007c000,0x00000000,
    01076        0x00000000,0x0060c000,0x0000820c,0x1040820c,0x10400000,0xe2244891,0x22380000,0x00061408,
    01077        0x102043e0,0x00000070,0x10208208,0x1e000000,0x03c0810c,0x0408e000,0x0000020c,0x2891f040,
    01078        0x80000000,0xf1020701,0x02380000,0x0001c410,0x2c6488e0,0x0000003e,0x08104102,0x08000000,
    01079        0x00e22487,0x11223800,0x00000711,0x223c0823,0x80000000,0x0060c000,0x060c0000,0x00000306,
    01080        0x00003060,0x41000000,0x0218c180,0xc0400000,0x000007f0,0x1fc00000,0x00000010,0x180c18c2,
    01081        0x00000000,0x3c440820,0x80020000,0x0000f229,0xd4afa038,0x00000002,0x0a1444f9,0x14100000,
    01082        0x00788913,0xc4489e00,0x000001e4,0x10204040,0x78000000,0x1e224489,0x12278000,0x0000f902,
    01083        0x0788103e,0x00000007,0xc8103c40,0x81000000,0x001e4102,0x34244780,0x00000112,0x244f9122,
    01084        0x44000000,0x0f840810,0x2043e000,0x00003810,0x2040811c,0x00000002,0x248a1828,0x48880000,
    01085        0x00102040,0x810207c0,0x0000019b,0x36ab56a9,0x42000000,0x044c9d2a,0x4c991000,0x00003c85,
    01086        0x0a14284f,0x00000001,0xe2244f10,0x20400000,0x000f2142,0x850a13c0,0xc0c000f1,0x12278911,
    01087        0x21000000,0x01e4080e,0x0204f000,0x00003f88,0x10204081,0x00000000,0x89122448,0x911c0000,
    01088        0x00082891,0x22285040,0x00000041,0x9325ab64,0xc8800000,0x020a2282,0x0a228200,0x00001051,
    01089        0x14102040,0x80000000,0xfc082082,0x083f0000,0x00e10204,0x08102040,0x81c01010,0x20202040,
    01090        0x40808080,0x70204081,0x02040810,0xe0008105,0x1b228200,0x00000000,0x00000000,0x00003f80,
    01091        0x20200000,0x00000000,0x00000000,0x0e023c89,0x11f00000,0x2040b192,0x24489e00,0x00000003,
    01092        0xc8102040,0x78000000,0x811e4489,0x1223c000,0x000000e2,0x27c8101e,0x00000071,0x0fc40810,
    01093        0x20400000,0x00003c89,0x12244781,0x1c008102,0xe6489122,0x44000001,0x001c0810,0x20408000,
    01094        0x00040070,0x20408102,0x04700102,0x04491c28,0x48880000,0x0e040810,0x20408100,0x00000002,
    01095        0xded93264,0xc9000000,0x000b9922,0x44891000,0x00000038,0x89122447,0x00000000,0x02c64891,
    01096        0x22788100,0x00000f22,0x448911e0,0x40800000,0xb9920408,0x10000000,0x00078818,0x0c08e000,
    01097        0x0000083e,0x20408101,0xc0000000,0x01122448,0x933a0000,0x00001051,0x22285040,0x00000000,
    01098        0x8326ad56,0xc8800000,0x00042486,0x0c248400,0x00000020,0xa24450a0,0x831c0000,0x00f81041,
    01099        0x041f0000,0x00308102,0x0c081020,0x40600204,0x08102040,0x81020400,0x60204081,0x82040810,
    01100        0xe0000000,0x00399c00,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01101        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01102        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01103        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01104        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01105        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01106        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01107        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01108        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01109        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    01110        0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x04001020,0x40810000,0x00107142,
    01111        0x85070400,0x000000c2,0x041c1020,0xf0000000,0x213c4891,0xe4200000,0x00010511,0x47c21f08,
    01112        0x00000081,0x02000000,0x00408100,0x001c40c1,0x62428302,0x38480000,0x00000000,0x00000000,
    01113        0x0f215aa5,0x6a13c000,0x00007871,0x23e00000,0x00000000,0x00028a28,0x28280000,0x00000001,
    01114        0xf8102000,0x00000000,0x0007c000,0x00000000,0x07113a44,0x70000000,0x1fc00000,0x00000000,
    01115        0x00000000,0x41410000,0x00000000,0x00000408,0x7c2043e0,0x0000003c,0x30f00000,0x00000000,
    01116        0x01c10700,0x00000000,0x00820000,0x00000000,0x00000000,0x01122448,0x933a4080,0x0007ce9d,
    01117        0x1a142850,0xa1400000,0x0000c180,0x00000000,0x00000000,0x00000010,0x60000604,0x08000000,
    01118        0x00000000,0x30912180,0x00000000,0x0000000a,0x0a0a28a0,0x00000032,0x28505952,0xf8400000,
    01119        0x01914282,0xe8514700,0x00000e38,0xba0e34be,0x10000000,0x00100040,0x8208111e,0x40404142,
    01120        0x889f2282,0x00004102,0x0a1444f9,0x1410000c,0x241050a2,0x27c8a080,0x0028a082,0x85113e45,
    01121        0x04000480,0x04142889,0xf2282000,0x082820a1,0x444f9141,0x00000001,0xc60c2c50,0xe2700000,
    01122        0x001e4102,0x04040782,0x0c2021f2,0x040f1020,0x7c000020,0x8f902078,0x8103e000,0x0c247c81,
    01123        0x03c4081f,0x00009003,0xe4081e20,0x40f80002,0x021f0810,0x204087c0,0x000410f8,0x40810204,
    01124        0x3e0000c2,0x47c20408,0x1021f000,0x09003e10,0x2040810f,0x80000001,0xe2245c91,0x22780000,
    01125        0xa288993a,0x54993220,0x00080879,0x0a142850,0x9e000010,0x43c850a1,0x4284f000,0x03091e42,
    01126        0x850a1427,0x80000a28,0xf2142850,0xa13c0001,0x200790a1,0x428509e0,0x00000000,0x8490c184,
    01127        0x90800000,0x01f66954,0xa966f800,0x01010891,0x22448911,0xc0000104,0x44891224,0x488e0000,
    01128        0x61222448,0x91224470,0x00048011,0x22448912,0x23800002,0x09051141,0x02040800,0x0000040f,
    01129        0x112244f1,0x0000000e,0x2448a142,0x444b8000,0x202001c0,0x4791223e,0x00004100,0x0e023c89,
    01130        0x11f0000c,0x24007011,0xe4488f80,0x0028a003,0x808f2244,0x7c000005,0x001c0479,0x1223e000,
    01131        0x082820e0,0x23c8911f,0x00000000,0x1d853e91,0x21b00000,0x00003c81,0x02040782,0x0c202001,
    01132        0xc44f9020,0x3c000041,0x000e227c,0x8101e000,0x0c240071,0x13e4080f,0x000000a0,0x03889f20,
    01133        0x40780002,0x02003810,0x20408100,0x00041001,0xc0810204,0x080000c2,0x400e0408,0x10204000,
    01134        0x000a0070,0x20408102,0x000000e1,0x21c44891,0x22380000,0xa2801732,0x44891220,0x00080800,
    01135        0x71122448,0x8e000020,0x80038891,0x22447000,0x0309001c,0x44891223,0x80000a28,0x00e22448,
    01136        0x911c0000,0x01400711,0x224488e0,0x00000000,0x2003f000,0x04000000,0x0001e4ca,0x99327800,
    01137        0x01010011,0x22448933,0xa0000410,0x00891224,0x499d0000,0x61200448,0x91224ce8,0x00000500,
    01138        0x22448912,0x67400004,0x10020a24,0x450a0831,0xc002040b,0x19224489,0xe204000a,0x00828911,
    01139        0x42820c70};
    01140
    01141     // Return a 'stringification' of standart integral types.
    01142     const char* const bool_st    = "bool";
    01143     const char* const uchar_st   = "unsigned char";
    01144     const char* const char_st    = "char";
    01145     const char* const ushort_st  = "unsigned short";
    01146     const char* const short_st   = "short";
    01147     const char* const uint_st    = "unsigned int";
    01148     const char* const int_st     = "int";
    01149     const char* const ulong_st   = "unsigned long";
    01150     const char* const long_st    = "long";
    01151     const char* const float_st   = "float";
    01152     const char* const double_st  = "double";
    01153     const char* const unknown_st = "unknown";
    01154     template<typename t> inline const char* get_type(const t&) { return unknown_st; }
    01155     inline const char* get_type(const bool&          ) { return bool_st;   }
    01156     inline const char* get_type(const unsigned char& ) { return uchar_st;  }
    01157     inline const char* get_type(const char&          ) { return char_st;   }
    01158     inline const char* get_type(const unsigned short&) { return ushort_st; }
    01159     inline const char* get_type(const short&         ) { return short_st;  }
    01160     inline const char* get_type(const unsigned int&  ) { return uint_st;   }
    01161     inline const char* get_type(const int&           ) { return int_st;    }
    01162     inline const char* get_type(const unsigned long& ) { return ulong_st;  }
    01163     inline const char* get_type(const long&          ) { return long_st;   }
    01164     inline const char* get_type(const float&         ) { return float_st;  }
    01165     inline const char* get_type(const double&        ) { return double_st; }
    01166
    01167     // Display a warning message
    01168 #if cimg_debug>=1
    01169     static void warn(const bool cond,const char *format,...) {
    01170       if (cond) {
    01171         va_list ap;
    01172         va_start(ap,format);
    01173         std::fprintf(stderr,"<CImg Warning> ");
    01174         std::vfprintf(stderr,format,ap);
    01175         std::fputc('\n',stderr);
    01176         va_end(ap);
    01177       }
    01178     }
    01179 #else
    01180     inline void warn(const bool cond,const char *format,...) {}
    01181 #endif
    01182
    01183     inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; }
    01184     inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); }
    01185     inline float atof(const char *str) {
    01186       float x=0,y=1;
    01187       if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
    01188     }
    01189     inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; }
    01190     inline int strncmp(const char *s1,const char *s2,const int l) {
    01191       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=abs(s1[k] - s2[k]); return n; }
    01192       return 0;
    01193     }
    01194     inline int strncasecmp(const char *s1,const char *s2,const int l) {
    01195       if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=abs(uncase(s1[k])-uncase(s2[k])); return n; }
    01196       return 0;
    01197     }
    01198     inline int strcmp(const char *s1,const char *s2)     {
    01199       const int l1 = strlen(s1), l2 = strlen(s2);
    01200       return strncmp(s1,s2,1+(l1<l2?l1:l2));
    01201     }
    01202     inline int strcasecmp(const char *s1,const char *s2) {
    01203       const int l1 = strlen(s1), l2 = strlen(s2);
    01204       return strncasecmp(s1,s2,1+(l1<l2?l1:l2));
    01205     }
    01206     inline int strfind(const char *s,const char c) {
    01207       if (s) {
    01208         int l; for (l=strlen(s); l>=0 && s[l]!=c; l--) ;
    01209         return l;
    01210       }
    01211       return -1;
    01212     }
    01213     inline const char* basename(const char *s)  {
    01214       return (cimg_OS!=2)?(s?s+1+strfind(s,'/'):NULL):(s?s+1+strfind(s,'\\'):NULL);
    01215     }
    01216
    01217     inline void system(const char *command) {
    01218 #if cimg_OS==2
    01219       PROCESS_INFORMATION pi;
    01220       STARTUPINFO si;
    01221       GetStartupInfo(&si);
    01222       si.wShowWindow = SW_HIDE;
    01223       si.dwFlags |= SW_HIDE;
    01224       BOOL res = CreateProcess(NULL,(LPTSTR)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
    01225       if (res) {
    01226         WaitForSingleObject(pi.hProcess, INFINITE);
    01227         CloseHandle(pi.hThread);
    01228         CloseHandle(pi.hProcess);
    01229       }
    01230 #else
    01231       ::system(command);
    01232 #endif
    01233     }
    01234
    01236
    01255     inline const char* convert_path() {
    01256       static char *convert_path = NULL;
    01257       if (!convert_path) {
    01258 #if cimg_OS==2 || defined(cimg_convert_path)
    01259         bool stopflag = false;
    01260         std::FILE *file;
    01261 #endif
    01262         convert_path = new char[1024];
    01263 #ifdef cimg_convert_path
    01264         std::strcpy(convert_path,cimg_convert_path);
    01265         if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
    01266 #endif
    01267 #if cimg_OS==2
    01268         for (unsigned int k=0; k<=9 && !stopflag; k++) {
    01269           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u-Q\\convert.exe",k);
    01270           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
    01271         }
    01272         if (!stopflag) for (unsigned int k=0; k<=9 && !stopflag; k++) {
    01273           std::sprintf(convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u\\convert.exe",k);
    01274           if ((file=std::fopen(convert_path,"r"))!=NULL) { std::fclose(file); stopflag = true; }
    01275         }
    01276         if (!stopflag) std::strcpy(convert_path,"convert.exe");
    01277 #else
    01278         std::strcpy(convert_path,"convert");
    01279 #endif
    01280       }
    01281       return convert_path;
    01282     }
    01283
    01285
    01302     inline const char* temporary_path() {
    01303       static char *temporary_path = NULL;
    01304       if (!temporary_path) {
    01305         temporary_path = new char[1024];
    01306 #ifdef cimg_temporary_path
    01307         std::strcpy(temporary_path,cimg_temporary_path);
    01308         const char* testing_path[7] = { temporary_path, "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
    01309 #else
    01310         const char* testing_path[6] = { "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL };
    01311 #endif
    01312         char filetmp[1024];
    01313         std::FILE *file=NULL;
    01314         int i=-1;
    01315         while (!file && testing_path[++i]) {
    01316           std::sprintf(filetmp,"%s/CImg%.4d.ppm",testing_path[i],std::rand()%10000);
    01317           if ((file=std::fopen(filetmp,"w"))!=NULL) { std::fclose(file); std::remove(filetmp); }
    01318         }
    01319         if (!file)
    01320           throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
    01321                                 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
    01322                                 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
    01323         std::strcpy(temporary_path,testing_path[i]);
    01324       }
    01325       return temporary_path;
    01326     }
    01327
    01328     inline const char *filename_split(const char *const filename, char *const body=NULL) {
    01329       if (!filename) throw CImgArgumentException("cimg::filename_split() : Can't split the (null) filename");
    01330       int l=strfind(filename,'.');
    01331       if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }}
    01332       else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; }
    01333       return filename+l+1;
    01334     }
    01335
    01336     inline char* filename_number(const char *filename,const int number,const unsigned int n,char *const string) {
    01337       char format[1024],body[1024];
    01338       const char *ext = filename_split(filename,body);
    01339       if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
    01340       else std::sprintf(format,"%s_%%d.%s",body,ext);
    01341       std::sprintf(string,format,number);
    01342       return string;
    01343     }
    01344     inline std::FILE *fopen(const char *const path,const char *const mode) {
    01345       if(!path || !mode) throw CImgArgumentException("cimg::fopen() : Can't open file '%s' with mode '%s'",path,mode);
    01346       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; else {
    01347         std::FILE *dest=std::fopen(path,mode);
    01348         if(!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened %s",
    01349                                         path,mode[0]=='r'?"for reading":(mode[0]=='w'?"for writing":""),path);
    01350         return dest;
    01351       }
    01352     }
    01353     inline int fclose(std::FILE *file) {
    01354       warn(!file,"cimg::fclose() : Can't close (null) file");
    01355       if (!file || file==stdin || file==stdout) return 0;
    01356       const int errn=std::fclose(file);
    01357       warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn);
    01358       return errn;
    01359     }
    01360     template<typename T> inline int fread(T *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
    01361       if (!ptr || size<=0 || nmemb<=0 || !stream)
    01362         throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
    01363                                     nmemb,size,stream,ptr);
    01364       const unsigned int errn = (unsigned int)std::fread((void*)ptr,size,nmemb,stream);
    01365       warn(errn!=nmemb,"cimg::fread() : File reading problems, only %u/%u elements read",errn,nmemb);
    01366       return errn;
    01367     }
    01368     inline int fwrite(const void *ptr,const unsigned int size,const unsigned int nmemb,std::FILE *stream) {
    01369       if (!ptr || size<=0 || nmemb<=0 || !stream)
    01370         throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
    01371                                     nmemb,size,stream,ptr);
    01372       const unsigned int errn = (unsigned int)std::fwrite(ptr,size,nmemb,stream);
    01373       if(errn!=nmemb)
    01374         throw CImgIOException("cimg::fwrite() : File writing problems, only %u/%u elements written",errn,nmemb);
    01375       return errn;
    01376     }
    01377
    01378     // Exchange the values of variables \p a and \p b
    01379     template<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; }
    01380     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2) { swap(a1,b1); swap(a2,b2); }
    01381     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3) { swap(a1,b1,a2,b2); swap(a3,b3); }
    01382     template<typename T> inline void swap(T& a1,T& b1,T& a2,T& b2,T& a3,T& b3,T& a4,T& b4) { swap(a1,b1,a2,b2,a3,b3); swap(a4,b4); }
    01383     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) {
    01384       swap(a1,b1,a2,b2,a3,b3,a4,b4); swap(a5,b5);
    01385     }
    01386     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) {
    01387       swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); swap(a6,b6);
    01388     }
    01389
    01390     template<typename T> inline T& endian_swap(T& a) {
    01391       if (sizeof(a)!=1) {
    01392         unsigned char *pb=(unsigned char*)&a, *pe=pb+sizeof(a);
    01393         for (int i=0; i<(int)sizeof(a)/2; i++) swap(*(pb++),*(--pe));
    01394       }
    01395       return a;
    01396     }
    01397
    01398     template<typename T> inline void endian_swap(T *const buffer,const unsigned int size) {
    01399       T *ptr = buffer;
    01400       for (unsigned int i=0; i<size; i++) endian_swap(*(ptr++));
    01401     }
    01402
    01403     inline const char* option(const char *const name,const unsigned int argc,char **argv,const char *const defaut,
    01404                               const char *const usage=NULL) {
    01405       static bool first=true, visu=false;
    01406       const char *res = NULL;
    01407       if (first) { first=false; visu = option("-h",argc,argv,(const char*)NULL)!=NULL; }
    01408       if (!name && visu) {
    01409         std::fprintf(stderr,"\n %s%s%s",t_red,basename(argv[0]),t_normal);
    01410         if (usage) std::fprintf(stderr," : %s",usage);
    01411         std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__);
    01412       }
    01413       if (name) {
    01414         if (argc>0) {
    01415           unsigned int k=0,i;
    01416           while (k<argc && strcmp(argv[k],name)) k++;
    01417           i=k;
    01418           res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
    01419         } else res = defaut;
    01420         if (visu && usage) std::fprintf(stderr,"    %s%-8s%s = %-12s : %s%s%s\n",
    01421                                         t_bold,name,t_normal,res?res:"NULL",t_purple,usage,t_normal);
    01422       }
    01423       return res;
    01424     }
    01425     inline bool option(const char *const name,const unsigned int argc,char **argv,
    01426                        const bool defaut,const char *const usage=NULL) {
    01427       const char *s = option(name,argc,argv,(const char*)NULL);
    01428       const bool res = s?(strcasecmp(s,"false") && strcasecmp(s,"off") && strcasecmp(s,"0")):defaut;
    01429       option(name,0,NULL,res?"true":"false",usage);
    01430       return res;
    01431     }
    01432     inline int option(const char *const name,const unsigned int argc,char **argv,
    01433                       const int defaut,const char *const usage=NULL) {
    01434       const char *s = option(name,argc,argv,(const char*)NULL);
    01435       const int res = s?atoi(s):defaut;
    01436       char tmp[256];
    01437       std::sprintf(tmp,"%d",res);
    01438       option(name,0,NULL,tmp,usage);
    01439       return res;
    01440     }
    01441     inline char option(const char *const name,const unsigned int argc,char **argv,
    01442                        const char defaut,const char *const usage=NULL) {
    01443       const char *s = option(name,argc,argv,(const char*)NULL);
    01444       const char res = s?s[0]:defaut;
    01445       char tmp[8];
    01446       tmp[0] = res;
    01447       tmp[1] ='\0';
    01448       option(name,0,NULL,tmp,usage);
    01449       return res;
    01450     }
    01451     inline double option(const char *const name,const unsigned int argc,char **argv,
    01452                          const double defaut,const char *const usage=NULL) {
    01453       const char *s = option(name,argc,argv,(const char*)NULL);
    01454       const double res = s?atof(s):defaut;
    01455       char tmp[256];
    01456       std::sprintf(tmp,"%g",res);
    01457       option(name,0,NULL,tmp,usage);
    01458       return res;
    01459     }
    01460
    01462     inline const bool endian() { const int x=1; return ((unsigned char*)&x)[0]?false:true; }
    01463
    01465     inline void info() {
    01466       std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n",
    01467                    t_red,cimg_version,t_normal,__DATE__,__TIME__);
    01468       std::fprintf(stderr,"  > Architecture   : %s%-12s%s %s(cimg_OS=%d)\n%s",
    01469                    t_bold,
    01470                    cimg_OS==0?"Sun Unix":
    01471                    (cimg_OS==1?"PC Unix":
    01472                     (cimg_OS==2?"PC Windows":
    01473                      (cimg_OS==3?"Mac OS X":
    01474                       "Unknown"))),
    01475                    t_normal,t_purple,cimg_OS,t_normal);
    01476       std::fprintf(stderr,"  > Display type   : %s%-12s%s %s(cimg_display_type=%d)%s\n",
    01477                    t_bold,cimg_display_type==0?"No":
    01478                    (cimg_display_type==1?"X11":
    01479                     (cimg_display_type==2?"WindowsGDI":
    01480                      "Unknown")),
    01481                    t_normal,t_purple,cimg_display_type,t_normal);
    01482 #ifdef cimg_color_terminal
    01483       std::fprintf(stderr,"  > Color terminal : %s%-12s%s %s(cimg_color_terminal defined)%s\n",t_bold,"Yes",t_normal,t_purple,t_normal);
    01484 #else
    01485       std::fprintf(stderr,"  > Color terminal : %-12s (cimg_color_terminal undefined)\n","No");
    01486 #endif
    01487 #ifdef cimg_lapack
    01488       std::fprintf(stderr,"  > Using LAPACK   : %s%-12s%s %s(cimg_lapack defined)%s\n",t_bold,"Yes",t_normal,t_purple,t_normal);
    01489 #else
    01490       std::fprintf(stderr,"  > Using LAPACK   : %s%-12s%s %s(cimg_lapack undefined)%s\n",t_bold,"No",t_normal,t_purple,t_normal);
    01491 #endif
    01492       std::fprintf(stderr,"  > Debug messages : %s%-12s%s %s(cimg_debug=%d)%s\n",t_bold,cimg_debug==2?"High":(cimg_debug==1?"Yes":"No"),
    01493                    t_normal,t_purple,cimg_debug,t_normal);
    01494       std::fprintf(stderr,"\n");
    01495     }
    01496
    01498     inline long int time() {
    01499 #if cimg_OS==0 || cimg_OS==1 || cimg_OS==3
    01500       struct timeval st_time;
    01501       gettimeofday(&st_time,NULL);
    01502       return (long int)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
    01503 #elif cimg_OS==2
    01504       static SYSTEMTIME st_time;
    01505       GetSystemTime(&st_time);
    01506       return (long int)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
    01507 #else
    01508       return 0;
    01509 #endif
    01510     }
    01511
    01513
    01518     inline void sleep(const int milliseconds) {
    01519 #if cimg_OS==0 || cimg_OS==1 || cimg_OS==3
    01520       struct timespec tv;
    01521       tv.tv_sec = milliseconds/1000;
    01522       tv.tv_nsec = (milliseconds%1000)*1000000;
    01523       nanosleep(&tv,NULL);
    01524 #elif cimg_OS==2
    01525       Sleep(milliseconds);
    01526 #endif
    01527     }
    01529
    01534     inline long int wait(const int milliseconds=20,long int reference_time=-1) {
    01535       static long int latest_time = time();
    01536       if (reference_time>=0) latest_time = reference_time;
    01537       const long int current_time = time(), time_diff = milliseconds + latest_time - current_time;
    01538       if (time_diff>0) { sleep(time_diff); return (latest_time = current_time + time_diff); }
    01539       else return (latest_time = current_time);
    01540     }
    01542     template<typename T> inline const T rol(const T& a,const unsigned int n=1) { return (a<<n)|(a>>((sizeof(T)<<3)-n)); }
    01544     template<typename T> inline const T ror(const T& a,const unsigned int n=1) { return (a>>n)|(a<<((sizeof(T)<<3)-n)); }
    01545
    01546 #if ( !defined(_MSC_VER) || _MSC_VER>1200 )
    01547
    01548     template<typename T> inline const T abs(const T& a) { return a>=0?a:-a; }
    01550     template<typename T> inline const T& min(const T& a,const T& b) { return a<=b?a:b; }
    01552     template<typename T> inline const T& min(const T& a,const T& b,const T& c) { return min(min(a,b),c); }
    01554     template<typename T> inline const T& min(const T& a,const T& b,const T& c,const T& d) { return min(min(min(a,b),c),d); }
    01556     template<typename T> inline const T& max(const T& a,const T& b) { return a>=b?a:b; }
    01558     template<typename T> inline const T& max(const T& a,const T& b,const T& c) { return max(max(a,b),c); }
    01560     template<typename T> inline const T& max(const T& a,const T& b,const T& c,const T& d) { return max(max(a,b,c),d); }
    01562     template<typename T> inline char sign(const T& x) { return (x<0)?-1:(x==0?0:1); }
    01563 #else
    01564     // Special versions due to object reference bug in VisualC++ 6.0.
    01565     template<typename T> inline const T abs(const T a) { return a>=0?a:-a; }
    01566     template<typename T> inline const T min(const T a,const T b) { return a<=b?a:b; }
    01567     template<typename T> inline const T min(const T a,const T b,const T c) { return min(min(a,b),c); }
    01568     template<typename T> inline const T min(const T a,const T b,const T c,const T& d) { return min(min(min(a,b),c),d); }
    01569     template<typename T> inline const T max(const T a,const T b) { return a>=b?a:b; }
    01570     template<typename T> inline const T max(const T a,const T b,const T c) { return max(max(a,b),c); }
    01571     template<typename T> inline const T max(const T a,const T b,const T c,const T& d) { return max(max(max(a,b),c),d); }
    01572     template<typename T> inline char sign(const T x) { return (x<0)?-1:(x==0?0:1); }
    01573 #endif
    01574
    01576
    01579     inline double mod(const double& x,const double& m) { return x-m*std::floor(x/m); }
    01580         inline float  mod(const float& x,const float& m)   { return (float)(x-m*std::floor((double)x/m)); }
    01581     inline int    mod(const int x,const int m)         { return x>=0?x%m:(x%m?m+x%m:0); }
    01582
    01584
    01589     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)); }
    01591     inline double rand() { return (double)std::rand()/RAND_MAX; }
    01593     inline double crand() { return 1-2*rand(); }
    01595     inline double grand() { return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*rand())))*std::cos((double)(2*PI*rand())); }
    01596   }
    01597
    01598   /*-------------------------------------------------------
    01599
    01600
    01601
    01602
    01603     Definition of the CImgStats structure
    01604
    01605
    01606
    01607
    01608     ------------------------------------------------------*/
    01610
    01624   struct CImgStats {
    01625     double min;
    01626     double max;
    01627     double mean;
    01628     double variance;
    01629     int xmin;
    01630     int ymin;
    01631     int zmin;
    01632     int vmin;
    01633     int lmin;
    01634     int xmax;
    01635     int ymax;
    01636     int zmax;
    01637     int vmax;
    01638     int lmax;
    01639
    01641     CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1),
    01642                 xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {}
    01644     CImgStats(const CImgStats& stats):min(stats.min),max(stats.max),mean(stats.mean),variance(stats.variance),
    01645                                       xmin(stats.xmin),ymin(stats.ymin),zmin(stats.zmin),vmin(stats.vmin),lmin(stats.lmin),
    01646                                       xmax(stats.xmax),ymax(stats.ymax),zmax(stats.zmax),vmax(stats.vmax),lmax(stats.lmax) {};
    01647
    01649
    01652     template<typename T> CImgStats(const CImg<T>& img,const bool compute_variance=true):mean(0),variance(0),lmin(-1),lmax(-1) {
    01653       cimg_test(img,"CImgStats::CImgStats");
    01654       T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin;
    01655       cimg_map(img,ptr,T) {
    01656         const T& a=*ptr;
    01657         mean+=(double)a;
    01658         if (a<pmin) { pmin=a; ptrmin = ptr; }
    01659         if (a>pmax) { pmax=a; ptrmax = ptr; }
    01660       }
    01661       mean/=img.size();
    01662       min=(double)pmin;
    01663       max=(double)pmax;
    01664       unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data);
    01665       const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height;
    01666       vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.height; xmin = offmin%img.width;
    01667       vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.height; xmax = offmax%img.width;
    01668       if (compute_variance) {
    01669         cimg_map(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
    01670         variance = std::sqrt(variance/img.size());
    01671       }
    01672     }
    01673
    01675
    01679     template<typename T> CImgStats(const CImgl<T>& list,const bool compute_variance=true):mean(0),variance(0) {
    01680       cimgl_test(list,"CImgStats::CImgStats");
    01681       T pmin=list[0][0], pmax=pmin, *ptrmin=list[0].data, *ptrmax=ptrmin;
    01682       int psize=0;
    01683       cimgl_map(list,l) {
    01684         cimg_map(list[l],ptr,T) {
    01685           const T& a=*ptr;
    01686           mean+=(double)a;
    01687           if (a<pmin) { pmin=a; ptrmin = ptr; lmin = l; }
    01688           if (a>pmax) { pmax=a; ptrmax = ptr; lmax = l; }
    01689         }
    01690         psize+=list[l].size();
    01691       }
    01692       mean/=psize;
    01693       min=(double)pmin;
    01694       max=(double)pmax;
    01695       const CImg<T> &imin = list[lmin], &imax = list[lmax];
    01696       unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data);
    01697       const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height;
    01698       vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.height; xmin = offmin%imin.width;
    01699       const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height;
    01700       vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.height; xmax = offmax%imax.width;
    01701       if (compute_variance) {
    01702         cimgl_map(list,l) cimg_map(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
    01703         variance = std::sqrt(variance/psize);
    01704       }
    01705     }
    01706
    01708     CImgStats& operator=(const CImgStats stats) {
    01709       min = stats.min;
    01710       max = stats.max;
    01711       mean = stats.mean;
    01712       variance = stats.variance;
    01713       xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin;
    01714       xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax;
    01715       return *this;
    01716     }
    01718     const CImgStats& print(const char* title=NULL) const {
    01719       if (lmin>=0 && lmax>=0)
    01720         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
    01721                      "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n",
    01722                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
    01723                      lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax);
    01724       else
    01725         std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
    01726                      "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n",
    01727                      title?title:"CImgStats",(void*)this,min,mean,variance,max,
    01728                      xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax);
    01729       return *this;
    01730     }
    01731
    01732 #ifdef cimgstats_plugin
    01733 #include cimgstats_plugin
    01734 #endif
    01735
    01736   };
    01737
    01738   /*-------------------------------------------------------
    01739
    01740
    01741
    01742
    01743     Definition of the CImgDisplay structure
    01744
    01745
    01746
    01747
    01748   ------------------------------------------------------*/
    01750
    01758   struct CImgDisplay {
    01759
    01760     //------------------------
    01761     //
    01762     // CImgDisplay variables
    01763     //
    01764     //------------------------
    01765
    01767
    01780     unsigned int width;
    01781
    01783
    01796     unsigned int height;
    01797
    01800
    01806     volatile unsigned int window_width;
    01807
    01810
    01816     volatile unsigned int window_height;
    01817
    01819
    01829     unsigned int normalization;
    01830
    01832
    01843     unsigned int events;
    01844
    01846
    01851     const bool fullscreen;
    01852
    01855
    01863     volatile int mousex;
    01864
    01867
    01875     volatile int mousey;
    01876
    01879
    01894     volatile unsigned int button;
    01895
    01897
    01922     volatile unsigned int key;
    01923
    01925
    01948     volatile bool closed;
    01949
    01951     volatile bool resized;
    01952
    01953     // Not documented, internal use only.
    01954     double min,max;
    01955
    01956     //------------------------
    01957     //
    01958     // CImgDisplay functions
    01959     //
    01960     //------------------------
    01961
    01963
    01969     const int dimx() const { return (int)width; }
    01970
    01972
    01978     const int dimy() const { return (int)height; }
    01979
    01980     const int window_dimx() const { return (int)window_width; }
    01981     const int window_dimy() const { return (int)window_height; }
    01982
    01983     // operator=(). It is actually defined to avoid its use, and throw a CImgDisplay exception.
    01984     CImgDisplay& operator=(const CImgDisplay&) {
    01985       throw CImgDisplayException("CImgDisplay()::operator=() : Assignement of CImgDisplay is not allowed. Use pointers instead !");
    01986       return *this;
    01987     }
    01988
    01990
    01992       const CImgDisplay& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; }
    01993
    01995
    02004     template<typename T> CImgDisplay& display(const CImgl<T>& list,const char axe='x',const char align='c') {
    02005       return display(list.get_append(axe,align));
    02006     }
    02007
    02009
    02017     template<typename T> CImgDisplay& resize(const CImg<T>& img,const bool redraw=false,const bool force=true) {
    02018       return resize(img.width,img.height,redraw,force);
    02019     }
    02020
    02021     CImgDisplay& resize(const CImgDisplay& disp,const bool redraw=false,const bool force=true) {
    02022       return resize(disp.width,disp.height,redraw,force);
    02023     }
    02024
    02025     CImgDisplay& resize(const bool redraw=false,const bool force=false) {
    02026       resize(window_width,window_height,redraw,force);
    02027       return *this;
    02028     }
    02029
    02030     // When no display available
    02031     //---------------------------
    02032 #if cimg_display_type==0
    02033     void nodisplay_available() {
    02034       static bool first = true;
    02035       if (first) {
    02036         cimg::warn(true,"CImgDisplay() : Display has been required but is not available (cimg_display_type=0)");
    02037         first = false;
    02038       }
    02039     }
    02041
    02050     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02051                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02052                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02053       nodisplay_available();
    02054     }
    02055
    02057
    02064     template<typename T>
    02065     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02066                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02067                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02068       nodisplay_available();
    02069     }
    02070
    02072
    02079     template<typename T>
    02080     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02081                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02082                 const bool fullscreen_flag=false,const bool closed_flag=false):fullscreen(false) {
    02083       nodisplay_available();
    02084     }
    02085
    02087
    02090     CImgDisplay(const CImgDisplay& win, char *title=NULL):fullscreen(false) { nodisplay_available(); }
    02091
    02093     CImgDisplay& resize(const int width, const int height,const bool redraw=false,const bool force=true) {
    02094       return *this;
    02095     }
    02097     CImgDisplay& move(const int posx,const int posy) { return *this; }
    02098
    02100     const int window_posx() const { return 0; }
    02101
    02103     const int window_posy() const { return 0; }
    02104
    02106     ~CImgDisplay() {}
    02108     template<typename T> void render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {}
    02110     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=-1) { return *this; }
    02112     CImgDisplay& wait()  { return *this; }
    02114     CImgDisplay& show()  { return *this; }
    02116     CImgDisplay& close() { return *this; }
    02117
    02118     // X11-based display
    02119     //------------------
    02120 #elif cimg_display_type==1
    02121     void *data;
    02122     Window window;
    02123     XImage *image;
    02124
    02125     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02126                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02127                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02128       width(dimw),height(dimh),window_width(dimw),window_height(dimh),
    02129       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02130       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02131       if (!dimw || !dimh)
    02132         throw CImgArgumentException("CImgDisplay::CImgDisplay() : Cannot create a 0x0 display window. "
    02133                                     "A Correct size must be specified");
    02134       new_lowlevel(title);
    02135       std::memset(data,0,(cimg::X11_nb_bits>16?sizeof(unsigned long):sizeof(unsigned short))*width*height);
    02136       pthread_mutex_lock(cimg::X11_mutex);
    02137       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02138       XFlush(cimg::X11_display);
    02139       pthread_mutex_unlock(cimg::X11_mutex);
    02140     }
    02141
    02142     template<typename T>
    02143     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02144                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02145                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02146       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02147       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02148       cimg_test(img,"CImgDisplay::CImgDisplay");
    02149       CImg<T> tmp;
    02150       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
    02151       window_width  = width  = nimg.width;
    02152       window_height = height = nimg.height;
    02153       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02154       new_lowlevel(title);
    02155       display(nimg);
    02156     }
    02157
    02158     template<typename T>
    02159     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02160                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02161                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02162       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02163       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02164       cimgl_test(list,"CImgDisplay::CImgDisplay");
    02165       CImg<T> tmp;
    02166       const CImg<T> img0 = list.get_append('x'),
    02167         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
    02168       window_width  = width  = img.width;
    02169       window_height = height = img.height;
    02170       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02171       new_lowlevel(title);
    02172       display(img);
    02173     }
    02174
    02175     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
    02176       width(win.width),height(win.height),window_width(width),window_height(height),
    02177       normalization(win.normalization),events(win.events),fullscreen(win.fullscreen),
    02178       mousex(-1),mousey(-1),button(0),key(0),closed(win.closed),resized(false),min(win.min),max(win.max) {
    02179       new_lowlevel(title);
    02180       std::memcpy(data,win.data,(cimg::X11_nb_bits>16?sizeof(unsigned long):sizeof(short))*width*height);
    02181       pthread_mutex_lock(cimg::X11_mutex);
    02182       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02183       XFlush(cimg::X11_display);
    02184       pthread_mutex_unlock(cimg::X11_mutex);
    02185     }
    02186
    02187     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
    02188       const unsigned int
    02189         dimx=nwidth>0?nwidth:-width*nwidth/100,
    02190         dimy=nheight>0?nheight:-height*nheight/100;
    02191       if (!dimx || !dimy) return *this;
    02192       pthread_mutex_lock(cimg::X11_mutex);
    02193       if (dimx!=width || dimy!=height) {
    02194         if (cimg::X11_nb_bits>16) {
    02195           unsigned long *ndata = new unsigned long[dimx*dimy];
    02196           if (redraw) for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
    02197             ndata[x+y*dimx] = ((unsigned long*)data)[x*width/dimx + width*(y*height/dimy)];
    02198           else std::memset(ndata,0,sizeof(unsigned long)*dimx*dimy);
    02199           data = (void*)ndata;
    02200         } else {
    02201           unsigned short *ndata = new unsigned short[dimx*dimy];
    02202           if (redraw) for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++)
    02203             ndata[x+y*dimx] = ((unsigned short*)data)[x*width/dimx + width*(y*height/dimy)];
    02204           else std::memset(ndata,0,sizeof(unsigned short)*dimx*dimy);
    02205           data = (void*)ndata;
    02206         }
    02207         XDestroyImage(image);
    02208         image = XCreateImage(cimg::X11_display,DefaultVisual(cimg::X11_display,DefaultScreen(cimg::X11_display)),
    02209                              cimg::X11_nb_bits,ZPixmap,0,(char*)data,dimx,dimy,8,0);
    02210       }
    02211       width  = dimx;
    02212       height = dimy;
    02213       if (force && (window_width!=width || window_height!=height)) {
    02214         XResizeWindow(cimg::X11_display,window,width,height);
    02215         window_width  = width;
    02216         window_height = height;
    02217       }
    02218       XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02219       XFlush(cimg::X11_display);
    02220       resized = false;
    02221       pthread_mutex_unlock(cimg::X11_mutex);
    02222       return *this;
    02223     }
    02224
    02225     CImgDisplay& move(const int posx,const int posy) {
    02226       pthread_mutex_lock(cimg::X11_mutex);
    02227       XMoveWindow(cimg::X11_display,window,posx,posy);
    02228       XFlush(cimg::X11_display);
    02229       pthread_mutex_unlock(cimg::X11_mutex);
    02230       return *this;
    02231     }
    02232
    02233     /*
    02234       const int window_posx() const {
    02235       pthread_mutex_lock(cimg::X11_mutex);
    02236       XWindowAttributes attr;
    02237       int st = XGetWindowAttributes(cimg::X11_display,window,&attr);
    02238       pthread_mutex_unlock(cimg::X11_mutex);
    02239       return attr.x;
    02240       }
    02241
    02242       const int window_posy() const {
    02243       pthread_mutex_lock(cimg::X11_mutex);
    02244       XWindowAttributes attr;
    02245       XGetWindowAttributes(cimg::X11_display,window,&attr);
    02246       pthread_mutex_unlock(cimg::X11_mutex);
    02247       return attr.y;
    02248       }
    02249     */
    02250
    02251     ~CImgDisplay() {
    02252       unsigned int i;
    02253       pthread_mutex_lock(cimg::X11_mutex);
    02254       for (i=0; i<cimg::X11_nb_wins && cimg::X11_wins[i]!=this; i++) i++;
    02255       for (; i<cimg::X11_nb_wins-1; i++) cimg::X11_wins[i]=cimg::X11_wins[i+1];
    02256       cimg::X11_nb_wins--;
    02257       XDestroyWindow(cimg::X11_display,window);
    02258       XDestroyImage(image);
    02259       if (!cimg::X11_nb_wins) {
    02260         pthread_cancel(*cimg::X11_event_thread);
    02261         pthread_join(*cimg::X11_event_thread,NULL);
    02262         XCloseDisplay(cimg::X11_display);
    02263         cimg::X11_display=NULL;
    02264         pthread_mutex_unlock(cimg::X11_mutex);
    02265         pthread_mutex_destroy(cimg::X11_mutex);
    02266         delete cimg::X11_event_thread;
    02267         delete cimg::X11_mutex;
    02268         delete cimg::X11_gc;
    02269       } else pthread_mutex_unlock(cimg::X11_mutex);
    02270     }
    02271
    02272     void new_lowlevel(const char *title=NULL) {
    02273       cimg::warn(fullscreen,"CImgDisplay::new_lowlevel() : Fullscreen mode requested, but not supported on X11 Displays");
    02274       if (!cimg::X11_display) {
    02275         cimg::X11_nb_wins = 0;
    02276         cimg::X11_thread_finished = false;
    02277         cimg::X11_mutex = new pthread_mutex_t;
    02278         pthread_mutex_init(cimg::X11_mutex,NULL);
    02279         pthread_mutex_lock(cimg::X11_mutex);
    02280         cimg::X11_display = XOpenDisplay((getenv("DISPLAY") ? getenv("DISPLAY") : ":0.0"));
    02281         if (!cimg::X11_display) throw CImgDisplayException("CImgDisplay::new_lowlevel() : Can't open X11 display");
    02282         cimg::X11_nb_bits = DefaultDepth(cimg::X11_display, DefaultScreen(cimg::X11_display));
    02283         if (cimg::X11_nb_bits!=16 && cimg::X11_nb_bits!=24)
    02284           throw CImgDisplayException("CImgDisplay::new_lowlevel() : %u bits mode is not supported (only 16 and 24 bits are supported)",
    02285                                      cimg::X11_nb_bits);
    02286         cimg::X11_gc = new GC;
    02287         *cimg::X11_gc = DefaultGC(cimg::X11_display,DefaultScreen(cimg::X11_display));
    02288         Visual *visual = DefaultVisual(cimg::X11_display,0);
    02289         XVisualInfo vtemplate;
    02290         vtemplate.visualid = XVisualIDFromVisual(visual);
    02291         int nb_visuals;
    02292         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11_display,VisualIDMask,&vtemplate,&nb_visuals);
    02293         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_endian = true;
    02294         cimg::X11_event_thread = new pthread_t;
    02295         pthread_create(cimg::X11_event_thread,NULL,thread_lowlevel,NULL);
    02296       } else pthread_mutex_lock(cimg::X11_mutex);
    02297       window = XCreateSimpleWindow(cimg::X11_display,RootWindow(cimg::X11_display,DefaultScreen(cimg::X11_display)),
    02298                                    0,0,width,height,2,0,0x0L);
    02299       if (cimg::X11_nb_bits>16) data = new unsigned long[width*height]; else data = new unsigned short[width*height];
    02300       image  = XCreateImage(cimg::X11_display,DefaultVisual(cimg::X11_display,DefaultScreen(cimg::X11_display)),
    02301                             cimg::X11_nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
    02302       XStoreName(cimg::X11_display,window,title?title:"");
    02303       if (!closed) {
    02304         XEvent event;
    02305         XSelectInput(cimg::X11_display,window,StructureNotifyMask);
    02306         XMapWindow(cimg::X11_display,window);
    02307         do XWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event); while (event.type!=MapNotify);
    02308       }
    02309       if (events) {
    02310         Atom atom = XInternAtom(cimg::X11_display, "WM_DELETE_WINDOW", False);
    02311         XSetWMProtocols(cimg::X11_display, window, &atom, 1);
    02312       }
    02313       cimg::X11_wins[cimg::X11_nb_wins++]=this;
    02314       pthread_mutex_unlock(cimg::X11_mutex);
    02315     }
    02316
    02317     void proc_lowlevel(XEvent *pevent) {
    02318       const unsigned int buttoncode[3] = { 1,4,2 };
    02319       XEvent event=*pevent;
    02320       switch (event.type) {
    02321       case ClientMessage:
    02322         XUnmapWindow(cimg::X11_display,window);
    02323         mousex=mousey=-1;
    02324         button=key=0;
    02325         closed=true;
    02326         break;
    02327      case ConfigureNotify: {
    02328         while (XCheckWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event));
    02329         const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height;
    02330         if (nw && nh && (nw!=window_width || nh!=window_height)) {
    02331           window_width = nw;
    02332           window_height = nh;
    02333           mousex = mousey = -1;
    02334           XResizeWindow(cimg::X11_display,window,window_width,window_height);
    02335           resized = true;
    02336         }
    02337       } break;
    02338       case Expose:
    02339         while (XCheckWindowEvent(cimg::X11_display,window,ExposureMask,&event));
    02340         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02341         break;
    02342       case ButtonPress:
    02343         while (XCheckWindowEvent(cimg::X11_display,window,ButtonPressMask,&event));
    02344         button |= buttoncode[event.xbutton.button-1];
    02345         break;
    02346       case ButtonRelease:
    02347         while (XCheckWindowEvent(cimg::X11_display,window,ButtonReleaseMask,&event));
    02348         button &= ~buttoncode[event.xbutton.button-1];
    02349         break;
    02350       case KeyPress: {
    02351         while (XCheckWindowEvent(cimg::X11_display,window,KeyPressMask,&event));
    02352         char tmp;
    02353         KeySym ksym;
    02354         XLookupString(&event.xkey,&tmp,1,&ksym,NULL);
    02355         key = (unsigned int)ksym;
    02356       }
    02357         break;
    02358       case KeyRelease:
    02359         while (XCheckWindowEvent(cimg::X11_display,window,KeyReleaseMask,&event));
    02360         key = 0;
    02361         break;
    02362       case LeaveNotify:
    02363         while (XCheckWindowEvent(cimg::X11_display,window,LeaveWindowMask,&event));
    02364         mousex = mousey =-1;
    02365         break;
    02366       case MotionNotify:
    02367         while (XCheckWindowEvent(cimg::X11_display,window,PointerMotionMask,&event));
    02368         mousex = event.xmotion.x;
    02369         mousey = event.xmotion.y;
    02370         if (mousex<0 || mousey<0 || mousex>=dimx() || mousey>=dimy()) mousex=mousey=-1;
    02371         break;
    02372       }
    02373     }
    02374
    02375     static void* thread_lowlevel(void *arg) {
    02376       XEvent event;
    02377       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    02378       for (;;) {
    02379         pthread_mutex_lock(cimg::X11_mutex);
    02380         for (unsigned int i=0; i<cimg::X11_nb_wins; i++) {
    02381           const unsigned int xevent_type = (cimg::X11_wins[i]->events)&3;
    02382           const unsigned int emask =
    02383             ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
    02384             ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
    02385             ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
    02386           XSelectInput(cimg::X11_display,cimg::X11_wins[i]->window,emask);
    02387         }
    02388         bool event_flag = XCheckTypedEvent(cimg::X11_display, ClientMessage, &event);
    02389         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11_display,
    02390                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
    02391                                                       KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
    02392                                                       KeyReleaseMask,&event);
    02393         if (event_flag) {
    02394           for (unsigned int i=0; i<cimg::X11_nb_wins; i++)
    02395             if (!cimg::X11_wins[i]->closed && event.xany.window==cimg::X11_wins[i]->window) cimg::X11_wins[i]->proc_lowlevel(&event);
    02396           cimg::X11_thread_finished = true;
    02397         }
    02398         pthread_mutex_unlock(cimg::X11_mutex);
    02399         cimg::wait(25);
    02400       }
    02401       return NULL;
    02402     }
    02403
    02404     template<typename T> XImage* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
    02405       cimg_test(img,"CImgDisplay::render");
    02406       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),0,~0);
    02407       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),0,~0);
    02408       const bool by=(ymin<=ymax);
    02409       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin);
    02410       const T
    02411         *data1 = img.ptr(0,nymin,0,0),
    02412         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
    02413         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
    02414       pthread_mutex_lock(cimg::X11_mutex);
    02415       if (!normalization) {
    02416         switch (cimg::X11_nb_bits) {
    02417         case 16: {
    02418           unsigned char *x11_buffer = (unsigned char*)data + sizeof(unsigned short)*nymin*width;
    02419           if (cimg::X11_endian) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02420             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
    02421             *(x11_buffer++) = (R&0xF8)|(G>>5); *(x11_buffer++) = (B>>3)|((G>>2)<<5);
    02422           } else for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02423             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
    02424             *(x11_buffer++) = (B>>3)|((G>>2)<<5); *(x11_buffer++) = (R&0xF8)|(G>>5);
    02425           }
    02426         } break;
    02427         case 24: {
    02428           unsigned char *x11_buffer = (unsigned char*)data + sizeof(unsigned long)*nymin*width;
    02429           if (cimg::X11_endian) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02430             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
    02431             *(x11_buffer++) = 0; *(x11_buffer++) = B; *(x11_buffer++) = G; *(x11_buffer++) = R;
    02432           } else for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02433             const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
    02434             *(x11_buffer++) = B; *(x11_buffer++) = G; *(x11_buffer++) = R; *(x11_buffer++) = 0;
    02435           }
    02436         } break;
    02437         };
    02438       } else {
    02439         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
    02440         const T nmin = (T)min, delta = (T)max-nmin, mm=delta?delta:(T)1;
    02441         switch (cimg::X11_nb_bits) {
    02442         case 16: {
    02443           unsigned char *x11_buffer = (unsigned char*)data + sizeof(unsigned short)*nymin*width;
    02444           if (cimg::X11_endian) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02445             const unsigned char
    02446               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02447               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02448               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02449             *(x11_buffer++) = (R&0xF8)|(G>>5); *(x11_buffer++) = (B>>3)|((G>>2)<<5);
    02450           } else for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02451             const unsigned char
    02452               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02453               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02454               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02455             *(x11_buffer++) = (B>>3)|((G>>2)<<5); *(x11_buffer++) = (R&0xF8)|(G>>5);
    02456           }
    02457         } break;
    02458         case 24: {
    02459           unsigned char *x11_buffer = (unsigned char*)data  + sizeof(unsigned long)*nymin*width;
    02460           if (cimg::X11_endian) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02461             const unsigned char
    02462               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02463               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02464               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02465             *(x11_buffer++) = 0; *(x11_buffer++) = B; *(x11_buffer++) = G; *(x11_buffer++) = R;
    02466           } else for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02467             const unsigned char
    02468               R = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02469               G = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02470               B = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02471             *(x11_buffer++) = B; *(x11_buffer++) = G; *(x11_buffer++) = R; *(x11_buffer++) = 0;
    02472           }
    02473         } break;
    02474         }
    02475       }
    02476       pthread_mutex_unlock(cimg::X11_mutex);
    02477       return image;
    02478     }
    02479
    02480     template<typename T> CImgDisplay& display(const CImg<T>& pimg,const unsigned int pymin=0,const unsigned int pymax=~0) {
    02481       const unsigned int
    02482         ymin = pymin<pymax?pymin:pymax,
    02483         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
    02484       render(pimg,ymin,ymax);
    02485       if (!closed) {
    02486         pthread_mutex_lock(cimg::X11_mutex);
    02487         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,ymin,0,ymin,width,ymax-ymin+1);
    02488         XFlush(cimg::X11_display);
    02489         pthread_mutex_unlock(cimg::X11_mutex);
    02490       }
    02491       return *this;
    02492     }
    02493
    02494     CImgDisplay& wait() {
    02495       if (!closed && events) {
    02496         XEvent event;
    02497         do {
    02498           pthread_mutex_lock(cimg::X11_mutex);
    02499           const unsigned int
    02500             emask = ExposureMask|StructureNotifyMask|
    02501             ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
    02502             ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0);
    02503           XSelectInput(cimg::X11_display,window,emask);
    02504           XPeekEvent(cimg::X11_display,&event);
    02505           cimg::X11_thread_finished = false;
    02506           pthread_mutex_unlock(cimg::X11_mutex);
    02507         } while (event.xany.window!=window);
    02508         while (!cimg::X11_thread_finished) cimg::wait(25);
    02509       }
    02510       return *this;
    02511     }
    02512
    02513     CImgDisplay& show() {
    02514       if (closed) {
    02515         pthread_mutex_lock(cimg::X11_mutex);
    02516         XEvent event;
    02517         XSelectInput(cimg::X11_display,window,StructureNotifyMask);
    02518         XMapWindow(cimg::X11_display,window);
    02519         do XWindowEvent(cimg::X11_display,window,StructureNotifyMask,&event);
    02520         while (event.type!=MapNotify);
    02521         XPutImage(cimg::X11_display,window,*cimg::X11_gc,image,0,0,0,0,width,height);
    02522         XFlush(cimg::X11_display);
    02523         closed = false;
    02524         pthread_mutex_unlock(cimg::X11_mutex);
    02525       }
    02526       return *this;
    02527     }
    02528     CImgDisplay& close() {
    02529       if (!closed) {
    02530         pthread_mutex_lock(cimg::X11_mutex);
    02531         XUnmapWindow(cimg::X11_display,window);
    02532         XFlush(cimg::X11_display);
    02533         closed = true;
    02534         pthread_mutex_unlock(cimg::X11_mutex);
    02535       }
    02536       return *this;
    02537     }
    02538
    02539     // Windows-based display
    02540     //-----------------------
    02541 #elif cimg_display_type==2
    02542     CLIENTCREATESTRUCT ccs;
    02543     BITMAPINFO bmi;
    02544     unsigned int *data;
    02545     DEVMODE curr_mode;
    02546     HWND window;
    02547     HDC hdc;
    02548     HANDLE thread;
    02549     HANDLE wait_disp;
    02550     HANDLE created;
    02551     HANDLE mutex;
    02552
    02553     CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL,
    02554                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02555                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02556       width(dimw),height(dimh),window_width(dimw),window_height(dimh),
    02557       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02558       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02559       if (!dimw || !dimh)
    02560         throw CImgArgumentException("CImgDisplay::CImgDisplay() : Cannot create a 0x0 display window. "
    02561                                     "A Correct size must be specified");
    02562       new_lowlevel(title);
    02563       std::memset(data,0,sizeof(unsigned int)*width*height);
    02564       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02565     }
    02566
    02567     template<typename T>
    02568     CImgDisplay(const CImg<T>& img,const char *title=NULL,
    02569                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02570                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02571       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02572       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02573       cimg_test(img,"CImgDisplay::CImgDisplay");
    02574       CImg<T> tmp;
    02575       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_3dplanes(img.width/2,img.height/2,img.depth/2));
    02576       window_width  = width  = nimg.width;
    02577       window_height = height = nimg.height;
    02578       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02579       new_lowlevel(title);
    02580       display(nimg);
    02581     }
    02582
    02583     template<typename T>
    02584     CImgDisplay(const CImgl<T>& list,const char *title=NULL,
    02585                 const unsigned int normalization_type=1,const unsigned int events_type=3,
    02586                 const bool fullscreen_flag=false,const bool closed_flag=false):
    02587       normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag),
    02588       mousex(-1),mousey(-1),button(0),key(0),closed(closed_flag),resized(false),min(0),max(0) {
    02589       cimgl_test(list,"CImgDisplay::CImgDisplay");
    02590       CImg<T> tmp;
    02591       const CImg<T> img0 = list.get_append('x'),
    02592         &img = (img0.depth==1)?img0:(tmp=img0.get_3dplanes(img0.width/2,img0.height/2,img0.depth/2));
    02593       window_width  = width  = img.width;
    02594       window_height = height = img.height;
    02595       if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; }
    02596       new_lowlevel(title);
    02597       display(img);
    02598     }
    02599
    02600     CImgDisplay(const CImgDisplay& win, char *title="[Copy]"):
    02601       width(win.width),height(win.height),window_width(win.width),window_height(win.height),
    02602       normalization(win.normalization),events(win.events),fullscreen(win.fullscreen),
    02603       mousex(-1),mousey(-1),button(0),key(0),closed(win.closed),resized(false),min(win.min),max(win.max) {
    02604       new_lowlevel(title);
    02605       std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
    02606       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02607     }
    02608
    02609     CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) {
    02610       const unsigned int
    02611         dimx=nwidth>0?nwidth:(-nwidth)*width/100,
    02612         dimy=nheight>0?nheight:(-nheight)*height/100;
    02613       if (!dimx || !dimy) return *this;
    02614       if (dimx!=width || dimy!=height) {
    02615         unsigned int *ndata = new unsigned int[dimx*dimy];
    02616         if (redraw)
    02617           for (unsigned int y=0; y<dimy; y++) for (unsigned int x=0; x<dimx; x++) ndata[x+y*dimx] = data[x*width/dimx + width*(y*height/dimy)];
    02618         else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
    02619         delete[] data;
    02620         data = ndata;
    02621         bmi.bmiHeader.biWidth=dimx;
    02622         bmi.bmiHeader.biHeight=-(int)dimy;
    02623       }
    02624       width  = dimx;
    02625       height = dimy;
    02626       if (force && (window_width!=width || window_height!=height)) {
    02627         int cwidth,cheight;
    02628         RECT rect;
    02629         rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1;
    02630         if (AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false)) {
    02631           cwidth = rect.right-rect.left+1; cheight = rect.bottom-rect.top+1;
    02632         } else { cwidth = width+9; cheight = height+28; }
    02633         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
    02634         window_width  = dimx;
    02635         window_height = dimy;
    02636       }
    02637       SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02638       resized = false;
    02639       return *this;
    02640     }
    02641
    02642     CImgDisplay& move(const int posx,const int posy) {
    02643       SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
    02644       return *this;
    02645     }
    02646
    02647     ~CImgDisplay() {
    02648       DestroyWindow(window);
    02649       if (events) TerminateThread(thread,0);
    02650       delete[] data;
    02651       if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
    02652     }
    02653
    02654     void new_lowlevel(const char *title=NULL) {
    02655       unsigned long ThreadID;
    02656       DEVMODE mode;
    02657       unsigned int imode=0,ibest=0,bestbpp=0;
    02658       void *arg = (void*)(new void*[2]);
    02659       ((void**)arg)[0]=(void*)this;
    02660       ((void**)arg)[1]=(void*)title;
    02661       if (fullscreen) {
    02662         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(NULL,imode,&mode); imode++)
    02663           if (mode.dmPelsWidth==width && mode.dmPelsHeight==height && mode.dmBitsPerPel>bestbpp) {
    02664             bestbpp = mode.dmBitsPerPel;
    02665             ibest=imode;
    02666           }
    02667         cimg::warn(!bestbpp,"CImgDisplay::new_lowlevel() : Could not initialize fullscreen mode %ux%u\n",width,height);
    02668         if (bestbpp) {
    02669           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
    02670           EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&curr_mode);
    02671           EnumDisplaySettings(NULL,ibest,&mode);
    02672           ChangeDisplaySettings(&mode,0);
    02673         }
    02674         else curr_mode.dmSize = 0;
    02675       }
    02676       else curr_mode.dmSize = 0;
    02677       if (events) {
    02678         mutex     = CreateMutex(NULL,FALSE,NULL);
    02679         created   = CreateEvent(NULL,FALSE,FALSE,NULL);
    02680         wait_disp = CreateEvent(NULL,FALSE,FALSE,NULL);
    02681         thread    = CreateThread(NULL,0,thread_lowlevel,arg,0,&ThreadID);
    02682         WaitForSingleObject(created,INFINITE);
    02683       } else thread_lowlevel(arg);
    02684     }
    02685
    02686     static LRESULT APIENTRY proc_lowlevel(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
    02687       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
    02688       MSG st_msg;
    02689
    02690       switch(msg) {
    02691       case WM_CLOSE:
    02692         disp->mousex=disp->mousey=-1;
    02693         disp->key=disp->button=0;
    02694         disp->closed=true;
    02695         ReleaseMutex(disp->mutex);
    02696         ShowWindow(disp->window,SW_HIDE);
    02697         return 0;
    02698       case WM_SIZE: {
    02699         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE));
    02700         WaitForSingleObject(disp->mutex,INFINITE);
    02701         const unsigned int nw = LOWORD(lParam), nh = HIWORD(lParam);
    02702         if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
    02703           disp->window_width  = nw;
    02704           disp->window_height = nh;
    02705           disp->mousex = disp->mousey = -1;
    02706           disp->resized = true;
    02707         }
    02708         ReleaseMutex(disp->mutex);
    02709       }
    02710         break;
    02711       case WM_PAINT:
    02712         WaitForSingleObject(disp->mutex,INFINITE);
    02713         SetDIBitsToDevice(disp->hdc,0,0,disp->width,disp->height,0,0,0,disp->height,disp->data,&(disp->bmi),DIB_RGB_COLORS);
    02714         ReleaseMutex(disp->mutex);
    02715         break;
    02716       }
    02717       if (disp->events>=2) switch(msg) {
    02718       case WM_KEYDOWN:
    02719         while (PeekMessage(&st_msg,window,WM_KEYDOWN,WM_KEYDOWN,PM_REMOVE));
    02720         disp->key=(int)wParam;
    02721         break;
    02722       case WM_MOUSEMOVE: {
    02723         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE));
    02724         disp->mousex = LOWORD(lParam);
    02725         disp->mousey = HIWORD(lParam);
    02726         if (disp->mousex<0 || disp->mousey<0 || disp->mousex>=disp->dimx() || disp->mousey>=disp->dimy())
    02727           disp->mousex=disp->mousey=-1;
    02728       }
    02729         break;
    02730       case WM_LBUTTONDOWN:
    02731         while (PeekMessage(&st_msg,window,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE));
    02732         disp->button |= 1;
    02733         break;
    02734       case WM_RBUTTONDOWN:
    02735         while (PeekMessage(&st_msg,window,WM_RBUTTONDOWN,WM_RBUTTONDOWN,PM_REMOVE));
    02736         disp->button |= 2;
    02737         break;
    02738       case WM_MBUTTONDOWN:
    02739         while (PeekMessage(&st_msg,window,WM_MBUTTONDOWN,WM_MBUTTONDOWN,PM_REMOVE));
    02740         disp->button |= 4;
    02741         break;
    02742       }
    02743       if (disp->events>=3) switch(msg) {
    02744       case WM_KEYUP:
    02745         while (PeekMessage(&st_msg,window,WM_KEYUP,WM_KEYUP,PM_REMOVE));
    02746         disp->key=0;
    02747         break;
    02748       case WM_LBUTTONUP:
    02749         while (PeekMessage(&st_msg,window,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE));
    02750         disp->button &= ~1;
    02751         break;
    02752       case WM_RBUTTONUP:
    02753         while (PeekMessage(&st_msg,window,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE));
    02754         disp->button &= ~2;
    02755         break;
    02756       case WM_MBUTTONUP:
    02757         while (PeekMessage(&st_msg,window,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE));
    02758         disp->button &= ~4;
    02759         break;
    02760       }
    02761       return DefWindowProc(window,msg,wParam,lParam);
    02762     }
    02763
    02764     static DWORD WINAPI thread_lowlevel(void* arg) {
    02765       CImgDisplay *disp  = (CImgDisplay*)(((void**)arg)[0]);
    02766       const char *title = (const char*)(((void**)arg)[1]);
    02767       MSG msg;
    02768       delete[] (void**)arg;
    02769       disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    02770       disp->bmi.bmiHeader.biWidth=disp->width;
    02771       disp->bmi.bmiHeader.biHeight=-(int)disp->height;
    02772       disp->bmi.bmiHeader.biPlanes=1;
    02773       disp->bmi.bmiHeader.biBitCount=32;
    02774       disp->bmi.bmiHeader.biCompression=BI_RGB;
    02775       disp->bmi.bmiHeader.biSizeImage=0;
    02776       disp->bmi.bmiHeader.biXPelsPerMeter=1;
    02777       disp->bmi.bmiHeader.biYPelsPerMeter=1;
    02778       disp->bmi.bmiHeader.biClrUsed=0;
    02779       disp->bmi.bmiHeader.biClrImportant=0;
    02780       disp->data = new unsigned int[disp->width*disp->height];
    02781       if (!disp->curr_mode.dmSize) {
    02782         int cwidth,cheight;
    02783         RECT rect;
    02784         rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1;
    02785         if (AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false)) {
    02786           cwidth = rect.right-rect.left+1; cheight = rect.bottom-rect.top+1;
    02787         } else { cwidth = disp->width+9; cheight = disp->height+28; }
    02788         disp->window = CreateWindow("MDICLIENT",title?title:"",
    02789                                     WS_OVERLAPPEDWINDOW | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
    02790                                     cwidth,cheight,NULL,NULL,NULL,&(disp->ccs));
    02791       }
    02792       else disp->window = CreateWindow("MDICLIENT",title?title:"",
    02793                                        WS_POPUP | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
    02794                                        disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs));
    02795       SetForegroundWindow(disp->window);
    02796       disp->hdc = GetDC(disp->window);
    02797       if (disp->events) {
    02798         SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
    02799         SetWindowLong(disp->window,GWL_WNDPROC,(LONG)proc_lowlevel);
    02800         SetEvent(disp->created);
    02801         while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); SetEvent(disp->wait_disp); }
    02802       }
    02803       return 0;
    02804     }
    02805
    02806     template<typename T> BITMAPINFO* render(const CImg<T>& img,const unsigned int ymin=0,const unsigned int ymax=~0) {
    02807       cimg_test(img,"CImgDisplay::render");
    02808       if (img.depth!=1) return render(img.get_3dplanes(img.width/2,img.height/2,img.depth/2),(unsigned int)0,~(unsigned int)0);
    02809       if (img.width!=width || img.height!=height) return render(img.get_resize(width,height,1,-100,1),(unsigned int)0,~(unsigned int)0);
    02810       const bool by=(ymin<=ymax);
    02811       const unsigned int nymin = by?ymin:ymax, nymax = by?(ymax>=height?height-1:ymax):(ymin>=height?height-1:ymin);
    02812       const T
    02813         *data1 = img.ptr(0,nymin,0,0),
    02814         *data2 = (img.dim>=2)?img.ptr(0,nymin,0,1):data1,
    02815         *data3 = (img.dim>=3)?img.ptr(0,nymin,0,2):data1;
    02816       unsigned int *ximg = data + nymin*width;
    02817       WaitForSingleObject(mutex,INFINITE);
    02818       if (!normalization) for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--)
    02819         *(ximg++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
    02820       else {
    02821         if (normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; }
    02822         const T nmin = (T)min, delta = (T)(max-nmin), mm = delta?delta:(T)1;
    02823         for (unsigned int xy = (nymax-nymin+1)*width; xy>0; xy--) {
    02824           const unsigned char
    02825             R = (unsigned char)(255*(*(data1++)-nmin)/mm),
    02826             G = (unsigned char)(255*(*(data2++)-nmin)/mm),
    02827             B = (unsigned char)(255*(*(data3++)-nmin)/mm);
    02828           *(ximg++) = (R<<16) | (G<<8) | (B);
    02829         }
    02830       }
    02831       ReleaseMutex(mutex);
    02832       return &bmi;
    02833     }
    02834
    02835     template<typename T> CImgDisplay& display(const CImg<T>& img,const unsigned int pymin=0,const unsigned int pymax=~0) {
    02836       cimg_test(img,"CImgDisplay::display");
    02837       const unsigned int
    02838         ymin = pymin<pymax?pymin:pymax,
    02839         ymax = pymin<pymax?(pymax>=height?height-1:pymax):(pymin>=height?height-1:pymin);
    02840       render(img,ymin,ymax);
    02841       if (!closed) {
    02842         WaitForSingleObject(mutex,INFINITE);
    02843         SetDIBitsToDevice(hdc,0,ymin,width,ymax-ymin+1,0,0,0,ymax-ymin+1,data+ymin*width,&bmi,DIB_RGB_COLORS);
    02844         ReleaseMutex(mutex);
    02845       }
    02846       return *this;
    02847     }
    02848
    02849     CImgDisplay& wait() {
    02850       if (!closed && events) WaitForSingleObject(wait_disp,INFINITE);
    02851       return *this;
    02852     }
    02853
    02854     CImgDisplay& show() {
    02855       if (closed) {
    02856         ShowWindow(window,SW_SHOW);
    02857         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
    02858         closed = false;
    02859       }
    02860       return *this;
    02861     }
    02862
    02863     CImgDisplay& close() {
    02864       if (!closed) {
    02865         ShowWindow(window,SW_HIDE);
    02866         closed = true;
    02867       }
    02868       return *this;
    02869     }
    02870 #endif
    02871
    02872 #ifdef cimgdisplay_plugin
    02873 #include cimgdisplay_plugin
    02874 #endif
    02875
    02876   };
    02877
    02878
    02879   /*-------------------------------------------------------
    02880
    02881
    02882
    02883
    02884     Definition of the CImg<T> structure
    02885
    02886
    02887
    02888
    02889   ------------------------------------------------------*/
    02890
    02892
    02963   template<typename T> struct CImg {
    02964
    02966
    02974     unsigned int width;
    02975
    02977
    02985     unsigned int height;
    02986
    02988
    02996     unsigned int depth;
    02997
    02999
    03007     unsigned int dim;
    03008
    03010
    03018     T *data;
    03019
    03020     //------------------------------------------
    03021     //------------------------------------------
    03022     //
    03024
    03025     //------------------------------------------
    03026     //------------------------------------------
    03027
    03029
    03039     explicit CImg(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1):
    03040       width(dx),height(dy),depth(dz),dim(dv) {
    03041       const unsigned int siz = size();
    03042       if (siz) data = new T[siz]; else { data=NULL; width=height=depth=dim=0; }
    03043     }
    03044
    03047
    03054     explicit CImg(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val):
    03055       width(dx),height(dy),depth(dz),dim(dv) {
    03056       const unsigned int siz = size();
    03057       if (siz) { data = new T[siz]; fill(val); } else { data=NULL; width=height=depth=dim=0; }
    03058     }
    03059
    03061
    03066     template<typename t> CImg(const CImg<t>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
    03067       const unsigned int siz = size();
    03068       if (siz) {
    03069         data = new T[siz];
    03070         const t *ptrs = img.data + siz;
    03071         cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs);
    03072       } else data = NULL;
    03073     }
    03074
    03075     CImg(const CImg<T>& img):width(img.width),height(img.height),depth(img.depth),dim(img.dim) {
    03076       const unsigned siz = size();
    03077       if (siz) {
    03078         data = new T[width*height*depth*dim];
    03079         std::memcpy(data,img.data,siz*sizeof(T));
    03080       } else data = NULL;
    03081     }
    03082
    03083
    03085
    03100     template<typename t> CImg(const CImg<t>& img,const bool pixel_copy):width(0),height(0),depth(0),dim(0),data(NULL) {
    03101       if (pixel_copy) CImg<T>(img).swap(*this);
    03102       CImg<T>(img.width,img.height,img.depth,img.dim).swap(*this);
    03103     }
    03104
    03106
    03112     CImg(const char *const filename):width(0),height(0),depth(0),dim(0),data(NULL) { load(filename).swap(*this); }
    03113
    03115
    03125     template<typename t> CImg(const t *const data_buffer,
    03126                               const unsigned int dx,const unsigned int dy=1,
    03127                               const unsigned int dz=1,const unsigned int dv=1,
    03128                               const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
    03129       const unsigned int siz = size();
    03130       if (data_buffer && siz) {
    03131         data = new T[siz];
    03132         if (multiplexed) {
    03133           const t *ptrs = data_buffer;
    03134           T *ptrd = data;
    03135           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
    03136         } else { const t *ptrs = data_buffer+siz; cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)); }
    03137       } else { width=height=depth=dim=0; data = NULL; }
    03138     }
    03139     // Add template overloading if VC>7.1 (optimized version)
    03140 #if !defined(_MSC_VER) && _MSC_VER>1300
    03141     CImg(const T *const data_buffer,
    03142          const unsigned int dx,const unsigned int dy=1,
    03143          const unsigned int dz=1,const unsigned int dv=1,
    03144          const bool multiplexed=false):width(dx),height(dy),depth(dz),dim(dv) {
    03145       const unsigned int siz = size();
    03146       if (data_buffer && siz) {
    03147         data = new T[siz];
    03148         if (multiplexed) {
    03149           const T *ptrs = data_buffer;
    03150           T *ptrd = data;
    03151           cimg_mapV(*this,k) { cimg_mapXYZ(*this,x,y,z) { *(ptrd++) = (T)(*(ptrs)); ptrs+=dim; } ptrs-=siz-1; }
    03152         } else std::memcpy(data,data_buffer,siz*sizeof(T));
    03153       } else { width=height=depth=dim=0; data = NULL; }
    03154     }
    03155 #endif
    03156
    03158
    03161     ~CImg() { if (data) delete[] data; }
    03162
    03164
    03170     CImg& empty() { return CImg<T>().swap(*this); }
    03171
    03173     //-----------------------------------------------------
    03174     //-----------------------------------------------------
    03175     //
    03177
    03178     //-----------------------------------------------------
    03179     //-----------------------------------------------------
    03180
    03182
    03188     static const char* pixel_type() { T val; return cimg::get_type(val); }
    03189
    03191
    03195     const unsigned int size() const { return width*height*depth*dim; }
    03196
    03198
    03205     const int dimx() const { return (int)width; }
    03206
    03208
    03215     const int dimy() const { return (int)height; }
    03216
    03218
    03224     const int dimz() const { return (int)depth; }
    03225
    03227
    03233     const int dimv() const { return (int)dim; }
    03234
    03236     // with respect to the pixel data pointer \ref data.
    03245     const int offset(const int x=0, const int y=0, const int z=0, const int v=0) const { return x+width*(y+height*(z+depth*v)); }
    03246
    03248
    03257     T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
    03258 #if cimg_debug>1
    03259       const int off = offset(x,y,z,v);
    03260       if (off<0 || off>=(int)size()) {
    03261         cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%d) which is"
    03262                    "outside the data of the image (%u,%u,%u,%u) (size=%u)",
    03263                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
    03264         return data;
    03265       }
    03266 #endif
    03267       return data+offset(x,y,z,v);
    03268     }
    03269
    03271
    03278     T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const {
    03279       const int off = offset(x,y,z,v);
    03280 #if cimg_debug>1
    03281       if (!data || off>=(int)size()) {
    03282         cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%d)"
    03283                    "outside the image range (%u,%u,%u,%u) (size=%u)",
    03284                    pixel_type(),x,y,z,v,offset(x,y,z,v),width,height,depth,dim,data,size());
    03285         return *data;
    03286       }
    03287 #endif
    03288       return data[off];
    03289     }
    03290
    03292
    03296     T& operator[](const unsigned int off) const {
    03297 #if cimg_debug>1
    03298       if (!data || off>=size()) {
    03299         cimg::warn(true,
    03300                    "CImg<%s>::operator[] : Trying to get a pixel at offset=%d, outside the range of the image (%u,%u,%u,%u) (size=%u)",
    03301                    pixel_type(),off,width,height,depth,dim,data,size());
    03302         return *data;
    03303       }
    03304 #endif
    03305       return data[off];
    03306     }
    03307
    03309
    03316     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 {
    03317       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
    03318     }
    03319
    03321
    03328     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 {
    03329       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
    03330     }
    03332
    03339     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 {
    03340       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
    03341     }
    03342
    03344
    03351     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 {
    03352       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
    03353     }
    03354
    03356
    03362     const T& neumann_pix4d(const int x,const int y=0,const int z=0,const int v=0) const {
    03363       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03364                      y<0?0:(y>=dimy()?dimy()-1:y),
    03365                      z<0?0:(z>=dimz()?dimz()-1:z),
    03366                      v<0?0:(v>=dimv()?dimv()-1:v));
    03367     }
    03369
    03375     const T& neumann_pix3d(const int x,const int y=0,const int z=0,const int v=0) const {
    03376       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03377                      y<0?0:(y>=dimy()?dimy()-1:y),
    03378                      z<0?0:(z>=dimz()?dimz()-1:z),v);
    03379     }
    03380
    03382
    03388     const T& neumann_pix2d(const int x,const int y=0,const int z=0,const int v=0) const {
    03389       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),
    03390                      y<0?0:(y>=dimy()?dimy()-1:y),z,v);
    03391     }
    03393
    03399     const T& neumann_pix1d(const int x,const int y=0,const int z=0,const int v=0) const {
    03400       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
    03401     }
    03402
    03404
    03410     double linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const {
    03411       double valx0,valx1,valy0,valy1,valz0,valz1;
    03412       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy),
    03413         fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv);
    03414       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy,  z = (unsigned int)fz, v = (unsigned int)fv;
    03415       const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
    03416       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;
    03417       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03418       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03419       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03420       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
    03421       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
    03422       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03423       valz0 = (1-dz)*valy0 + (dz)*valy1;
    03424       valx0 = (1-dx)*(*this)(x,y,z,nv)  + (dx)*(*this)(nx,y,z,nv);
    03425       valx1 = (1-dx)*(*this)(x,ny,z,nv) + (dx)*(*this)(nx,ny,z,nv);
    03426       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03427       valx0 = (1-dx)*(*this)(x,y,nz,nv)  + (dx)*(*this)(nx,y,nz,nv);
    03428       valx1 = (1-dx)*(*this)(x,ny,nz,nv) + (dx)*(*this)(nx,ny,nz,nv);
    03429       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03430       valz1 = (1-dz)*valy0 + (dz)*valy1;
    03431       return (1-dv)*valz0 + (dv)*valz1;
    03432     }
    03433
    03435
    03441     double linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const {
    03442       double valx0,valx1,valy0,valy1;
    03443       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);
    03444       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz;
    03445       const float dx = fx-x, dy = fy-y, dz = fz-z;
    03446       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z;
    03447       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03448       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03449       valy0 = (1-dy)*valx0 + (dy)*valx1;
    03450       valx0 = (1-dx)*(*this)(x,y,nz,v)  + (dx)*(*this)(nx,y,nz,v);
    03451       valx1 = (1-dx)*(*this)(x,ny,nz,v) + (dx)*(*this)(nx,ny,nz,v);
    03452       valy1 = (1-dy)*valx0 + (dy)*valx1;
    03453       return (1-dz)*valy0 + (dz)*valy1;
    03454     }
    03455
    03457
    03463     double linear_pix2d(const float ffx,const float ffy=0,const int z=0,int v=0) const {
    03464       double valx0,valx1;
    03465       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy);
    03466       const unsigned int x = (unsigned int)fx, y = (unsigned int)fy;
    03467       const float dx = fx-x, dy = fy-y;
    03468       const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y;
    03469       valx0 = (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03470       valx1 = (1-dx)*(*this)(x,ny,z,v) + (dx)*(*this)(nx,ny,z,v);
    03471       return (1-dy)*valx0 + (dy)*valx1;
    03472     }
    03473
    03475
    03481     double linear_pix1d(const float ffx,const int y=0,const int z=0,int v=0) const {
    03482       const float fx = ffx<0?0:(ffx>width-1?width-1:ffx);
    03483       const unsigned int x = (unsigned int)fx;
    03484       const float dx = fx-x;
    03485       const unsigned int nx = dx>0?x+1:x;
    03486       return (1-dx)*(*this)(x,y,z,v)  + (dx)*(*this)(nx,y,z,v);
    03487     }
    03488
    03490
    03496     double cubic_pix2d(const float pfx,const float pfy=0,const int z=0,int v=0) const {
    03497       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy);
    03498       const unsigned int
    03499         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,
    03500         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;
    03501       const float dx = fx-x, dy = fy-y;
    03502       const T&
    03503         a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v),
    03504         e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v),
    03505         i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v),
    03506         m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v);
    03507       const double
    03508         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,
    03509         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,
    03510         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,
    03511         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;
    03512       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;
    03513     }
    03514
    03516
    03522     double cubic_pix1d(const float pfx,const int y=0,const int z=0,int v=0) const {
    03523       const float fx = pfx<0?0:(pfx>width-1?width-1:pfx);
    03524       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;
    03525       const float dx = fx-x;
    03526       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);
    03527       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;
    03528     }
    03529
    03531
    03537     const CImg& print(const char *title=NULL,const unsigned int print_flag=1) const {
    03538       std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p",
    03539                    title?title:"CImg",(void*)this,
    03540                    width,height,depth,dim,pixel_type(),(void*)data);
    03541       if (size()==0 || !data) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; }
    03542       if (print_flag>=1) {
    03543         CImgStats st(*this);
    03544         std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)",
    03545                      st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax);
    03546       }
    03547       if (print_flag>=2 || size()<=16) {
    03548         std::fprintf(stderr," }, %s = [ ",title?title:"data");
    03549         cimg_mapXYZV(*this,x,y,z,k)
    03550           std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k),
    03551                        ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]":(((x+1)%width==0)?" ; ":" ")));
    03552       } else std::fprintf(stderr," }\n");
    03553       return *this;
    03554     }
    03555
    03557
    03562     const CImg& print(const unsigned int print_flag) const { return print(NULL,print_flag); }
    03563
    03565     //--------------------------------------------------
    03566     //--------------------------------------------------
    03567     //
    03569
    03570     //--------------------------------------------------
    03571     //--------------------------------------------------
    03572
    03574
    03578     template<typename t> CImg<T>& operator=(const CImg<t>& img) {
    03579       if (img.width!=width || img.height!=height || img.depth!=depth || img.dim!=dim) return CImg<T>(img).swap(*this);
    03580       t* ptrs = img.data + size();
    03581       cimg_map(*this,ptrd,T) *ptrd = (T)*(--ptrs);
    03582       return *this;
    03583     }
    03584
    03585     CImg& operator=(const CImg& img) {
    03586       if (&img==this) return *this;
    03587       if (img.width!=width || img.height!=height || img.depth!=depth || img.dim!=dim) return CImg<T>(img).swap(*this);
    03588       std::memcpy(data,img.data,sizeof(T)*size());
    03589       return *this;
    03590     }
    03591
    03593
    03596     CImg& operator=(const T& val) { return fill(val); }
    03597
    03599
    03602     CImg& operator=(const T *buf) {
    03603       if (buf) std::memcpy(data,buf,size()*sizeof(T));
    03604       else throw CImgArgumentException("CImg<T>::operator=() : Given array pointer 'ptr' is NULL");
    03605       return *this;
    03606     }
    03607
    03609
    03612     CImg& operator+=(const T& val) { cimg_map(*this,ptr,T) (*ptr)+=val; return *this; }
    03613
    03615
    03618     CImg& operator-=(const T& val) { cimg_map(*this,ptr,T) (*ptr)-=val; return *this; }
    03619
    03621
    03624     CImg& operator%=(const T& val) { cimg_map(*this,ptr,T) (*ptr)%=val; return *this; }
    03625
    03627
    03630     CImg& operator&=(const T& val) { cimg_map(*this,ptr,T) (*ptr)&=val; return *this; }
    03631
    03633     CImg& operator|=(const T& val) { cimg_map(*this,ptr,T) (*ptr)|=val; return *this; }
    03634
    03636     CImg& operator^=(const T& val) { cimg_map(*this,ptr,T) (*ptr)^=val; return *this; }
    03637
    03639     CImg operator+(const T& val) const { return CImg<T>(*this)+=val; }
    03640
    03642     CImg operator-(const T& val) const { return CImg<T>(*this)-=val; }
    03643
    03645     CImg operator%(const T& val) const { return CImg<T>(*this)%=val; }
    03646
    03648     CImg operator&(const T& val) const { return CImg<T>(*this)&=val; }
    03649
    03651     CImg operator|(const T& val) const { return CImg<T>(*this)|=val; }
    03652
    03654     CImg operator^(const T& val) const { return CImg<T>(*this)^=val; }
    03655
    03657     CImg operator!() const {
    03658       CImg<T> res(*this,false);
    03659       const T *ptrs = ptr() + size();
    03660       cimg_map(res,ptrd,T) *ptrd=!(*(--ptrs));
    03661       return res;
    03662     }
    03663
    03665     CImg operator~() const {
    03666       CImg<T> res(*this,false);
    03667       const T *ptrs = ptr() + size();
    03668       cimg_map(res,ptrd,T) *ptrd=~(*(--ptrs));
    03669       return res;
    03670     }
    03671
    03673     template<typename t> CImg& operator+=(const CImg<t>& img) {
    03674       const unsigned int smin = cimg::min(size(),img.size());
    03675       t *ptrs = img.data+smin;
    03676       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs))));
    03677       return *this;
    03678     }
    03680     template<typename t> CImg& operator-=(const CImg<t>& img) {
    03681       const unsigned int smin = cimg::min(size(),img.size());
    03682       t *ptrs = img.data+smin;
    03683       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs))));
    03684       return *this;
    03685     }
    03687     CImg& operator%=(const CImg& img) {
    03688       const unsigned int smin = cimg::min(size(),img.size());
    03689       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)%=*(--ptrs));
    03690       return *this;
    03691     }
    03693     CImg& operator&=(const CImg& img) {
    03694       const unsigned int smin = cimg::min(size(),img.size());
    03695       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)&=*(--ptrs));
    03696       return *this;
    03697     }
    03699     CImg& operator|=(const CImg& img) {
    03700       const unsigned int smin = cimg::min(size(),img.size());
    03701       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)|=*(--ptrs));
    03702       return *this;
    03703     }
    03705     CImg& operator^=(const CImg& img) {
    03706       const unsigned int smin = cimg::min(size(),img.size());
    03707       for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)^=*(--ptrs));
    03708       return *this;
    03709     }
    03710
    03712     template<typename t> CImg operator+(const CImg<t>& img)  const { return CImg<T>(*this)+=img; }
    03713
    03715     template<typename t> CImg operator-(const CImg<t>& img)  const { return CImg<T>(*this)-=img; }
    03716
    03718     CImg operator%(const CImg& img) const { return CImg<T>(*this)%=img; }
    03719
    03721     CImg operator&(const CImg& img) const { return CImg<T>(*this)&=img; }
    03722
    03724     CImg operator|(const CImg& img) const { return CImg<T>(*this)|=img; }
    03725
    03727     CImg operator^(const CImg& img) const { return CImg<T>(*this)^=img; }
    03728
    03730     CImg& operator*=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)*val); return *this; }
    03731
    03733     CImg& operator/=(const double val) { cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)/val); return *this; }
    03734
    03736     CImg operator*(const double val) const { return CImg<T>(*this)*=val; }
    03737
    03739     CImg operator/(const double val) const { return CImg<T>(*this)/=val; }
    03740
    03742     friend CImg operator+(const T& val, const CImg& img) { return CImg<T>(img)+=val; }
    03743
    03745     friend CImg operator*(const double val,const CImg &img) { return CImg<T>(img)*=val; }
    03746
    03748     friend CImg operator-(const T& val, const CImg& img) { return CImg<T>(img.width,img.height,img.depth,img.dim,val)-=img; }
    03749
    03751     template<typename t> const bool operator==(const CImg<t>& img) const {
    03752       const unsigned int siz = size();
    03753       bool vequal = true;
    03754       if (siz!=img.size()) return false;
    03755       t *ptrs=img.data+siz;
    03756       for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs))));
    03757       return vequal;
    03758     }
    03760     template<typename t> const bool operator!=(const CImg<t>& img) const { return !((*this)==img); }
    03761
    03763     //--------------------------------------------------
    03764     //--------------------------------------------------
    03765     //
    03767
    03768     //--------------------------------------------------
    03769     //--------------------------------------------------
    03770
    03772
    03776     template<typename t> CImg& mul(const CImg<t>& img) {
    03777       t *ptrs = img.data;
    03778       T *ptrf = data + cimg::min(size(),img.size());
    03779       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd*(*(ptrs++)));
    03780       return *this;
    03781     }
    03782
    03784
    03790     template<typename t> CImg get_mul(const CImg<t>& img) const { return CImg<T>(*this).mul(img); }
    03791
    03793
    03797     template<typename t> CImg& div(const CImg<t>& img) {
    03798       t *ptrs = img.data;
    03799       T *ptrf = data + cimg::min(size(),img.size());
    03800       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd/(*(ptrs++)));
    03801       return *this;
    03802     }
    03803
    03805
    03811     template<typename t> CImg get_div(const CImg<t>& img) const { return CImg<T>(*this).div(img); }
    03812
    03814
    03818     template<typename t> CImg& max(const CImg<t>& img) {
    03819       t *ptrs = img.data;
    03820       T *ptrf = data + cimg::min(size(),img.size());
    03821       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::max((T)(*(ptrs++)),*ptrd);
    03822       return *this;
    03823     }
    03825
    03829     template<typename t> CImg get_max(const CImg<t>& img) const { return CImg<T>(*this).max(img); }
    03830
    03832
    03836     template<typename t> CImg& min(const CImg<t>& img) {
    03837       t *ptrs = img.data;
    03838       T *ptrf = data + cimg::min(size(),img.size());
    03839       for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::min((T)(*(ptrs++)),*ptrd);
    03840       return *this;
    03841     }
    03843
    03847     template<typename t> CImg get_min(const CImg<t>& img) const { return CImg<T>(*this).min(img); }
    03848
    03850
    03853     CImg& sqrt() {
    03854       cimg_map(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr));
    03855       return *this;
    03856     }
    03857
    03859
    03862     CImg get_sqrt() const { return CImg<T>(*this).sqrt(); }
    03863
    03865
    03868     CImg& log() {
    03869       cimg_map(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr));
    03870       return *this;
    03871     }
    03872
    03874
    03877     CImg get_log() const { return CImg<T>(*this).log(); }
    03878
    03880
    03883     CImg& log10() {
    03884       cimg_map(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr));
    03885       return *this;
    03886     }
    03887
    03889
    03892     CImg get_log10() const { return CImg<T>(*this).log10(); }
    03893
    03895
    03899     CImg& pow(const double p) {
    03900       cimg_map(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p);
    03901       return *this;
    03902     }
    03903
    03905
    03909     CImg get_pow(const double p) const { return CImg<T>(*this).pow(p); }
    03910
    03912
    03915     CImg& abs() {
    03916       cimg_map(*this,ptr,T) (*ptr)=cimg::abs(*ptr);
    03917       return *this;
    03918     }
    03919
    03921
    03924     CImg get_abs() const { return CImg<T>(*this).abs(); }
    03925
    03927
    03930     CImg& cos() {
    03931       cimg_map(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr));
    03932       return *this;
    03933     }
    03934
    03936
    03939     CImg get_cos() const { return CImg<T>(*this).cos(); }
    03940
    03942
    03945     CImg& sin() {
    03946       cimg_map(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr));
    03947       return *this;
    03948     }
    03949
    03951
    03954     CImg get_sin() const { return CImg<T>(*this).sin(); }
    03955
    03957
    03960     CImg& tan() {
    03961       cimg_map(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr));
    03962       return *this;
    03963     }
    03964
    03966
    03969     CImg get_tan() const { return CImg<T>(*this).tan(); }
    03970
    03971
    03973     //------------------------------------------
    03974     //------------------------------------------
    03975     //
    03977
    03978     //------------------------------------------
    03979     //------------------------------------------
    03980
    03982
    03986     CImg& fill(const T& val) {
    03987       cimg_test(*this,"CImg<T>::fill");
    03988       if (val!=0 && sizeof(T)!=1) cimg_map(*this,ptr,T) *ptr=val;
    03989       else std::memset(data,(int)val,size()*sizeof(T));
    03990       return *this;
    03991     }
    03992
    03994
    03998     CImg& fill(const T& val0,const T& val1) {
    03999       cimg_test(*this,"CImg<T>::fill");
    04000       T *ptr, *ptr_end = data+size();
    04001       for (ptr=data; ptr<ptr_end-1; ) { *(ptr++)=val0; *(ptr++)=val1; }
    04002       if (ptr!=ptr_end) *(ptr++)=val0;
    04003       return *this;
    04004     }
    04005
    04007
    04012     CImg& fill(const T& val0,const T& val1,const T& val2) {
    04013       cimg_test(*this,"CImg<T>::fill");
    04014       T *ptr, *ptr_end = data+size();
    04015       for (ptr=data; ptr<ptr_end-2; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; }
    04016       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1;
    04017       return *this;
    04018     }
    04019
    04021
    04027     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3) {
    04028       cimg_test(*this,"CImg<T>::fill");
    04029       T *ptr, *ptr_end = data+size();
    04030       for (ptr=data; ptr<ptr_end-3; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; }
    04031       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04032       return *this;
    04033     }
    04034
    04036
    04043     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4) {
    04044       cimg_test(*this,"CImg<T>::fill");
    04045       T *ptr, *ptr_end = data+size();
    04046       for (ptr=data; ptr<ptr_end-4; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; }
    04047       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04048       if (ptr!=ptr_end) *(ptr++)=val3;
    04049       return *this;
    04050     }
    04051
    04053
    04061     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5) {
    04062       cimg_test(*this,"CImg<T>::fill");
    04063       T *ptr, *ptr_end = data+size();
    04064       for (ptr=data; ptr<ptr_end-5; ) {
    04065         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5;
    04066       }
    04067       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04068       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4;
    04069       return *this;
    04070     }
    04071
    04073
    04082     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
    04083                const T& val4,const T& val5,const T& val6) {
    04084       cimg_test(*this,"CImg<T>::fill");
    04085       T *ptr, *ptr_end = data+size();
    04086       for (ptr=data; ptr<ptr_end-6; ) {
    04087         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6;
    04088       }
    04089       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04090       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04091       return *this;
    04092     }
    04093
    04095
    04105     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
    04106                const T& val4,const T& val5,const T& val6,const T& val7) {
    04107       cimg_test(*this,"CImg<T>::fill");
    04108       T *ptr, *ptr_end = data+size();
    04109       for (ptr=data; ptr<ptr_end-7; ) {
    04110         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3;
    04111         *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7;
    04112       }
    04113       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04114       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04115       if (ptr!=ptr_end) *(ptr++)=val6;
    04116       return *this;
    04117     }
    04118
    04120
    04131     CImg& fill(const T& val0,const T& val1,const T& val2,
    04132                const T& val3,const T& val4,const T& val5,
    04133                const T& val6,const T& val7,const T& val8) {
    04134       cimg_test(*this,"CImg<T>::fill");
    04135       T *ptr, *ptr_end = data+size();
    04136       for (ptr=data; ptr<ptr_end-8; ) {
    04137         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2;
    04138         *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5;
    04139         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8;
    04140       }
    04141       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04142       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04143       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7;
    04144       return *this;
    04145     }
    04146
    04148
    04160     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,
    04161                const T& val5,const T& val6,const T& val7,const T& val8,const T& val9) {
    04162       cimg_test(*this,"CImg<T>::fill");
    04163       T *ptr, *ptr_end = data+size();
    04164       for (ptr=data; ptr<ptr_end-9; ) {
    04165         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4;
    04166         *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9;
    04167       }
    04168       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04169       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04170       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
    04171       return *this;
    04172     }
    04173
    04175
    04189     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
    04190                const T& val4,const T& val5,const T& val6,const T& val7,
    04191                const T& val8,const T& val9,const T& val10,const T& val11) {
    04192       cimg_test(*this,"CImg<T>::fill");
    04193       T *ptr, *ptr_end = data+size();
    04194       for (ptr=data; ptr<ptr_end-11; ) {
    04195         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5;
    04196         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
    04197       }
    04198       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04199       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04200       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
    04201       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10;
    04202       return *this;
    04203     }
    04205
    04223     CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,
    04224                const T& val4,const T& val5,const T& val6,const T& val7,
    04225                const T& val8,const T& val9,const T& val10,const T& val11,
    04226                const T& val12,const T& val13,const T& val14,const T& val15) {
    04227       cimg_test(*this,"CImg<T>::fill");
    04228       T *ptr, *ptr_end = data+size();
    04229       for (ptr=data; ptr<ptr_end-15; ) {
    04230         *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5;
    04231         *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11;
    04232         *(ptr++)=val12; *(ptr++)=val13; *(ptr++)=val14; *(ptr++)=val15;
    04233       }
    04234       if (ptr!=ptr_end) *(ptr++)=val0; if (ptr!=ptr_end) *(ptr++)=val1; if (ptr!=ptr_end) *(ptr++)=val2;
    04235       if (ptr!=ptr_end) *(ptr++)=val3; if (ptr!=ptr_end) *(ptr++)=val4; if (ptr!=ptr_end) *(ptr++)=val5;
    04236       if (ptr!=ptr_end) *(ptr++)=val6; if (ptr!=ptr_end) *(ptr++)=val7; if (ptr!=ptr_end) *(ptr++)=val8;
    04237       if (ptr!=ptr_end) *(ptr++)=val9; if (ptr!=ptr_end) *(ptr++)=val10; if (ptr!=ptr_end) *(ptr++)=val11;
    04238       if (ptr!=ptr_end) *(ptr++)=val12; if (ptr!=ptr_end) *(ptr++)=val13; if (ptr!=ptr_end) *(ptr++)=val14;
    04239       return *this;
    04240     }
    04241
    04243
    04248     CImg& normalize(const T& a,const T& b) {
    04249       cimg_test(*this,"CImg<T>::normalize");
    04250       const CImgStats st(*this,false);
    04251       if (st.min==st.max) fill(0);
    04252       else cimg_map(*this,ptr,T) *ptr=(T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a);
    04253       return *this;
    04254     }
    04255
    04257
    04262     CImg get_normalize(const T& a,const T& b) const { return CImg<T>(*this).normalize(a,b); }
    04263
    04265
    04270     CImg& cut(const T& a, const T& b) {
    04271       cimg_test(*this,"CImg<T>::cut");
    04272       cimg_map(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
    04273       return *this;
    04274     }
    04275
    04277
    04282     CImg get_cut(const T& a, const T& b) const { return CImg<T>(*this).cut(a,b); }
    04283
    04285
    04289     CImg& quantify(const unsigned int n=256) {
    04290       cimg_test(*this,"CImg<T>::quantify");
    04291       const CImgStats st(*this,false);
    04292       const double range = st.max-st.min;
    04293       cimg_map(*this,ptr,T) *ptr = (T)(st.min + range*(int)((*ptr-st.min)*(int)n/range)/n);
    04294       return *this;
    04295     }
    04296
    04298
    04302     CImg get_quantify(const unsigned int n=256) const { return CImg<T>(*this).quantify(n); }
    04303
    04305
    04309     CImg& threshold(const T& thres) {
    04310       cimg_test(*this,"CImg<T>::threshold");
    04311       cimg_map(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1;
    04312       return *this;
    04313     }
    04314
    04316
    04320     CImg get_threshold(const T& thres) const { return CImg<T>(*this).threshold(thres); }
    04321
    04323
    04332     CImg get_rotate(const float angle,const unsigned int cond=2) const {
    04333       cimg_test(*this,"CImg<T>::get_rotate");
    04334       CImg dest;
    04335       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
    04336         ca=(float)std::cos(rad), sa=(float)std::sin(rad);
    04337
    04338       if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
    04339         const int iangle = (int)nangle/90;
    04340         switch (iangle) {
    04341         case 1: {
    04342           dest = CImg<T>(height,width,depth,dim);
    04343           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,height-1-x,z,v);
    04344         } break;
    04345         case 2: {
    04346           dest = CImg<T>(width,height,depth,dim);
    04347           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
    04348         } break;
    04349         case 3: {
    04350           dest = CImg<T>(height,width,depth,dim);
    04351           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-y,x,z,v);
    04352         } break;
    04353         default:
    04354           return *this;
    04355         }
    04356       } else { // generic version
    04357         const float
    04358           ux  = (float)(std::fabs(width*ca)),  uy  = (float)(std::fabs(width*sa)),
    04359           vx  = (float)(std::fabs(height*sa)), vy  = (float)(std::fabs(height*ca)),
    04360           w2  = 0.5f*width,           h2  = 0.5f*height,
    04361           dw2 = 0.5f*(ux+vx),         dh2 = 0.5f*(uy+vy);
    04362         dest = CImg<T>((int)(ux+vx), (int)(uy+vy),depth,dim);
    04363
    04364         switch (cond) {
    04365         case 0: {
    04366           cimg_mapXY(dest,x,y)
    04367             cimg_mapZV(*this,z,v)
    04368             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);
    04369         } break;
    04370         case 1: {
    04371           cimg_mapXY(dest,x,y)
    04372             cimg_mapZV(*this,z,v)
    04373             dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width),
    04374                                     cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height),z,v);
    04375         } break;
    04376         default: {
    04377           cimg_mapXY(dest,x,y) {
    04378             const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
    04379             const int ix = (int)X, iy = (int)Y;
    04380             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
    04381             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
    04382           }
    04383         } break;
    04384         }
    04385       }
    04386       return dest;
    04387     }
    04388
    04390
    04398     CImg& rotate(const float angle,const unsigned int cond=2) { return get_rotate(angle,cond).swap(*this); }
    04399
    04401
    04412     CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) const {
    04413       cimg_test(*this,"CImg<T>::get_rotate");
    04414       CImg dest(*this,false);
    04415       const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
    04416         ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom;
    04417
    04418       if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
    04419         const int iangle = (int)nangle/90;
    04420         switch (iangle) {
    04421         case 1: {
    04422           dest.fill(0);
    04423           const unsigned int
    04424             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
    04425             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
    04426             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
    04427             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
    04428           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
    04429             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
    04430         } break;
    04431         case 2: {
    04432           cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
    04433         } break;
    04434         case 3: {
    04435           dest.fill(0);
    04436           const unsigned int
    04437             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
    04438             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
    04439             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
    04440             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
    04441           cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y<ymax; y++) for (unsigned int x=xmin; x<xmax; x++)
    04442             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
    04443         } break;
    04444         default:
    04445           return *this;
    04446         }
    04447       } else
    04448         switch (cond) { // generic version
    04449         case 0: {
    04450           cimg_mapXY(dest,x,y)
    04451             cimg_mapZV(*this,z,v)
    04452             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);
    04453         } break;
    04454         case 1: {
    04455           cimg_mapXY(dest,x,y)
    04456             cimg_mapZV(*this,z,v)
    04457             dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width),
    04458                                     cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height),z,v);
    04459         } break;
    04460         default: {
    04461           cimg_mapXY(dest,x,y) {
    04462             const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
    04463             const int ix = (int)X, iy = (int)Y;
    04464             if (ix<0 || ix>=dimx() || iy<0 || iy>=dimy()) cimg_mapZV(*this,z,v) dest(x,y,z,v) = 0;
    04465             else cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v);
    04466           }
    04467         } break;
    04468         }
    04469       return dest;
    04470     }
    04471
    04473
    04485     CImg& rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=2) {
    04486       return get_rotate(angle,cx,cy,zoom,cond).swap(*this);
    04487     }
    04488
    04490
    04504     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 {
    04505       cimg_test(*this,"CImg<T>::get_resize");
    04506       const unsigned int
    04507         dx = pdx<0?-pdx*width/100:pdx,
    04508         dy = pdy<0?-pdy*height/100:pdy,
    04509         dz = pdz<0?-pdz*depth/100:pdz,
    04510         dv = pdv<0?-pdv*dim/100:pdv;
    04511       CImg res(dx?dx:1,dy?dy:1,dz?dz:1,dv?dv:1);
    04512       if (width==res.width && height==res.height && depth==res.depth && dim==res.dim) return *this;
    04513       switch (interp) {
    04514       case 0: { // Zero filling
    04515         res.fill(0).draw_image(*this,0,0,0,0);
    04516       } break;
    04517       case 1: { // Bloc interpolation
    04518         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
    04519         float cx,cy,cz,ck=0;
    04520         cimg_mapV(res,k) { cz = 0;
    04521         cimg_mapZ(res,z) { cy = 0;
    04522         cimg_mapY(res,y) { cx = 0;
    04523         cimg_mapX(res,x) { res(x,y,z,k) = (*this)((unsigned int)cx,(unsigned int)cy,(unsigned int)cz,(unsigned int)ck); cx+=sx;
    04524         } cy+=sy;
    04525         } cz+=sz;
    04526         } ck+=sk;
    04527         }
    04528       } break;
    04529       case 2: { // Mosaic filling
    04530         for (unsigned int k=0; k<res.dim; k+=dim)
    04531           for (unsigned int z=0; z<res.depth; z+=depth)
    04532             for (unsigned int y=0; y<res.height; y+=height)
    04533               for (unsigned int x=0; x<res.width; x+=width) res.draw_image(*this,x,y,z,k);
    04534       } break;
    04535       case 3: { // Linear interpolation
    04536         const float
    04537           sx = res.width>1?(float)(width-1)/(res.width-1):0,
    04538           sy = res.height>1?(float)(height-1)/(res.height-1):0,
    04539           sz = res.depth>1?(float)(depth-1)/(res.depth-1):0,
    04540           sk = res.dim>1?(float)(dim-1)/(res.dim-1):0;
    04541         float cx,cy,cz,ck = 0;
    04542         cimg_mapV(res,k) { cz = 0;
    04543         cimg_mapZ(res,z) { cy = 0;
    04544         cimg_mapY(res,y) { cx = 0;
    04545         cimg_mapX(res,x) { res(x,y,z,k) = (T)linear_pix4d(cx,cy,cz,ck); cx+=sx;
    04546         } cy+=sy;
    04547         } cz+=sz;
    04548         } ck+=sk;
    04549         }
    04550       } break;
    04551       case 4: { // Grid filling
    04552         const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim;
    04553         res.fill(0);
    04554         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);
    04555       } break;
    04556       case 5: { // Cubic 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)cubic_pix2d(cx,cy,(int)cz,(int)ck); cx+=sx;
    04567         } cy+=sy;
    04568         } cz+=sz;
    04569         } ck+=sk;
    04570         }
    04571       } break;
    04572       }
    04573       return res;
    04574     }
    04575
    04577
    04588     template<typename t> CImg get_resize(const CImg<t>& src,const unsigned int interp=1) const {
    04589       return get_resize(src.width,src.height,src.depth,src.dim,interp);
    04590     }
    04591
    04593
    04604     CImg get_resize(const CImgDisplay& disp,const unsigned int interp=1) const {
    04605       return get_resize(disp.width,disp.height,depth,dim,interp);
    04606     }
    04607
    04609
    04623     CImg& resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) {
    04624       const unsigned int
    04625         dx = pdx<0?-pdx*width/100 :(pdx==0?1:pdx),
    04626         dy = pdy<0?-pdy*height/100:(pdy==0?1:pdy),
    04627         dz = pdz<0?-pdz*depth/100 :(pdz==0?1:pdz),
    04628         dv = pdv<0?-pdv*dim/100   :(pdv==0?1:pdv);
    04629       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
    04630       else return get_resize(dx,dy,dz,dv,interp).swap(*this);
    04631     }
    04632
    04634
    04645     template<typename t> CImg& resize(const CImg<t>& src,const unsigned int interp=1) {
    04646       return resize(src.width,src.height,src.depth,src.dim,interp);
    04647     }
    04648
    04650
    04661     CImg& resize(const CImgDisplay& disp,const unsigned int interp=1) {
    04662       return resize(disp.width,disp.height,depth,dim,interp);
    04663     }
    04664
    04666
    04669     CImg get_resize_halfXY() const {
    04670       cimg_test(*this,"CImg<T>::get_resize_halfXY");
    04671       CImg<float> mask = CImg<float>::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f,
    04672                                              0.1231940459f,  0.1935127547f, 0.1231940459f,
    04673                                              0.07842776544f, 0.1231940459f, 0.07842776544f);
    04674       CImg_3x3(I,float);
    04675       CImg dest(width/2,height/2,depth,dim);
    04676       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);
    04677       return dest;
    04678     }
    04679
    04681
    04684     CImg& resize_halfXY() {     return get_resize_halfXY().swap(*this); }
    04685
    04687
    04699     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
    04700                   const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
    04701                   const bool border_condition = false) const {
    04702       cimg_test(*this,"CImg<T>::get_crop");
    04703       const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1;
    04704       CImg dest(dx,dy,dz,dv);
    04705       if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth ||
    04706           v0>=dim || v1>=dim || x1<x0 || y1<y0 || z1<z0 || v1<v0)
    04707         switch (border_condition) {
    04708         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;
    04709         default: { cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = neumann_pix4d(x0+x,y0+y,z0+z,v0+v); } break;
    04710         } else {
    04711           T *psrc = ptr(x0,y0,z0,v0), *pdest = dest.ptr(0,0,0,0);
    04712           if (dx!=width)
    04713             for (unsigned int k=0; k<dv; k++) {
    04714               for (unsigned int z=0; z<dz; z++) {
    04715                 for (unsigned int y=0; y<dy; y++) {
    04716                   std::memcpy(pdest,psrc,dx*sizeof(T));
    04717                   pdest+=dx;
    04718                   psrc+=width;
    04719                 }
    04720                 psrc+=width*(height-dy);
    04721               }
    04722               psrc+=width*height*(depth-dz);
    04723             }
    04724           else {
    04725             if (dy!=height)
    04726               for (unsigned int k=0; k<dv; k++) {
    04727                 for (unsigned int z=0; z<dz; z++) {
    04728                   std::memcpy(pdest,psrc,dx*dy*sizeof(T));
    04729                   pdest+=dx*dy;
    04730                   psrc+=width*height;
    04731                 }
    04732                 psrc+=width*height*(depth-dz);
    04733               }
    04734             else {
    04735               if (dz!=depth)
    04736                 for (unsigned int k=0; k<dv; k++) {
    04737                   std::memcpy(pdest,psrc,dx*dy*dz*sizeof(T));
    04738                   pdest+=dx*dy*dz;
    04739                   psrc+=width*height*depth;
    04740                 }
    04741               else std::memcpy(pdest,psrc,dx*dy*dz*dv*sizeof(T));
    04742             }
    04743           }
    04744         }
    04745       return dest;
    04746     }
    04747
    04749
    04758     CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
    04759                   const unsigned int x1,const unsigned int y1,const unsigned int z1,
    04760                   const bool border_condition=false) const {
    04761       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
    04762     }
    04763
    04765
    04772     CImg get_crop(const unsigned int x0,const unsigned int y0,
    04773                   const unsigned int x1,const unsigned int y1,
    04774                   const bool border_condition=false) const {
    04775       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
    04776     }
    04777
    04779
    04784     CImg get_crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) const {
    04785       return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
    04786     }
    04787
    04789
    04800     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0,
    04801                const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1,
    04802                const bool border_condition=false) {
    04803       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).swap(*this);
    04804     }
    04805
    04807
    04816     CImg& crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,
    04817                const unsigned int x1,const unsigned int y1,const unsigned int z1,
    04818                const bool border_condition=false) {
    04819       return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
    04820     }
    04821
    04823
    04830     CImg& crop(const unsigned int x0,const unsigned int y0,
    04831                const unsigned int x1,const unsigned int y1,
    04832                const bool border_condition=false) {
    04833       return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
    04834     }
    04835
    04837
    04842     CImg& crop(const unsigned int x0,const unsigned int x1,const bool border_condition=false) {
    04843       return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
    04844     }
    04845
    04847
    04851     CImg get_channel(const unsigned int v0=0) const { return get_crop(0,0,0,v0,width-1,height-1,depth-1,v0); }
    04852
    04854
    04858     CImg get_slice(const unsigned int z0=0) const { return get_crop(0,0,z0,0,width-1,height-1,z0,dim-1); }
    04859
    04861
    04866     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); }
    04867
    04869     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 {
    04870       cimg_test(*this,"CImg<T>::ref_pointset");
    04871       if (xmax<xmin || xmax>=width || y0>=height || z0>=depth || v0>=dim)
    04872         throw CImgArgumentException("CImg<%s>::ref_pointset() : Cannot return a reference (%u->%u,%u,%u,%u) from a (%u,%u,%u,%u) image",
    04873                                     pixel_type(),xmin,xmax,y0,z0,v0,width,height,depth,dim);
    04874       return CImgROI<T>(1+xmax-xmin,1,1,1,ptr(xmin,y0,z0,v0));
    04875     }
    04876
    04878     CImgROI<T> ref_lineset(const unsigned int ymin,const unsigned int ymax,const unsigned int z0=0,const unsigned int v0=0) const {
    04879       cimg_test(*this,"CImg<T>::ref_lineset");
    04880       if (ymax<ymin || ymax>=height || z0>=depth || v0>=dim)
    04881         throw CImgArgumentException("CImg<%s>::ref_lineset() : Cannot return a reference (0->%u,%u->%u,%u,%u) from a (%u,%u,%u,%u) image",
    04882                                     pixel_type(),width-1,ymin,ymax,z0,v0,width,height,depth,dim);
    04883       return CImgROI<T>(width,1+ymax-ymin,1,1,ptr(0,ymin,z0,v0));
    04884     }
    04885
    04887     CImgROI<T> ref_planeset(const unsigned int zmin,const unsigned int zmax,const unsigned int v0=0) const {
    04888       cimg_test(*this,"CImg<T>::ref_planeset");
    04889       if(zmax<zmin || zmax>=depth || v0>=dim)
    04890         throw CImgArgumentException("CImg<%s>::ref_planeset() : Cannot return a reference (0->%u,0->%u,%u->%u,%u) from a (%u,%u,%u,%u) image",
    04891                                     pixel_type(),width-1,height-1,zmin,zmax,v0,width,height,depth,dim);
    04892       return CImgROI<T>(width,height,1+zmax-zmin,1,ptr(0,0,zmin,v0));
    04893     }
    04894
    04896     CImgROI<T> ref_channelset(const unsigned int vmin,const unsigned int vmax) const {
    04897       cimg_test(*this,"CImg<T>::ref_channelset");
    04898       if (vmax<vmin || vmax>=dim)
    04899         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",
    04900                                     pixel_type(),width-1,height-1,depth-1,vmin,vmax,width,height,depth,dim);
    04901       return CImgROI<T>(width,height,depth,1+vmax-vmin,ptr(0,0,0,vmin));
    04902     }
    04903
    04905     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); }
    04906
    04908     CImgROI<T> ref_plane(const unsigned int z0,const unsigned int v0=0) const { return ref_lineset(0,height-1,z0,v0); }
    04909
    04911     CImgROI<T> ref_channel(const unsigned int v0) const { return ref_planeset(0,depth-1,v0); }
    04912
    04914     CImg& channel(const unsigned int v0=0) { return get_channel(v0).swap(*this); }
    04915
    04917     CImg& slice(const unsigned int z0=0) { return get_slice(z0).swap(*this); }
    04918
    04920     CImg& plane(const unsigned int z0=0, const unsigned int v0=0) { return get_plane(z0,v0).swap(*this); }
    04921
    04923     CImg& flip(const char axe='x') {
    04924       cimg_test(*this,"CImg<T>::flip");
    04925       T *pf,*pb,*buf=NULL;
    04926       switch (cimg::uncase(axe)) {
    04927       case 'x': {
    04928         pf = ptr(); pb = ptr(width-1);
    04929         for (unsigned int yzv=0; yzv<height*depth*dim; yzv++) {
    04930           for (unsigned int x=0; x<width/2; x++) { const T val = *pf; *(pf++)=*pb; *(pb--)=val; }
    04931           pf+=width-width/2;
    04932           pb+=width+width/2;
    04933         }
    04934       } break;
    04935       case 'y': {
    04936         buf = new T[width];
    04937         pf = ptr(); pb = ptr(0,height-1);
    04938         for (unsigned int zv=0; zv<depth*dim; zv++) {
    04939           for (unsigned int y=0; y<height/2; y++) {
    04940             std::memcpy(buf,pf,width*sizeof(T));
    04941             std::memcpy(pf,pb,width*sizeof(T));
    04942             std::memcpy(pb,buf,width*sizeof(T));
    04943             pf+=width;
    04944             pb-=width;
    04945           }
    04946           pf+=width*(height-height/2);
    04947           pb+=width*(height+height/2);
    04948         }
    04949       } break;
    04950       case 'z': {
    04951         buf = new T[width*height];
    04952         pf = ptr(); pb = ptr(0,0,depth-1);
    04953         cimg_mapV(*this,v) {
    04954           for (unsigned int z=0; z<depth/2; z++) {
    04955             std::memcpy(buf,pf,width*height*sizeof(T));
    04956             std::memcpy(pf,pb,width*height*sizeof(T));
    04957             std::memcpy(pb,buf,width*height*sizeof(T));
    04958             pf+=width*height;
    04959             pb-=width*height;
    04960           }
    04961           pf+=width*height*(depth-depth/2);
    04962           pb+=width*height*(depth+depth/2);
    04963         }
    04964       } break;
    04965       case 'v': {
    04966         buf = new T[width*height*depth];
    04967         pf = ptr(); pb = ptr(0,0,0,dim-1);
    04968         for (unsigned int v=0; v<dim/2; v++) {
    04969           std::memcpy(buf,pf,width*height*depth*sizeof(T));
    04970           std::memcpy(pf,pb,width*height*depth*sizeof(T));
    04971           std::memcpy(pb,buf,width*height*depth*sizeof(T));
    04972           pf+=width*height*depth;
    04973           pb-=width*height*depth;
    04974         }
    04975       } break;
    04976       default:
    04977         throw CImgArgumentException("CImg<%s>::flip() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
    04978       }
    04979       if (buf) delete[] buf;
    04980       return *this;
    04981     }
    04982
    04984     CImg get_flip(const char axe='x') { return CImg<T>(*this).flip(axe); }
    04985
    04987     CImg& scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,const int border_condition=0) {
    04988       cimg_test(*this,"CImg<T>::scroll");
    04989
    04990       if (scrollx) // Scroll along X-axis
    04991         switch (border_condition) {
    04992         case 0:
    04993           if (cimg::abs(scrollx)>=(int)width) return fill(0);
    04994           if (scrollx>0) cimg_mapYZV(*this,y,z,k) {
    04995             std::memmove(ptr(0,y,z,k),ptr(scrollx,y,z,k),(width-scrollx)*sizeof(T));
    04996             std::memset(ptr(width-scrollx,y,z,k),0,scrollx*sizeof(T));
    04997           } else cimg_mapYZV(*this,y,z,k) {
    04998             std::memmove(ptr(-scrollx,y,z,k),ptr(0,y,z,k),(width+scrollx)*sizeof(T));
    04999             std::memset(ptr(0,y,z,k),0,-scrollx*sizeof(T));
    05000           }
    05001           break;
    05002         case 1:
    05003           if (scrollx>0) {
    05004             const int nscrollx = (scrollx>=(int)width)?width-1:scrollx;
    05005             if (!nscrollx) return *this;
    05006             cimg_mapYZV(*this,y,z,k) {
    05007               std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
    05008               T *ptrd = ptr(width-1,y,z,k);
    05009               const T &val = *ptrd;
    05010               for (int l=0; l<nscrollx-1; l++) *(--ptrd) = val;
    05011             }
    05012           } else {
    05013             const int nscrollx = (-scrollx>=(int)width)?width-1:-scrollx;
    05014             if (!nscrollx) return *this;
    05015             cimg_mapYZV(*this,y,z,k) {
    05016               std::memmove(ptr(nscrollx,y,z,k),ptr(0,y,z,k),(width-nscrollx)*sizeof(T));
    05017               T *ptrd = ptr(0,y,z,k);
    05018               const T &val = *ptrd;
    05019               for (int l=0; l<nscrollx-1; l++) *(++ptrd) = val;
    05020             }
    05021           }
    05022           break;
    05023         case 2: {
    05024           const int ml = cimg::mod(scrollx,width), nscrollx = (ml<=(int)width/2)?ml:(ml-(int)width);
    05025           if (!nscrollx) return *this;
    05026           T* buf = new T[cimg::abs(nscrollx)];
    05027           if (nscrollx>0) cimg_mapYZV(*this,y,z,k) {
    05028             std::memcpy(buf,ptr(0,y,z,k),nscrollx*sizeof(T));
    05029             std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T));
    05030             std::memcpy(ptr(width-nscrollx,y,z,k),buf,nscrollx*sizeof(T));
    05031           } else cimg_mapYZV(*this,y,z,k) {
    05032             std::memcpy(buf,ptr(width+nscrollx,y,z,k),-nscrollx*sizeof(T));
    05033             std::memmove(ptr(-nscrollx,y,z,k),ptr(0,y,z,k),(width+nscrollx)*sizeof(T));
    05034             std::memcpy(ptr(0,y,z,k),buf,-nscrollx*sizeof(T));
    05035           }
    05036           delete[] buf;
    05037         } break;
    05038         }
    05039
    05040       if (scrolly) // Scroll along Y-axis
    05041         switch (border_condition) {
    05042         case 0:
    05043           if (cimg::abs(scrolly)>=(int)height) return fill(0);
    05044           if (scrolly>0) cimg_mapZV(*this,z,k) {
    05045             std::memmove(ptr(0,0,z,k),ptr(0,scrolly,z,k),width*(height-scrolly)*sizeof(T));
    05046             std::memset(ptr(0,height-scrolly,z,k),0,width*scrolly*sizeof(T));
    05047           } else cimg_mapZV(*this,z,k) {
    05048             std::memmove(ptr(0,-scrolly,z,k),ptr(0,0,z,k),width*(height+scrolly)*sizeof(T));
    05049             std::memset(ptr(0,0,z,k),0,-scrolly*width*sizeof(T));
    05050           }
    05051           break;
    05052         case 1:
    05053           if (scrolly>0) {
    05054             const int nscrolly = (scrolly>=(int)height)?height-1:scrolly;
    05055             if (!nscrolly) return *this;
    05056             cimg_mapZV(*this,z,k) {
    05057               std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
    05058               T *ptrd = ptr(0,height-nscrolly,z,k), *ptrs = ptr(0,height-1,z,k);
    05059               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
    05060             }
    05061           } else {
    05062             const int nscrolly = (-scrolly>=(int)height)?height-1:-scrolly;
    05063             if (!nscrolly) return *this;
    05064             cimg_mapZV(*this,z,k) {
    05065               std::memmove(ptr(0,nscrolly,z,k),ptr(0,0,z,k),width*(height-nscrolly)*sizeof(T));
    05066               T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
    05067               for (int l=0; l<nscrolly-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
    05068             }
    05069           }
    05070           break;
    05071         case 2: {
    05072           const int ml = cimg::mod(scrolly,height), nscrolly = (ml<=(int)height/2)?ml:(ml-(int)height);
    05073           if (!nscrolly) return *this;
    05074           T* buf = new T[width*cimg::abs(nscrolly)];
    05075           if (nscrolly>0) cimg_mapZV(*this,z,k) {
    05076             std::memcpy(buf,ptr(0,0,z,k),width*nscrolly*sizeof(T));
    05077             std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T));
    05078             std::memcpy(ptr(0,height-nscrolly,z,k),buf,width*nscrolly*sizeof(T));
    05079           } else cimg_mapZV(*this,z,k) {
    05080             std::memcpy(buf,ptr(0,height+nscrolly,z,k),-nscrolly*width*sizeof(T));
    05081             std::memmove(ptr(0,-nscrolly,z,k),ptr(0,0,z,k),width*(height+nscrolly)*sizeof(T));
    05082             std::memcpy(ptr(0,0,z,k),buf,-nscrolly*width*sizeof(T));
    05083           }
    05084           delete[] buf;
    05085         } break;
    05086         }
    05087
    05088       if (scrollz) // Scroll along Z-axis
    05089         switch (border_condition) {
    05090         case 0:
    05091           if (cimg::abs(scrollz)>=(int)depth) return fill(0);
    05092           if (scrollz>0) cimg_mapV(*this,k) {
    05093             std::memmove(ptr(0,0,0,k),ptr(0,0,scrollz,k),width*height*(depth-scrollz)*sizeof(T));
    05094             std::memset(ptr(0,0,depth-scrollz,k),0,width*height*scrollz*sizeof(T));
    05095           } else cimg_mapV(*this,k) {
    05096             std::memmove(ptr(0,0,-scrollz,k),ptr(0,0,0,k),width*height*(depth+scrollz)*sizeof(T));
    05097             std::memset(ptr(0,0,0,k),0,-scrollz*width*height*sizeof(T));
    05098           }
    05099           break;
    05100         case 1:
    05101           if (scrollz>0) {
    05102             const int nscrollz = (scrollz>=(int)depth)?depth-1:scrollz;
    05103             if (!nscrollz) return *this;
    05104             cimg_mapV(*this,k) {
    05105               std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
    05106               T *ptrd = ptr(0,0,depth-nscrollz,k), *ptrs = ptr(0,0,depth-1,k);
    05107               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
    05108             }
    05109           } else {
    05110             const int nscrollz = (-scrollz>=(int)depth)?depth-1:-scrollz;
    05111             if (!nscrollz) return *this;
    05112             cimg_mapV(*this,k) {
    05113               std::memmove(ptr(0,0,nscrollz,k),ptr(0,0,0,k),width*height*(depth-nscrollz)*sizeof(T));
    05114               T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
    05115               for (int l=0; l<nscrollz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
    05116             }
    05117           }
    05118           break;
    05119         case 2: {
    05120           const int ml = cimg::mod(scrollz,depth), nscrollz = (ml<=(int)depth/2)?ml:(ml-(int)depth);
    05121           if (!nscrollz) return *this;
    05122           T* buf = new T[width*height*cimg::abs(nscrollz)];
    05123           if (nscrollz>0) cimg_mapV(*this,k) {
    05124             std::memcpy(buf,ptr(0,0,0,k),width*height*nscrollz*sizeof(T));
    05125             std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T));
    05126             std::memcpy(ptr(0,0,depth-nscrollz,k),buf,width*height*nscrollz*sizeof(T));
    05127           } else cimg_mapV(*this,k) {
    05128             std::memcpy(buf,ptr(0,0,depth+nscrollz,k),-nscrollz*width*height*sizeof(T));
    05129             std::memmove(ptr(0,0,-nscrollz,k),ptr(0,0,0,k),width*height*(depth+nscrollz)*sizeof(T));
    05130             std::memcpy(ptr(0,0,0,k),buf,-nscrollz*width*height*sizeof(T));
    05131           }
    05132           delete[] buf;
    05133         } break;
    05134         }
    05135
    05136       if (scrollv) // Scroll along V-axis
    05137         switch (border_condition) {
    05138         case 0:
    05139           if (cimg::abs(scrollv)>=(int)dim) return fill(0);
    05140           if (scrollv>0) {
    05141             std::memmove(data,ptr(0,0,0,scrollv),width*height*depth*(dim-scrollv)*sizeof(T));
    05142             std::memset(ptr(0,0,0,dim-scrollv),0,width*height*depth*scrollv*sizeof(T));
    05143           } else cimg_mapV(*this,k) {
    05144             std::memmove(ptr(0,0,0,-scrollv),data,width*height*depth*(dim+scrollv)*sizeof(T));
    05145             std::memset(data,0,-scrollv*width*height*depth*sizeof(T));
    05146           }
    05147           break;
    05148         case 1:
    05149           if (scrollv>0) {
    05150             const int nscrollv = (scrollv>=(int)dim)?dim-1:scrollv;
    05151             if (!nscrollv) return *this;
    05152             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
    05153             T *ptrd = ptr(0,0,0,dim-nscrollv), *ptrs = ptr(0,0,0,dim-1);
    05154             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
    05155           } else {
    05156             const int nscrollv = (-scrollv>=(int)dim)?dim-1:-scrollv;
    05157             if (!nscrollv) return *this;
    05158             std::memmove(ptr(0,0,0,nscrollv),data,width*height*depth*(dim-nscrollv)*sizeof(T));
    05159             T *ptrd = ptr(0,0,0,1);
    05160             for (int l=0; l<nscrollv-1; l++) { std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
    05161           }
    05162           break;
    05163         case 2: {
    05164           const int ml = cimg::mod(scrollv,dim), nscrollv = (ml<=(int)dim/2)?ml:(ml-(int)dim);
    05165           if (!nscrollv) return *this;
    05166           T* buf = new T[width*height*depth*cimg::abs(nscrollv)];
    05167           if (nscrollv>0) {
    05168             std::memcpy(buf,data,width*height*depth*nscrollv*sizeof(T));
    05169             std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T));
    05170             std::memcpy(ptr(0,0,0,dim-nscrollv),buf,width*height*depth*nscrollv*sizeof(T));
    05171           } else {
    05172             std::memcpy(buf,ptr(0,0,0,dim+nscrollv),-nscrollv*width*height*depth*sizeof(T));
    05173             std::memmove(ptr(0,0,0,-nscrollv),data,width*height*depth*(dim+nscrollv)*sizeof(T));
    05174             std::memcpy(data,buf,-nscrollv*width*height*depth*sizeof(T));
    05175           }
    05176           delete[] buf;
    05177         } break;
    05178         }
    05179
    05180       return *this;
    05181     }
    05182
    05184     CImg get_scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,
    05185                     const int border_condition=0) const {
    05186       return CImg<T>(*this).scroll(scrollx,scrolly,scrollz,scrollv,border_condition);
    05187     }
    05188
    05190     CImg get_3dplanes(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const {
    05191       cimg_test(*this,"CImg<T>::get_3dplanes");
    05192       const unsigned int
    05193         x0=(px0>=width)?width-1:px0,
    05194         y0=(py0>=height)?height-1:py0,
    05195         z0=(pz0>=depth)?depth-1:pz0;
    05196       CImg res(width+depth,height+depth,1,dim);
    05197       res.fill((*this)[0]);
    05198       { cimg_mapXYV(*this,x,y,k) res(x,y,0,k)        = (*this)(x,y,z0,k); }
    05199       { cimg_mapYZV(*this,y,z,k) res(width+z,y,0,k)  = (*this)(x0,y,z,k); }
    05200       { cimg_mapXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); }
    05201       return res;
    05202     }
    05203
    05205     CImg<float> get_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const {
    05206       cimg_test(*this,"CImg<T>::get_histogram");
    05207       if (nblevels<1) {
    05208         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %u levels",
    05209                                     pixel_type(),nblevels);
    05210       }
    05211       T vmin=val_min,vmax=val_max;
    05212       CImg<float> res(nblevels,1,1,1,0);
    05213       if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
    05214       cimg_map(*this,ptr,T) { const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); if (pos>=0 && pos<(int)nblevels) res[pos]++; }
    05215       return res;
    05216     }
    05217
    05219     CImg& equalize_histogram(const unsigned int nblevels=256) {
    05220       cimg_test(*this,"CImg<T>::equalize_histogram");
    05221       CImgStats st(*this,false);
    05222       CImg<float> hist = get_histogram(nblevels,(T)st.min,(T)st.max);
    05223       float cumul=0;
    05224       cimg_mapX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
    05225       cimg_map(*this,ptr,T) {
    05226         unsigned int pos = (unsigned int)((*ptr-st.min)*nblevels/(1+st.max-st.min));
    05227         *ptr = (T)(st.min + (st.max-st.min)*hist[pos]/size());
    05228       }
    05229       return *this;
    05230     }
    05232     CImg get_equalize_histogram(const unsigned int nblevels=256) const { return CImg<T>(*this).equalize_histogram(nblevels); }
    05233
    05235     CImg<float> get_norm_pointwise(int ntype=2) const {
    05236       cimg_test(*this,"CImg<T>::get_norm_pointwise");
    05237       CImg<float> res(width,height,depth);
    05238       switch(ntype) {
    05239       case -1:                // Linf norm
    05240         {
    05241           cimg_mapXYZ(*this,x,y,z) {
    05242             float n=0; cimg_mapV(*this,v) if (std::fabs((double)((*this)(x,y,z,v)))>n) n=(float)(*this)(x,y,z,v); res(x,y,z) = n;
    05243           }
    05244         } break;
    05245       case 1:               // L1 norm
    05246         {
    05247           cimg_mapXYZ(*this,x,y,z) {
    05248             float n=0; cimg_mapV(*this,v) n+=(float)std::fabs((double)((*this)(x,y,z,v))); res(x,y,z) = n;
    05249           }
    05250         } break;
    05251       default:              // L2 norm
    05252         {
    05253           cimg_mapXYZ(*this,x,y,z) {
    05254             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);
    05255           }
    05256         } break;
    05257       }
    05258       return res;
    05259     }
    05260
    05262     CImg& norm_pointwise() { return CImg<T>(get_norm_pointwise()).swap(*this); }
    05263
    05265     CImg get_orientation_pointwise() const {
    05266       cimg_test(*this,"CImg<T>::get_orientation_pointwise");
    05267       CImg dest(width,height,depth,dim);
    05268       cimg_mapXYZ(dest,x,y,z) {
    05269         float n = 0;
    05270         cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
    05271         n = (float)std::sqrt((double)n);
    05272         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;
    05273       }
    05274       return dest;
    05275     }
    05276
    05278     CImg& orientation_pointwise() { return get_orientation_pointwise().swap(*this); }
    05279
    05281
    05284     CImgl<T> get_split(const char axe,const unsigned int nb=0) const {
    05285       cimg_test(*this,"CImg<T>::get_split");
    05286       CImgl<T> res;
    05287       switch (cimg::uncase(axe)) {
    05288       case 'x': {
    05289         res = CImgl<T>(nb?nb:width);
    05290         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);
    05291         } break;
    05292       case 'y': {
    05293         res = CImgl<T>(nb?nb:height);
    05294         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);
    05295         } break;
    05296       case 'z': {
    05297         res = CImgl<T>(nb?nb:depth);
    05298         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);
    05299         } break;
    05300       case 'v': {
    05301         res = CImgl<T>(nb?nb:dim);
    05302         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);
    05303         } break;
    05304       default:
    05305         throw CImgArgumentException("CImg<%s>::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
    05306         break;
    05307       }
    05308       return res;
    05309     }
    05310
    05312
    05322     CImgl<T> get_gradientXY(const int scheme=0,const float alpha=0) const {
    05323       cimg_test(*this,"CImg<T>::get_gradientXY");
    05324       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
    05325       CImgl<T> res(2,width,height,depth,dim);
    05326       CImg_3x3(I,T);
    05327       switch(scheme) {
    05328       case -1: { // backward finite differences
    05329         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; }
    05330       } break;
    05331       case 1: { // forward finite differences
    05332         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; }
    05333       } break;
    05334       case 2: { // using Sobel mask
    05335         const float a = 1, b = 2;
    05336         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05337           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
    05338           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
    05339         }
    05340       } break;
    05341       case 3: { // using rotation invariant mask
    05342         const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1));
    05343         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05344           res[0](x,y,z,k) = (T)(-a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn);
    05345           res[1](x,y,z,k) = (T)(-a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn);
    05346         }
    05347       } break;
    05348       case 4: { // using Deriche filter with low variance
    05349         res[0] = get_deriche(alpha,1,'x');
    05350         res[1] = get_deriche(alpha,1,'y');
    05351       } break;
    05352       default: { // central finite differences
    05353         cimg_mapZV(*this,z,k) cimg_map3x3(*this,x,y,z,k,I) {
    05354           res[0](x,y,z,k) = (T)(0.5*(Inc-Ipc));
    05355           res[1](x,y,z,k) = (T)(0.5*(Icn-Icp));
    05356         }
    05357       } break;
    05358       }
    05359       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
    05360       return res;
    05361     }
    05362
    05364
    05367     CImgl<T> get_gradientXYZ(const int scheme=0,const float alpha=0) const {
    05368       cimg_test(*this,"CImg<T>::get_gradientXYZ");
    05369       if (alpha<0) throw CImgArgumentException("CImg<%s>::get_gradientXYZ() : Given blur parameter %g is negative",pixel_type(),alpha);
    05370       CImgl<T> res(3,width,height,depth,dim);
    05371       CImg_3x3x3(I,T);
    05372       switch(scheme) {
    05373       case -1: { // backward finite differences
    05374         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05375           res[0](x,y,z,k) = Iccc-Ipcc;
    05376           res[1](x,y,z,k) = Iccc-Icpc;
    05377           res[2](x,y,z,k) = Iccc-Iccp;
    05378         }
    05379       } break;
    05380       case 1: { // forward finite differences
    05381         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05382           res[0](x,y,z,k) = Incc-Iccc;
    05383           res[1](x,y,z,k) = Icnc-Iccc;
    05384           res[2](x,y,z,k) = Iccn-Iccc;
    05385         }
    05386       } break;
    05387       case 4: { // using Deriche filter with low variance
    05388         res[0] = get_deriche(alpha,1,'x');
    05389         res[1] = get_deriche(alpha,1,'y');
    05390         res[2] = get_deriche(alpha,1,'z');
    05391       } break;
    05392       default: { // central finite differences
    05393         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) {
    05394           res[0](x,y,z,k) = (T)(0.5*(Incc-Ipcc));
    05395           res[1](x,y,z,k) = (T)(0.5*(Icnc-Icpc));
    05396           res[2](x,y,z,k) = (T)(0.5*(Iccn-Iccp));
    05397         }
    05398       } break;
    05399       }
    05400       if (scheme!=4 && alpha>0) cimgl_map(res,l) res[l].blur(alpha);
    05401       return res;
    05402     }
    05403
    05405     //--------------------------------------
    05406     //--------------------------------------
    05407     //
    05409
    05410     //--------------------------------------
    05411     //--------------------------------------
    05412
    05414     CImg& RGBtoXYZ() {
    05415       cimg_test(*this,"CImg<T>::RGBtoXYZ");
    05416       if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, should be a (R,G,B) image (dim=3)",
    05417                                               pixel_type(),dim);
    05418       cimg_mapXYZ(*this,x,y,z) {
    05419         const T R = (*this)(x,y,z,0), G = (*this)(x,y,z,1), B = (*this)(x,y,z,2);
    05420         (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B);
    05421         (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B);
    05422         (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B);
    05423       }
    05424       return *this;
    05425     }
    05427     CImg get_RGBtoXYZ() const { return CImg<T>(*this).RGBtoXYZ(); }
    05428
    05430     CImg& XYZtoRGB() {
    05431       cimg_test(*this,"CImg<T>::XYZtoRGB");
    05432       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, should be a (X,Y,Z) image (dim=3)",
    05433                                               pixel_type(),dim);
    05434       cimg_mapXYZ(*this,x,y,z) {
    05435         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
    05436         (*this)(x,y,z,0) = (T)(3.240479*X  - 1.537150*Y - 0.498535*Z);
    05437         (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z);
    05438         (*this)(x,y,z,2) = (T)(0.055648*X  - 0.204043*Y + 1.057311*Z);
    05439       }
    05440       return *this;
    05441     }
    05443     CImg get_XYZtoRGB() const { return CImg<T>(*this).XYZtoRGB(); }
    05444
    05446     CImg& XYZtoLab() {
    05447       cimg_test(*this,"CImg<T>::XYZtoLab");
    05448       if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, should be a (X,Y,Z) image (dim=3)",
    05449                                               pixel_type(),dim);
    05450       CImg<double> white = CImg<double>(1,1,1,3,1).RGBtoXYZ();
    05451       const double Xn = white(0), Yn = white(1), Zn = white(2);
    05452
    05453       cimg_mapXYZ(*this,x,y,z) {
    05454         const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
    05455         const double L = (T)(116*std::pow(Y/Yn,1/3.0)-16);
    05456         (*this)(x,y,z,0) = (T)(L>=0?L:0);
    05457         (*this)(x,y,z,1) = (T)(500*(std::pow(X/Xn,1/3.0)-std::pow(Y/Yn,1/3.0)));
    05458         (*this)(x,y,z,2) = (T)(200*(std::pow(Y/Yn,1/3.0)-std::pow(Z/Zn,1/3.0)));
    05459       }
    05460       return *this;
    05461     }
    05463     CImg get_XYZtoLab() const { return CImg<T>(*this).XYZtoLab(); }
    05464
    05465     CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); }
    05466     CImg get_RGBtoLab() { return CImg<T>(*this).RGBtoLab(); }
    05467
    05469     //--------------------------------------
    05470     //--------------------------------------
    05471     //
    05473
    05474     //--------------------------------------
    05475     //--------------------------------------
    05476
    05477     // Should be used only by member functions. Not an user-friendly function.
    05478     void draw_scanline(const int x0,const int x1,const int y,const T *col,const float opacity=1) {
    05479       const int nx0 = cimg::max(x0,0), nx1 = cimg::min(x1,dimx()-1), dx = nx1-nx0+1;
    05480       if (dx>0) {
    05481         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05482         const unsigned int whz = width*height*depth;
    05483         if (opacity>=1) cimg_mapV(*this,k) {
    05484           T *ptrd = ptr(nx0,y,0,k);
    05485           const T& val = *(col++);
    05486           if (sizeof(T)!=1) { for (int x=nx0; x<=nx1; x++) *(ptrd++)=val; ptrd-=whz; }
    05487           else std::memset(ptrd,(int)val,dx);
    05488         } else cimg_mapV(*this,k) {
    05489           T *ptrd = ptr(nx0,y,0,k);
    05490           const T& val = *(col++);
    05491           for (int x=nx0; x<=nx1; x++) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ptrd++; }
    05492           ptrd-=whz;
    05493         }
    05494       }
    05495     }
    05496
    05498
    05506     CImg& draw_point(const int x0,const int y0,const int z0,
    05507                      const T *const color,const float opacity=1) {
    05508       cimg_test(*this,"CImg<T>::draw_point");
    05509       if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : specified color is (null)",pixel_type());
    05510       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
    05511         const T *col=color;
    05512         const unsigned int whz = width*height*depth;
    05513         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05514         T *ptrd = ptr(x0,y0,z0,0);
    05515         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
    05516         else cimg_mapV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
    05517       }
    05518       return *this;
    05519     }
    05520
    05522
    05529     CImg& draw_point(const int x0,const int y0,const T *const color,const float opacity=1) {
    05530       return draw_point(x0,y0,0,color,opacity);
    05531     }
    05532
    05534
    05544     CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
    05545                     const T *const color,const unsigned long pattern=~0L,const float opacity=1) {
    05546       cimg_test(*this,"CImg<T>::draw_line");
    05547       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
    05548       const T* col=color;
    05549       unsigned long hatch=1;
    05550       int nx0=x0, nx1=x1, ny0=y0, ny1=y1;
    05551       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1);
    05552       if (nx1<0 || nx0>=dimx()) return *this;
    05553       if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; }
    05554       if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;}
    05555       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
    05556       if (ny1<0 || ny0>=dimy()) return *this;
    05557       if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; }
    05558       if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;}
    05559       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),ny1-ny0), whz = width*height*depth;
    05560       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0;
    05561       float x = (float)nx0, y = (float)ny0;
    05562       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
    05563         if (!(~pattern) || (~pattern && pattern&hatch)) {
    05564           T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05565           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
    05566           col-=dim;
    05567         }
    05568         x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05569       } else {
    05570         const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f);
    05571         for (unsigned int t=0; t<=dmax; t++) {
    05572           if (!(~pattern) || (~pattern && pattern&hatch)) {
    05573             T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05574             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
    05575             col-=dim;
    05576           }
    05577           x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05578         }
    05579       }
    05580       return *this;
    05581     }
    05582
    05584
    05596     CImg& draw_line(const int x0,const int y0,const int z0,const int x1,const int y1,const int z1,
    05597                     const T *const color,const unsigned long pattern=~0L,const float opacity=1) {
    05598       cimg_test(*this,"CImg<T>::draw_line");
    05599       if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : specified color is (null)",pixel_type());
    05600       const T* col=color;
    05601       unsigned long hatch=1;
    05602       int nx0=x0, ny0=y0, nz0=z0, nx1=x1, ny1=y1, nz1=z1;
    05603       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05604       if (nx1<0 || nx0>=dimx()) return *this;
    05605       if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; nz0-=nx0*(nz1-nz0)/D; nx0=0; }
    05606       if (nx1>=dimx()) { const int d=nx1-dimx(), D=nx1-nx0; ny1+=d*(ny0-ny1)/D; nz1+=d*(nz0-nz1)/D; nx1=dimx()-1;}
    05607       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05608       if (ny1<0 || ny0>=dimy()) return *this;
    05609       if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; nz0-=ny0*(nz1-nz0)/D; ny0=0; }
    05610       if (ny1>=dimy()) { const int d=ny1-dimy(), D=ny1-ny0; nx1+=d*(nx0-nx1)/D; nz1+=d*(nz0-nz1)/D; ny1=dimy()-1;}
    05611       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
    05612       if (nz1<0 || nz0>=dimz()) return *this;
    05613       if (nz0<0) { const int D=nz1-nz0; nx0-=nz0*(nx1-nx0)/D; ny0-=nz0*(ny1-ny0)/D; nz0=0; }
    05614       if (nz1>=dimz()) { const int d=nz1-dimz(), D=nz1-nz0; nx1+=d*(nx0-nx1)/D; ny1+=d*(ny0-ny1)/D; nz1=dimz()-1;}
    05615       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),std::abs(ny1-ny0),nz1-nz0), whz = width*height*depth;
    05616       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, pz = dmax?(nz1-nz0)/(float)dmax:0;
    05617       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
    05618       if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) {
    05619         if (!(~pattern) || (~pattern && pattern&hatch)) {
    05620           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
    05621           cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; }
    05622           col-=dim;
    05623         }
    05624         x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05625       } else {
    05626         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05627         for (unsigned int t=0; t<=dmax; t++) {
    05628           if (!(~pattern) || (~pattern && pattern&hatch)) {
    05629             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
    05630             cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
    05631             col-=dim;
    05632           }
    05633           x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned long)*8-1));
    05634         }
    05635       }
    05636       return *this;
    05637     }
    05638
    05640
    05653     template<typename t> CImg& draw_line(const int x0,const int y0,const int x1,const int y1,
    05654                                          const CImg<t>& texture,
    05655                                          const int tx0,const int ty0,const int tx1,const int ty1,
    05656                                          const float opacity=1) {
    05657       cimg_test(*this,"CImg<T>::draw_line"); cimg_test(texture,"CImg<T>::draw_line");
    05658       if (texture.dim<dim)
    05659         throw CImgArgumentException("CImg<%s>::draw_line() : texture has %u channel while image has %u channels",texture.dim,dim);
    05660       int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1;
    05661       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    05662       if (nx1<0 || nx0>=dimx()) return *this;
    05663       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; }
    05664       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; }
    05665       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    05666       if (ny1<0 || ny0>=dimy()) return *this;
    05667       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; }
    05668       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; }
    05669       const unsigned int dmax = (unsigned int)cimg::max(std::abs(nx1-nx0),ny1-ny0),
    05670         whz = width*height*depth, twhz = texture.width*texture.height*texture.depth;
    05671       const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0,
    05672         tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0;
    05673       float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0;
    05674       if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) {
    05675         T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05676         t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
    05677         cimg_mapV(*this,k) { *ptrd = (T)(*ptrs); ptrd+=whz; ptrs+=twhz; }
    05678         x+=px; y+=py; tx+=tpx; ty+=tpy;
    05679       } else {
    05680         const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05681         for (unsigned int tt=0; tt<=dmax; tt++) {
    05682           T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0);
    05683           t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0);
    05684           cimg_mapV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; }
    05685           x+=px; y+=py; tx+=tpx; ty+=tpy;
    05686         }
    05687       }
    05688       return *this;
    05689     }
    05690
    05692
    05704     CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1,
    05705                      const T *const color,
    05706                      const float angle=30,const float length=-10,const unsigned long pattern=~0L,const float opacity=1) {
    05707       cimg_test(*this,"CImg<T>::draw_arrow");
    05708       const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v,
    05709         deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
    05710         l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
    05711       if (sq>0) {
    05712         const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg);
    05713         const int
    05714           xl = x1+(int)(l*cl), yl = y1+(int)(l*sl),
    05715           xr = x1+(int)(l*cr), yr = y1+(int)(l*sr),
    05716           xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2;
    05717         draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
    05718       } else draw_point(x0,y0,color,opacity);
    05719       return *this;
    05720     }
    05721
    05723
    05732     template<typename t> CImg& draw_image(const CImg<t>& sprite,
    05733                                           const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) {
    05734       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image");
    05735       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05736       const int
    05737         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05738         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05739         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05740         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05741       const t *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
    05742         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
    05743       const unsigned int
    05744         offX = width-lX, soffX = sprite.width-lX,
    05745         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05746         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
    05747       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05748       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05749       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05750         for (int v=0; v<lV; v++) {
    05751           for (int z=0; z<lZ; z++) {
    05752             for (int y=0; y<lY; y++) {
    05753               if (opacity>=1) for (int x=0; x<lX; x++) *(ptrd++) = (T)(*(ptrs++));
    05754               else for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
    05755               ptrd+=offX; ptrs+=soffX;
    05756             }
    05757             ptrd+=offY; ptrs+=soffY;
    05758           }
    05759           ptrd+=offZ; ptrs+=soffZ;
    05760         }
    05761       return *this;
    05762     }
    05763
    05764     // Add template overloading for VC++>=7.1
    05765 #if ( !defined(_MSC_VER) || _MSC_VER>1300 )
    05766     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) {
    05767       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image");
    05768       if (this==&sprite) return draw_image(CImg<T>(sprite),x0,y0,z0,v0,opacity);
    05769       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05770       const int
    05771         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05772         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05773         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05774         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05775       const T *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+
    05776         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
    05777       const unsigned int
    05778         offX = width-lX, soffX = sprite.width-lX,
    05779         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05780         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ),
    05781         slX = lX*sizeof(T);
    05782       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05783       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05784       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05785         for (int v=0; v<lV; v++) {
    05786           for (int z=0; z<lZ; z++) {
    05787             if (opacity>=1) for (int y=0; y<lY; y++) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
    05788             else for (int y=0; y<lY; y++) {
    05789               for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; }
    05790               ptrd+=offX; ptrs+=soffX;
    05791             }
    05792             ptrd+=offY; ptrs+=soffY;
    05793           }
    05794           ptrd+=offZ; ptrs+=soffZ;
    05795         }
    05796       return *this;
    05797     }
    05798 #endif
    05799
    05801
    05814     template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite,const CImg<tm>& mask,
    05815                                                        const int x0=0,const int y0=0,const int z0=0,const int v0=0,
    05816                                                        const tm mask_valmax=1,const float opacity=1) {
    05817       cimg_test(*this,"CImg<T>::draw_image"); cimg_test(sprite,"CImg<T>::draw_image"); cimg_test(mask,"CImg<T>::draw_image");
    05818       if ((void*)this==(void*)&sprite) return draw_image(CImg<T>(sprite),mask,x0,y0,z0,v0);
    05819       if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
    05820         throw CImgArgumentException("CImg<%s>::draw_image() : mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
    05821                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
    05822       const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
    05823       const int
    05824         lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
    05825         lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0),
    05826         lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
    05827         lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
    05828       const int coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-
    05829         (bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
    05830         ssize = mask.dimx()*mask.dimy()*mask.dimz();
    05831       const ti *ptrs = sprite.ptr() + coff;
    05832       const tm *ptrm = mask.ptr() + coff;
    05833       const unsigned int
    05834         offX = width-lX, soffX = sprite.width-lX,
    05835         offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY),
    05836         offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ);
    05837       T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
    05838       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05839         for (int v=0; v<lV; v++) {
    05840           ptrm = mask.data + (ptrm - mask.data)%ssize;
    05841           for (int z=0; z<lZ; z++) {
    05842             for (int y=0; y<lY; y++) {
    05843               for (int x=0; x<lX; x++) {
    05844                 const float mopacity = *(ptrm++)*opacity,
    05845                   nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f);
    05846                 *(ptrd++) = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax);
    05847               }
    05848               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
    05849             }
    05850             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
    05851           }
    05852           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
    05853         }
    05854       return *this;
    05855     }
    05856
    05858
    05871     CImg& draw_rectangle(const int x0,const int y0,const int z0,const int v0,
    05872                          const int x1,const int y1,const int z1,const int v1,
    05873                          const T& val,float opacity=1) {
    05874       cimg_test(*this,"CImg<T>::draw_rectangle");
    05875       const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1);
    05876       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;
    05877       const int
    05878         lX = (1+nx1-nx0) + (nx1>=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0),
    05879         lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0),
    05880         lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0),
    05881         lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0);
    05882       const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ);
    05883       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    05884       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
    05885       if (lX>0 && lY>0 && lZ>0 && lV>0)
    05886         for (int v=0; v<lV; v++) {
    05887           for (int z=0; z<lZ; z++) {
    05888             for (int y=0; y<lY; y++) {
    05889               if (opacity>=1) {
    05890                 if (sizeof(T)!=1) { for (int x=0; x<lX; x++) *(ptrd++) = val; ptrd+=offX; }
    05891                 else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
    05892               } else { for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ptrd++; } ptrd+=offX; }
    05893             }
    05894             ptrd+=offY;
    05895           }
    05896           ptrd+=offZ;
    05897         }
    05898       return *this;
    05899     }
    05900
    05902
    05913     CImg& draw_rectangle(const int x0,const int y0,const int z0,
    05914                          const int x1,const int y1,const int z1,
    05915                          const T *const color,const float opacity=1) {
    05916       if (!color) throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",pixel_type());
    05917       cimg_mapV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
    05918       return *this;
    05919     }
    05920
    05922
    05931     CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1,
    05932                          const T *const color,const float opacity=1) {
    05933       draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
    05934       return *this;
    05935     }
    05936
    05938
    05949     CImg& draw_triangle(const int x0,const int y0,
    05950                         const int x1,const int y1,
    05951                         const int x2,const int y2,
    05952                         const T *const color, const float opacity=1) {
    05953       cimg_test(*this,"CImg<T>::draw_triangle");
    05954       if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : specified color is (null).");
    05955       int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2;
    05956       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
    05957       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
    05958       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
    05959       if (ny0>=dimy() || ny2<0) return *this;
    05960       const float
    05961         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
    05962         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
    05963         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1);
    05964       float xleft = (float)nx0, xright = xleft, pleft = (p1<p2)?p1:p2, pright = (p1<p2)?p2:p1;
    05965       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; }
    05966       const int ya = ny1>dimy()?height:ny1;
    05967       for (int y=ny0<0?0:ny0; y<ya; y++) { draw_scanline((int)xleft,(int)xright,y,color,opacity); xleft+=pleft; xright+=pright; }
    05968       if (p1<p2) { xleft=(float)nx1;  pleft=p3;  if (ny1<0) xleft-=ny1*pleft; }
    05969       else       { xright=(float)nx1; pright=p3; if (ny1<0) xright-=ny1*pright; }
    05970       const int yb = ny2>=dimy()?height-1:ny2;
    05971       for (int yy=ny1<0?0:ny1; yy<=yb; yy++) { draw_scanline((int)xleft,(int)xright,yy,color,opacity); xleft+=pleft; xright+=pright; }
    05972       return *this;
    05973     }
    05974
    05976
    05993     template<typename t> CImg& draw_triangle(const int x0,const int y0,
    05994                                              const int x1,const int y1,
    05995                                              const int x2,const int y2,
    05996                                              const CImg<t>& texture,
    05997                                              const int tx0,const int ty0,
    05998                                              const int tx1,const int ty1,
    05999                                              const int tx2,const int ty2,
    06000                                              const float opacity=1) {
    06001       cimg_test(*this,"CImg<T>::draw_triangle"); cimg_test(texture,"CImg<T>::draw_triangle");
    06002       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;
    06003       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
    06004       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
    06005       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
    06006       if (ny0>=dimy() || ny2<0) return *this;
    06007       const float
    06008         p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0),
    06009         p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0),
    06010         p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1),
    06011         tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0,
    06012         tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0,
    06013         tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0,
    06014         tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0,
    06015         tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0,
    06016         tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0;
    06017       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06018       float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,
    06019         xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft;
    06020       if (p1<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; }
    06021       else       { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; }
    06022       if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft;
    06023         txright-=ny0*tpxright; tyright-=ny0*tpyright; }
    06024       const int ya = ny1<dimy()?ny1:height;
    06025       for (int y=(ny0<0?0:ny0); y<ya; y++) {
    06026         const int dx = (int)xright-(int)xleft;
    06027         const float
    06028           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    06029           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    06030           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    06031           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
    06032         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
    06033         if (xmin<=xmax) {
    06034           const int offx=whz-xmax+xmin-1;
    06035           T* ptrd = ptr(xmin,y,0,0);
    06036           if (opacity>=1) cimg_mapV(*this,k) {
    06037             float tx=txi, ty=tyi;
    06038             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
    06039             ptrd+=offx;
    06040           } else cimg_mapV(*this,k) {
    06041             float tx=txi, ty=tyi;
    06042             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; }
    06043             ptrd+=offx;
    06044           }
    06045         }
    06046         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
    06047       }
    06048
    06049       if (p1<p2) {
    06050         xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3;
    06051         if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; }
    06052       } else {
    06053         xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3;
    06054         if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; }
    06055       }
    06056       const int yb = ny2>=dimy()?(height-1):ny2;
    06057       for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) {
    06058         const int dx = (int)xright-(int)xleft;
    06059         const float
    06060           tpx = dx?((int)txright-(int)txleft)/(float)dx:0,
    06061           tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0,
    06062           txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)),
    06063           tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy));
    06064         const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright<dimx())?(int)xright:(width-1);
    06065         if (xmin<=xmax) {
    06066           const int offx=whz-xmax+xmin-1;
    06067           T* ptrd = ptr(xmin,yy,0,0);
    06068           if (opacity>=1) cimg_mapV(*this,k) {
    06069             float tx=txi, ty=tyi;
    06070             for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)texture((unsigned int)tx,(unsigned int)ty,0,k); tx+=tpx; ty+=tpy; }
    06071             ptrd+=offx;
    06072           } else cimg_mapV(*this,k) {
    06073             float tx=txi, ty=tyi;
    06074             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; }
    06075             ptrd+=offx;
    06076           }
    06077         }
    06078         xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright;
    06079       }
    06080       return *this;
    06081     }
    06082
    06084
    06094     CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv,
    06095                        const T *const color,const float opacity=1) {
    06096       cimg_test(*this,"CImg<T>::draw_ellipse");
    06097       if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : specified color is (null).",pixel_type());
    06098       const float
    06099         norm = (float)std::sqrt(ru*ru+rv*rv),
    06100         u = norm>0?ru/norm:1,
    06101         v = norm>0?rv/norm:0,
    06102         rmax = cimg::max(r1,r2),
    06103         l1 = (float)std::pow(rmax/(r1>0?r1:1e-6),2),
    06104         l2 = (float)std::pow(rmax/(r2>0?r2:1e-6),2),
    06105         a = l1*u*u + l2*v*v,
    06106         b = u*v*(l1-l2),
    06107         c = l1*v*v + l2*u*u;
    06108       const int
    06109         yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)),
    06110         ymin = (y0-yb<0)?0:(y0-yb),
    06111         ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb);
    06112       for (int y=ymin; y<=ymax; y++) {
    06113         const float
    06114           Y = (float)(y-y0),
    06115           delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax);
    06116         if (delta>=0) {
    06117           int xmin = (int)(x0-(b*Y+std::sqrt(delta))/a), xmax = (int)(x0-(b*Y-std::sqrt(delta))/a);
    06118           draw_scanline(xmin,xmax,y,color,opacity);
    06119         }
    06120       }
    06121       return *this;
    06122     }
    06123
    06125
    06132     template<typename t> CImg& draw_ellipse(const int x0,const int y0,const CImg<t> &tensor,
    06133                                             const T *color,const float opacity=1) {
    06134       CImgl<t> eig = tensor.get_eigen();
    06135       const CImg<t> &val = eig[0], &vec = eig[1];
    06136       return draw_ellipse(x0,y0,val(0),val(1),vec(0),vec(1),color,opacity);
    06137     }
    06138
    06140
    06147     CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const float opacity=1) {
    06148       return draw_ellipse(x0,y0,r,r,1,0,color,opacity);
    06149     }
    06150
    06152
    06163     template<typename t> CImg& draw_text(const char *const text,
    06164                                          const int x0,const int y0,
    06165                                          const T *const fgcolor,const T *const bgcolor,
    06166                                          const CImgl<t>& font,const float opacity=1) {
    06167       cimg_test(*this,"CImg<T>::draw_text");
    06168       int x=x0, y=y0;
    06169       CImg letter;
    06170       for (int i=0; i<cimg::strlen(text); i++) {
    06171         const unsigned char c = text[i];
    06172         switch (c) {
    06173         case '\n': y+=font[' '].height; x=x0; break;
    06174         case '\t': x+=4*font[' '].width; break;
    06175         default: if (c<font.size) {
    06176             letter = font[c];
    06177             const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c];
    06178             if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) if (mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=(T)(letter(p,0,0,k)*fgcolor[k]);
    06179             if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) if (!mask(p)) cimg_mapV(*this,k) letter(p,0,0,k)=bgcolor[k];
    06180             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);
    06181             x+=letter.width;
    06182           }
    06183           break;
    06184         }
    06185       }
    06186       return *this;
    06187     }
    06188
    06189
    06191
    06201     CImg& draw_text(const char *const text,
    06202                     const int x0,const int y0,
    06203                     const T *const fgcolor=NULL,const T *const bgcolor=NULL,
    06204                     const float opacity=1) {
    06205       static bool first = true;
    06206       static CImgl<T> default_font;
    06207       if (first) { default_font = CImgl<T>::get_font7x11(); first = false; }
    06208       return draw_text(text,x0,y0,fgcolor,bgcolor,default_font,opacity);
    06209     }
    06210
    06212
    06222     CImg& draw_text(const int x0,const int y0,
    06223                     const T *const fgcolor,const T *const bgcolor,
    06224                     const float opacity,const char *format,...) {
    06225       char tmp[2048];
    06226       va_list ap;
    06227       va_start(ap,format);
    06228       std::vsprintf(tmp,format,ap);
    06229       va_end(ap);
    06230       return draw_text(tmp,x0,y0,fgcolor,bgcolor,opacity);
    06231     }
    06232     template<typename t> CImg& draw_text(const int x0,const int y0,
    06233                                          const T *const fgcolor,const T *const bgcolor,
    06234                                          const CImgl<t>& font, const float opacity, const char *format,...) {
    06235       char tmp[2048]; va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap);
    06236       return draw_text(tmp,x0,y0,fgcolor,bgcolor,font);
    06237     }
    06238
    06240
    06249     template<typename t>
    06250     CImg& draw_quiver(const CImg<t>& flow,const T *const color,const unsigned int sampling=25,const float factor=-20,
    06251                       const int quiver_type=0,const float opacity=1) {
    06252       cimg_test(*this,"CImg<T>::draw_quiver"); cimg_test(flow,"CImg<T>::draw_quiver");
    06253       if (!color)
    06254         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified color is (null)",pixel_type());
    06255       if (sampling<=0)
    06256         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
    06257       if (flow.dim!=2)
    06258         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
    06259                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
    06260       float vmax,fact;
    06261       if (factor<=0) {
    06262         CImgStats st(flow.get_norm_pointwise(2),false);
    06263         vmax = (float)cimg::max(std::fabs(st.min),std::fabs(st.max));
    06264         fact = -factor;
    06265       } else { fact = factor; vmax = 1; }
    06266
    06267       for (unsigned int y=sampling/2; y<height; y+=sampling)
    06268         for (unsigned int x=sampling/2; x<width; x+=sampling) {
    06269           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
    06270           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
    06271           if (!quiver_type) {
    06272             const int xx = x+(int)u, yy = y+(int)v;
    06273             draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,~0L,opacity);
    06274           } 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);
    06275         }
    06276       return *this;
    06277     }
    06278
    06280
    06289     template<typename t1,typename t2>
    06290       CImg& draw_quiver(const CImg<t1>& flow,const CImg<t2>& color,const unsigned int sampling=25,const float factor=-20,
    06291                         const int quiver_type=0,const float opacity=1) {
    06292       cimg_test(*this,"CImg<T>::draw_quiver"); cimg_test(flow,"CImg<T>::draw_quiver"); cimg_test(color,"CImg<T>::draw_quiver");
    06293       if (sampling<=0)
    06294         throw CImgArgumentException("CImg<%s>::draw_quiver() : incorrect sampling value = %g",pixel_type(),sampling);
    06295       if (flow.dim!=2)
    06296         throw CImgArgumentException("CImg<%s>::draw_quiver() : specified flow has invalid dimensions (%u,%u,%u,%u)",
    06297                                     pixel_type(),flow.width,flow.height,flow.depth,flow.dim);
    06298       if (color.width!=flow.width || color.height!=flow.height)
    06299         throw CImgArgumentException("CImg<%s>::draw_quiver() : input color data map=(%u,%u,%u,%u)\
    06300  and data flow=(%u,%u,%u,%u) must have same dimension.",
    06301                                     color.width,color.height,color.depth,color.data,
    06302                                     flow.width,flow.height,flow.depth,flow.data);
    06303       float vmax,fact;
    06304       if (factor<=0) {
    06305         CImgStats st(flow.get_norm_pointwise(2),false);
    06306         vmax = (float)cimg::max(std::fabs(st.min),std::fabs(st.max));
    06307         fact = -factor;
    06308       } else { fact = factor; vmax = 1; }
    06309
    06310       for (unsigned int y=sampling/2; y<height; y+=sampling)
    06311         for (unsigned int x=sampling/2; x<width; x+=sampling) {
    06312           const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
    06313           float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
    06314           if (!quiver_type) {
    06315             const int xx = x+(int)u, yy = y+(int)v;
    06316             draw_arrow(x,y,xx,yy,color.get_vector(X,Y).data,45,sampling/5,~0L,opacity);
    06317           } 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);
    06318         }
    06319       return *this;
    06320     }
    06321
    06323
    06337     template<typename t>
    06338     CImg& draw_graph(const CImg<t>& data,const T *const color,const unsigned int gtype=0,
    06339                      const double ymin=0,const double ymax=0,const float opacity=1) {
    06340       cimg_test(*this,"CImg<T>::draw_graph");
    06341       if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : specified color is (null)",pixel_type());
    06342       T *color1 = new T[dim], *color2 = new T[dim];
    06343       cimg_mapV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); }
    06344       CImgStats st;
    06345       if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; }
    06346       if (st.min==st.max) { st.min--; st.max++; }
    06347       const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min;
    06348       const int Y0 = (int)(-cb/ca);
    06349       int pY=0;
    06350       cimg_mapoff(data,off) {
    06351         const int Y = (int)((data[off]-cb)/ca);
    06352         switch (gtype) {
    06353         case 0: // plot with segments
    06354           if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity);
    06355           break;
    06356         case 1: { // plot with bars
    06357           const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1;
    06358           draw_rectangle(X,(int)Y0,nX,Y,color1,opacity);
    06359           draw_line(X,Y,X,(int)Y0,color2,~0L,opacity);
    06360           draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity);
    06361           draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity);
    06362           draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity);
    06363         } break;
    06364         }
    06365         pY=Y;
    06366       }
    06367       if (gtype==2) { // plot with cubic interpolation
    06368         const CImgROI<t> ndata(data.size(),1,1,1,data.ptr());
    06369         cimg_mapX(*this,x) {
    06370           const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca);
    06371           if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity);
    06372           pY=Y;
    06373         }
    06374       }
    06375       delete[] color1; delete[] color2;
    06376       return *this;
    06377     }
    06378
    06380
    06390     CImg& draw_axeX(const double x0,const double x1,const int y,const T *const color,
    06391                     const double precision=0,const float opacity=1) {
    06392       if (x0==x1) return *this;
    06393       if (x0<x1) draw_arrow(0,y,width-1,y,color,30,5,~0L,opacity);
    06394       else draw_arrow(width-1,y,0,y,color,30,5,~0L,opacity);
    06395       const int yt = (y+14)<dimy()?(y+3):(y-14);
    06396       double nprecision=precision;
    06397       if (precision<=0) {
    06398         const double nb_pow = std::floor(std::log10(std::fabs(x1-x0)))-1;
    06399         nprecision = std::pow(10.0,nb_pow);
    06400         while ((std::fabs(x1-x0)/nprecision)>(dimx()/40)) nprecision*=2;
    06401       }
    06402       const double xmin=x0<x1?x0:x1, xmax=x0<x1?x1:x0,
    06403         tx0 = cimg::mod(xmin,nprecision)==0?xmin:((xmin+nprecision)-cimg::mod(xmin+nprecision,nprecision)),
    06404         tx1 = cimg::mod(xmax,nprecision)==0?xmax:((xmax+nprecision)-cimg::mod(xmax+nprecision,nprecision));
    06405       char txt[32];
    06406       for (double x=tx0; x<=tx1; x+=nprecision) {
    06407         std::sprintf(txt,"%g",x);
    06408         const int xi=(int)((x-x0)*(width-1)/(x1-x0)), xt = xi-(int)std::strlen(txt)*3;
    06409         draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
    06410           draw_text(txt,xt<0?0:xt,yt,color,NULL,opacity);
    06411       }
    06412       return *this;
    06413     }
    06414
    06416
    06426     CImg& draw_axeY(const int x,const double y0,const double y1,const T *const color,
    06427                     const double precision=0,const float opacity=1) {
    06428       if (y0==y1) return *this;
    06429       if (y0<y1) draw_arrow(x,0,x,height-1,color,30,5,~0L,opacity);
    06430       else draw_arrow(x,height-1,x,0,color,30,5,~0L,opacity);
    06431       double nprecision=precision;
    06432       if (precision<=0) {
    06433         const double nb_pow = std::floor(std::log10(std::fabs(y1-y0)))-1;
    06434         nprecision = std::pow(10.0,nb_pow);
    06435         while ((std::fabs(y1-y0)/nprecision)>(dimy()/40)) nprecision*=2;
    06436       }
    06437       const double ymin=y0<y1?y0:y1, ymax=y0<y1?y1:y0,
    06438         ty0 = cimg::mod(ymin,nprecision)==0?ymin:((ymin+nprecision)-cimg::mod(ymin+nprecision,nprecision)),
    06439         ty1 = cimg::mod(ymax,nprecision)==0?ymax:((ymax+nprecision)-cimg::mod(ymax+nprecision,nprecision));
    06440       char txt[32];
    06441       for (double y=ty0; y<=ty1; y+=nprecision) {
    06442         std::sprintf(txt,"%g",y);
    06443         const int yi = (int)((y-y0)*(height-1)/(y1-y0)), xt = x-(int)std::strlen(txt)*7;
    06444         draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
    06445         if (xt>0) draw_text(txt,xt,yi-5,color,NULL,opacity);
    06446         else draw_text(txt,x+3,yi-5,color,NULL,opacity);
    06447       }
    06448       return *this;
    06449     }
    06450
    06452
    06464     CImg& draw_axeXY(const double x0,const double x1,const double y0,const double y1,const T *const color,
    06465                      const double precisionx=0,const double precisiony=0,const float opacity=1) {
    06466       if (x0*x1<=0) {
    06467         const int xz = (int)(-x0*(width-1)/(x1-x0));
    06468         if (xz>=0 && xz<dimx()) draw_axeY(xz,y0,y1,color,precisiony,opacity);
    06469       }
    06470       if (y0*y1<=0) {
    06471         const int yz = (int)(-y0*(height-1)/(y1-y0));
    06472         if (yz>=0 && yz<dimy()) draw_axeX(x0,x1,yz,color,precisionx,opacity);
    06473       }
    06474       return *this;
    06475     }
    06476
    06477     // Local class used by function CImg<>::draw_fill()
    06478     template<typename T1,typename T2> struct _draw_fill {
    06479       const T1 *const color;
    06480       const float sigma,opacity;
    06481       const CImg<T1> value;
    06482       CImg<T2> region;
    06483
    06484       _draw_fill(const CImg<T1>& img,const int x,const int y,const int z,
    06485                  const T *const pcolor,const float psigma,const float popacity):
    06486         color(pcolor),sigma(psigma),opacity(popacity),
    06487         value(img.get_vector(x,y,z)), region(CImg<T2>(img.width,img.height,img.depth,1,(T2)false)) {
    06488         cimg_test(img,"CImg<T>::draw_fill");
    06489         if (!color) throw CImgArgumentException("CImg<%s>::draw_fill() : specified color is (null)",img.pixel_type());
    06490       }
    06491
    06492            _draw_fill& operator=(const _draw_fill& d) {
    06493                         color = d.color;
    06494                         sigma = d.sigma;
    06495                         opacity = d.opacity;
    06496                         value = d.value;
    06497                         region = d.region;
    06498                 }
    06499
    06500       bool comp(const CImg<T1>& A,const CImg<T1>& B) const {
    06501         bool res=true;
    06502         const T *pA=A.data+A.size();
    06503         for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) );
    06504         return res;
    06505       }
    06506
    06507       void fill(CImg<T1>& img,const int x,const int y,const int z) {
    06508         if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return;
    06509         if (!region(x,y,z) && comp(value,img.get_vector(x,y,z))) {
    06510           const T *col=color;
    06511           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06512           int xmin,xmax;
    06513           if (opacity>=1) cimg_mapV(img,k) img(x,y,z,k)=*(col++);
    06514           else cimg_mapV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k));
    06515           col-=img.dim;
    06516           region(x,y,z) = (T2)true;
    06517           for (xmin=x-1; xmin>=0 && comp(value,img.get_vector(xmin,y,z)); xmin--) {
    06518             if (opacity>=1) cimg_mapV(img,k) img(xmin,y,z,k) = *(col++);
    06519             else cimg_mapV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k));
    06520             col-=img.dim;
    06521             region(xmin,y,z)=(T2)true;
    06522           }
    06523           for (xmax=x+1; xmax<img.dimx() && comp(value,img.get_vector(xmax,y,z)); xmax++) {
    06524             if (opacity>=1) cimg_mapV(img,k) img(xmax,y,z,k) = *(col++);
    06525             else cimg_mapV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k));
    06526             col-=img.dim;
    06527             region(xmax,y,z)=(T2)true;
    06528           }
    06529           xmin++; xmax--;
    06530           for (; xmin<=xmax; xmin++) {
    06531             fill(img,xmin,y-1,z);
    06532             fill(img,xmin,y+1,z);
    06533             fill(img,xmin,y,z-1);
    06534             fill(img,xmin,y,z+1);
    06535           }
    06536         }
    06537       }
    06538     };
    06539
    06541
    06552     template<typename t> CImg& draw_fill(const int x,const int y,const int z,
    06553                                          const T *const color, CImg<t>& region,const float sigma=0,
    06554                                          const float opacity=1) {
    06555       _draw_fill<T,t> F(*this,x,y,z,color,sigma,opacity);
    06556       F.fill(*this,x,y,z);
    06557       region = F.region;
    06558       return *this;
    06559     }
    06560
    06562
    06570     CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) {
    06571       CImg<bool> tmp;
    06572       return draw_fill(x,y,z,color,tmp,sigma,opacity);
    06573     }
    06574
    06576
    06583     CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) {
    06584       CImg<bool> tmp;
    06585       return draw_fill(x,y,0,color,tmp,sigma,opacity);
    06586     }
    06587
    06589
    06598     CImg& draw_plasma(const int x0,const int y0,const int x1,const int y1,
    06599                       const double alpha=1.0,const double beta=1.0,const float opacity=1) {
    06600       cimg_test(*this,"CImg<T>::draw_plasma");
    06601       int nx0=x0,nx1=x1,ny0=y0,ny1=y1;
    06602       if (nx1<nx0) cimg::swap(nx0,nx1);
    06603       if (ny1<ny0) cimg::swap(ny0,ny1);
    06604       if (nx0<0) nx0=0;
    06605       if (nx1>=dimx()) nx1=width-1;
    06606       if (ny0<0) ny0=0;
    06607       if (ny1>=dimy()) ny1=height-1;
    06608       const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0);
    06609       const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta;
    06610       cimg_mapV(*this,k) {
    06611         if (opacity>=1) {
    06612           (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k)));
    06613           (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k)));
    06614           (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k)));
    06615           (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k)));
    06616           (*this)(xc,yc,0,k)  = (T)(0.25*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
    06617                                           (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand());
    06618         } else {
    06619           const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06620           (*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));
    06621           (*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));
    06622           (*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));
    06623           (*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));
    06624           (*this)(xc,yc,0,k)  = (T)(0.25*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
    06625                                            (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity
    06626                                     + copacity*(*this)(xc,yc,0,k));
    06627         }
    06628       }
    06629       if (xc!=nx0 || yc!=ny0) {
    06630         draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
    06631         draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
    06632         draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
    06633         draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
    06634       }
    06635       return *this;
    06636     }
    06637
    06639
    06644     CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) {
    06645       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
    06646     }
    06647
    06649
    06655     template<typename t> CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) {
    06656       cimg_test(*this,"CImg<T>::draw_gaussian");
    06657       const double sigma2 = 2*sigma*sigma;
    06658       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06659       const unsigned int whz = width*height*depth;
    06660       const T *col = color;
    06661       cimg_mapX(*this,x) {
    06662         const float dx = (x-xc);
    06663         const double val = std::exp( -dx*dx/sigma2 );
    06664         T *ptrd = ptr(x,0,0,0);
    06665         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06666         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06667         col-=dim;
    06668       }
    06669       return *this;
    06670     }
    06671
    06673
    06680     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const CImg<t>& tensor,
    06681                                              const T *const color,const float opacity=1) {
    06682       cimg_test(*this,"CImg<T>::draw_gaussian");
    06683       if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
    06684         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 2x2 matrix,"
    06685                                     "given is (%u,%u,%u,%u)",
    06686                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
    06687       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
    06688       const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1);
    06689       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06690       const unsigned int whz = width*height*depth;
    06691       const T *col = color;
    06692       cimg_mapXY(*this,x,y) {
    06693         const float dx = (x-xc), dy = (y-yc);
    06694         const double val = std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
    06695         T *ptrd = ptr(x,y,0,0);
    06696         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06697         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06698         col-=dim;
    06699       }
    06700       return *this;
    06701     }
    06702
    06704
    06711     CImg& draw_gaussian(const float xc,const float yc,const float sigma,const T *const color,const float opacity=1) {
    06712       return draw_gaussian(xc,yc,CImg<float>::diagonal(sigma,sigma),color,opacity);
    06713     }
    06714
    06716
    06724     template<typename t> CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg<t>& tensor,
    06725                                              const T *const color,const float opacity=1) {
    06726       cimg_test(*this,"CImg<T>::draw_gaussian");
    06727       if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
    06728         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter must be a 3x3 matrix,"
    06729                                     "given is (%u,%u,%u,%u)",
    06730                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim);
    06731       const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
    06732       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);
    06733       const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
    06734       const unsigned int whz = width*height*depth;
    06735       const T *col = color;
    06736       cimg_mapXYZ(*this,x,y,z) {
    06737         const float dx = (x-xc), dy = (y-yc), dz = (z-zc);
    06738         const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
    06739         T *ptrd = ptr(x,y,z,0);
    06740         if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
    06741         else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
    06742         col-=dim;
    06743       }
    06744       return *this;
    06745     }
    06746
    06748
    06756     CImg& draw_gaussian(const float xc,const float yc,const float zc,
    06757                         const double sigma,const T *const color,const float opacity=1) {
    06758       return draw_gaussian(xc,yc,zc,CImg<float>::diagonal(sigma,sigma,sigma),color,opacity);
    06759     }
    06760
    06762     //---------------------------------------
    06763     //---------------------------------------
    06764     //
    06766
    06767     //---------------------------------------
    06768     //---------------------------------------
    06769
    06771
    06780     template<typename t> CImg get_correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) const {
    06781       cimg_test_scalar(mask,"CImg<T>::get_correlate");
    06782       CImg dest(*this,false);
    06783       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
    06784         // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1)
    06785         switch (mask.depth) {
    06786         case 3: {
    06787           CImg_3x3x3(I,T);
    06788           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);
    06789           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
    06790             const double norm = (double)cimg_squaresum3x3x3(I);
    06791             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0;
    06792           }
    06793         } break;
    06794         case 2: {
    06795           CImg_2x2x2(I,T);
    06796           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);
    06797           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
    06798             const double norm = (double)cimg_squaresum2x2x2(I);
    06799             dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0;
    06800           }
    06801         } break;
    06802         default:
    06803         case 1:
    06804           switch (mask.width) {
    06805           case 5: {
    06806             CImg_5x5(I,T);
    06807             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);
    06808             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
    06809               const double norm = (double)cimg_squaresum5x5(I);
    06810               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0;
    06811             }
    06812           } break;
    06813           case 4: {
    06814             CImg_4x4(I,T);
    06815             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);
    06816             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
    06817               const double norm = (double)cimg_squaresum4x4(I);
    06818               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0;
    06819             }
    06820           } break;
    06821           case 3: {
    06822             CImg_3x3(I,T);
    06823             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);
    06824             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
    06825               const double norm = (double)cimg_squaresum3x3(I);
    06826               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0;
    06827             }
    06828           } break;
    06829           case 2: {
    06830             CImg_2x2(I,T);
    06831             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);
    06832             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
    06833               const double norm = (double)cimg_squaresum2x2(I);
    06834               dest(x,y,z,v) = (norm!=0)?(T)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0;
    06835             }
    06836           } break;
    06837           case 1: dest = mask(0)*(*this); break;
    06838           }
    06839         }
    06840       } else {
    06841         // Generic version for other masks
    06842         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);
    06843         cimg_mapV(*this,v)
    06844           if (!weighted_correl) {       // Classical correlation
    06845             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06846               double val = 0;
    06847               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06848                 val+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06849               dest(x,y,z,v)=(T)val;
    06850             }
    06851             if (cond) cimg_mapYZV(*this,y,z,v)
    06852               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))) {
    06853                 double val = 0;
    06854                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06855                   val+= neumann_pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06856                 dest(x,y,z,v)=(T)val;
    06857               }
    06858             else cimg_mapYZV(*this,y,z,v)
    06859               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))) {
    06860                 double val = 0;
    06861                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
    06862                   val+= dirichlet_pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
    06863                 dest(x,y,z,v)=(T)val;
    06864               }
    06865           } else {      // Weighted correlation
    06866             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06867               double val = 0, norm = 0;
    06868               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06869                 const T cval = (*this)(x+xm,y+ym,z+zm,v);
    06870                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06871                 norm+= cval*cval;
    06872               }
    06873               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06874             }
    06875             if (cond) cimg_mapYZV(*this,y,z,v)
    06876               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))) {
    06877                 double val = 0, norm = 0;
    06878                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06879                   const T cval = neumann_pix3d(x+xm,y+ym,z+zm,v);
    06880                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06881                   norm+=cval*cval;
    06882                 }
    06883                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06884               }
    06885             else cimg_mapYZV(*this,y,z,v)
    06886               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))) {
    06887                 double val = 0, norm = 0;
    06888                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    06889                   const T cval = dirichlet_pix3d(x+xm,y+ym,z+zm,v,0);
    06890                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    06891                   norm+= cval*cval;
    06892                 }
    06893                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):0;
    06894               }
    06895           }
    06896       }
    06897       return dest;
    06898     }
    06900
    06904     template<typename t> CImg& correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) {
    06905       return get_correlate(mask,cond,weighted_correl).swap(*this);
    06906     }
    06907
    06909
    06918     template<typename t> CImg get_convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) const {
    06919       cimg_test_scalar(mask,"CImg<T>::get_convolve");
    06920       CImg dest(*this,false);
    06921       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version
    06922         switch (mask.depth) {
    06923         case 3: {
    06924           CImg_3x3x3(I,T);
    06925           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);
    06926           else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) {
    06927             const double norm = (double)cimg_squaresum3x3x3(I);
    06928             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):(T)0;
    06929           }
    06930         } break;
    06931         case 2: {
    06932           CImg_2x2x2(I,T);
    06933           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);
    06934           else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) {
    06935             const double norm = (double)cimg_squaresum2x2x2(I);
    06936             dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):(T)0;
    06937           }
    06938         } break;
    06939         default:
    06940         case 1:
    06941           switch (mask.width) {
    06942           case 5: {
    06943             CImg_5x5(I,T);
    06944             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);
    06945             else cimg_mapZV(*this,z,v) cimg_map5x5(*this,x,y,z,v,I) {
    06946               const double norm = (double)cimg_squaresum5x5(I);
    06947               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv5x5(I,mask)/std::sqrt(norm)):(T)0;
    06948             }
    06949           } break;
    06950           case 4: {
    06951             CImg_4x4(I,T);
    06952             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);
    06953             else cimg_mapZV(*this,z,v) cimg_map4x4(*this,x,y,z,v,I) {
    06954               const double norm = (double)cimg_squaresum4x4(I);
    06955               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv4x4(I,mask)/std::sqrt(norm)):(T)0;
    06956             }
    06957           } break;
    06958           case 3: {
    06959             CImg_3x3(I,T);
    06960             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);
    06961             else cimg_mapZV(*this,z,v) cimg_map3x3(*this,x,y,z,v,I) {
    06962               const double norm = (double)cimg_squaresum3x3(I);
    06963               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv3x3(I,mask)/std::sqrt(norm)):(T)0;
    06964             }
    06965           } break;
    06966           case 2: {
    06967             CImg_2x2(I,T);
    06968             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);
    06969             else cimg_mapZV(*this,z,v) cimg_map2x2(*this,x,y,z,v,I) {
    06970               const double norm = (double)cimg_squaresum2x2(I);
    06971               dest(x,y,z,v) = (norm!=0)?(T)(cimg_conv2x2(I,mask)/std::sqrt(norm)):(T)0;
    06972             }
    06973           } break;
    06974           case 1: dest = mask(0)*(*this); break;
    06975           }
    06976         }
    06977       } else { // generic version
    06978
    06979         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);
    06980         cimg_mapV(*this,v)
    06981           if (!weighted_convol) {       // Classical convolution
    06982             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    06983               double val = 0;
    06984               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06985                 val+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06986               dest(x,y,z,v)=(T)val;
    06987             }
    06988             if (cond) cimg_mapYZV(*this,y,z,v)
    06989               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))) {
    06990                 double val = 0;
    06991                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++)
    06992                   val+= neumann_pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
    06993                 dest(x,y,z,v)=(T)val;
    06994               }
    06995             else cimg_mapYZV(*this,y,z,v)
    06996               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))) {
    06997                 double val = 0;
    06998                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++)
    06999                   val+= dirichlet_pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
    07000                 dest(x,y,z,v)=(T)val;
    07001               }
    07002           } else {      // Weighted convolution
    07003             for (int z=czm; z<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) {
    07004               double val = 0, norm = 0;
    07005               for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    07006                 const T cval = (*this)(x-xm,y-ym,z-zm,v);
    07007                 val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    07008                 norm+= cval*cval;
    07009               }
    07010               dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    07011             }
    07012             if (cond) cimg_mapYZV(*this,y,z,v)
    07013               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))) {
    07014                 double val = 0, norm = 0;
    07015                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) {
    07016                   const T cval = neumann_pix3d(x-xm,y-ym,z-zm,v);
    07017                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    07018                   norm+=cval*cval;
    07019                 }
    07020                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    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, norm = 0;
    07025                 for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++)  for (int xm=-cxm; xm<=fxm; xm++) {
    07026                   const T cval = dirichlet_pix3d(x-xm,y-ym,z-zm,v,0);
    07027                   val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
    07028                   norm+= cval*cval;
    07029                 }
    07030                 dest(x,y,z,v)=(norm!=0)?(T)(val/std::sqrt(norm)):(T)0;
    07031               }
    07032           }
    07033       }
    07034       return dest;
    07035     }
    07036
    07038
    07042     template<typename t> CImg& convolve(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_convol=false) {
    07043       return get_convolve(mask,cond,weighted_convol).swap(*this);
    07044     }
    07045
    07047
    07051     CImg& noise(const double sigma=-20,const unsigned int ntype=0) {
    07052       cimg_test(*this,"CImg<T>::noise");
    07053       double nsigma = sigma;
    07054       static bool first_time = true;
    07055       if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; }
    07056       CImgStats st;
    07057       if (nsigma==0) return *this;
    07058       if (nsigma<0 || ntype==2) st = CImgStats(*this,false);
    07059       if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0;
    07060       switch (ntype) {
    07061       case 0: { cimg_map(*this,ptr,T) *ptr=(T)(*ptr+nsigma*cimg::grand()); } break;    // Gaussian noise
    07062       case 1: { cimg_map(*this,ptr,T) *ptr=(T)(*ptr+nsigma*cimg::crand()); } break;    // Uniform noise
    07063       case 2: {                                                                       // Salt & Pepper
    07064         if (st.max==st.min) { st.min=0; st.max=255; }
    07065         cimg_map(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr=(T)(cimg::rand()<0.5?st.max:st.min);
    07066       } break;
    07067       }
    07068       return *this;
    07069     }
    07070
    07072
    07077     CImg get_noise(const double sigma=-20,const unsigned int ntype=0) const { return CImg<T>(*this).noise(sigma,ntype); }
    07078
    07079
    07080 #define cimg_deriche_map(x0,y0,z0,k0,nb,offset,T) {                           \
    07081     ima = ptr(x0,y0,z0,k0);                                                   \
    07082     I2 = *ima; ima+=offset; I1 = *ima; ima+=offset;                           \
    07083     Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2;                   \
    07084     for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset;                          \
    07085         Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2;                          \
    07086         I2=I1; Y2=Y1; Y1=Y0; }                                                \
    07087     ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \
    07088     ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1);                            \
    07089     for (i=(nb)-3; i>=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset;      \
    07090       I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; }                    \
    07091   }
    07092
    07094
    07098     CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) {
    07099       cimg_test(*this,"CImg<T>::deriche");
    07100       if (sigma<0 || order<0 || order>2)
    07101         throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order);
    07102       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;
    07103       float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0;
    07104       double *Y,Y0,Y1,Y2;
    07105       int i,offset,nb;
    07106       T *ima,I1,I2;
    07107       switch(order) {
    07108       case 1:                 // first derivative
    07109         ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0;  a2 = ek*ema; a3 = -ek*ema; parity =-1;\
    07110         if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } \
    07111         else g0 = sumg0 = sumg1 = 0;
    07112         break;
    07113       case 2:               // second derivative
    07114         ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
    07115         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;
    07116         if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; }
    07117         else g0=sumg0=sumg1=0;
    07118         break;
    07119       default:              // smoothing
    07120         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;
    07121         if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; }
    07122         else  g0=sumg0=sumg1=0;
    07123         break;
    07124       }
    07125       // filter init
    07126       Y = new double[cimg::max(width,height,depth)];
    07127       switch(cimg::uncase(axe)) {
    07128       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;
    07129       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;
    07130       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;
    07131       default: throw CImgArgumentException("CImg<%s>::deriche() : unknow axe '%c', must be 'x','y' or 'z'",pixel_type(),axe);
    07132       }
    07133       delete[] Y;
    07134       return *this;
    07135     }
    07137
    07142     CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const {
    07143       return CImg<T>(*this).deriche(sigma,order,axe,cond);
    07144     }
    07145
    07147
    07151     CImg& blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) {
    07152       cimg_test(*this,"CImg<T>::blur");
    07153       if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
    07154       if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
    07155       if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
    07156       return *this;
    07157     }
    07158
    07160     CImg& blur(const float sigma=1,const unsigned int cond=1) { return blur(sigma,sigma,sigma,cond); }
    07161
    07163
    07166     CImg get_blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) const {
    07167       return CImg<T>(*this).blur(sigmax,sigmay,sigmaz,cond);
    07168     }
    07169
    07171     CImg get_blur(const float sigma=1,const unsigned int cond=1) const { return CImg<T>(*this).blur(sigma,cond); }
    07172
    07174     CImg get_erode(const unsigned int n=1) {
    07175       CImg_3x3x3(I,T);
    07176       if (n==1) {
    07177         CImg dest(*this);
    07178         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I)
    07179           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) dest(x,y,z,k) = 0;
    07180         return dest;
    07181       }
    07182       CImg img1(*this),img2(*this,false);
    07183       CImg *src = &img1, *dest = &img2, *tmp = NULL;
    07184       for (unsigned int iter=0; iter<n; iter++) {
    07185         *dest = *src;
    07186         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I)
    07187           if (Iccc && (!Incc || !Ipcc || !Icnc || !Icpc || !Iccn || !Iccp)) (*dest)(x,y,z,k) = 0;
    07188         tmp = src;
    07189         src = dest;
    07190         dest = tmp;
    07191       }
    07192       return *src;
    07193     }
    07194
    07196     CImgl<T> get_FFT(const char axe,const bool inverse=false) const {
    07197       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(axe,inverse);
    07198     }
    07199
    07201     CImgl<T> get_FFT(const bool inverse=false) const {
    07202       return CImgl<T>(*this,CImg<T>(width,height,depth,dim,0)).FFT(inverse);
    07203     }
    07204
    07206     CImg& erode(const unsigned int n=1) { return get_erode(n).swap(*this); }
    07207
    07209     CImg get_dilate(const unsigned int n=1) {
    07210       CImgStats stats(*this);
    07211       const T tmax = stats.max!=0?(T)stats.max:(T)1;
    07212       CImg_3x3x3(I,T);
    07213       if (n==1) {
    07214         CImg dest(*this);
    07215         cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I)
    07216           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) dest(x,y,z,k) = tmax;
    07217         return dest;
    07218       }
    07219       CImg img1(*this),img2(*this,false);
    07220       CImg *src = &img1, *dest = &img2, *tmp = NULL;
    07221       for (unsigned int iter=0; iter<n; iter++) {
    07222         *dest = *src;
    07223         cimg_mapV(*src,k) cimg_map3x3x3(*src,x,y,z,k,I)
    07224           if (!Iccc && (Incc || Ipcc || Icnc || Icpc || Iccn || Iccp)) (*dest)(x,y,z,k) = tmax;
    07225         tmp = src;
    07226         src = dest;
    07227         dest = tmp;
    07228       }
    07229       return *src;
    07230     }
    07232     CImg& dilate(const unsigned int n=1) { return get_dilate(n).swap(*this); }
    07233
    07235     //------------------------------------------
    07236     //------------------------------------------
    07237     //
    07239
    07240     //------------------------------------------
    07241     //------------------------------------------
    07242
    07244     static CImg vector(const T& a1) { return CImg<T>(1,1).fill(a1); }
    07245     static CImg vector(const T& a1,const T& a2) { return CImg<T>(1,2).fill(a1,a2); }
    07246     static CImg vector(const T& a1,const T& a2,const T& a3) { return CImg<T>(1,3).fill(a1,a2,a3); }
    07247     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); }
    07248     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); }
    07249     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); }
    07250     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
    07251                        const T& a5,const T& a6,const T& a7) { return CImg<T>(1,7).fill(a1,a2,a3,a4,a5,a6,a7); }
    07252     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
    07253                        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); }
    07254     static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,
    07255                        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); }
    07256
    07258     static CImg matrix(const T& a1) { return vector(a1); }
    07259     static CImg matrix(const T& a1,const T& a2,
    07260                        const T& a3,const T& a4) { return CImg<T>(2,2).fill(a1,a2,a3,a4); }
    07261     static CImg matrix(const T& a1,const T& a2,const T& a3,
    07262                        const T& a4,const T& a5,const T& a6,
    07263                        const T& a7,const T& a8,const T& a9) { return CImg<T>(3,3).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
    07264     static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4,
    07265                        const T& a5,const T& a6,const T& a7,const T& a8,
    07266                        const T& a9,const T& a10,const T& a11,const T& a12,
    07267                        const T& a13,const T& a14,const T& a15,const T& a16) {
    07268       return CImg<T>(4,4).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
    07269     }
    07270
    07272     static CImg tensor(const T& a1) { return matrix(a1); }
    07273     static CImg tensor(const T& a1,const T& a2,const T& a3) { return matrix(a1,a2,a2,a3); }
    07274     static CImg tensor(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) {
    07275       return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
    07276     }
    07277
    07279     static CImg diagonal(const T& a1) { return matrix(a1); }
    07280     static CImg diagonal(const T& a1,const T& a2) { return matrix(a1,0,0,a2); }
    07281     static CImg diagonal(const T& a1,const T& a2,const T& a3) { return matrix(a1,0,0,0,a2,0,0,0,a3); }
    07282     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); }
    07283
    07285     template<typename t> CImg operator*(const CImg<t>& img) const {
    07286       cimg_test_matrix(*this,"CImg<T>::operator*");
    07287       cimg_test_matrix(img,"CImg<T>::operator*");
    07288       if (width!=img.height)
    07289         throw CImgArgumentException("CImg<%s>::operator*() : can't multiply a matrix *this = (%ux%u) by a matrix (%ux%u)",
    07290                                     pixel_type(),width,height,img.width,img.height);
    07291       CImg res(img.width,height);
    07292       double val;
    07293       cimg_mapXY(res,i,j) { val=0; cimg_mapX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = (T)val; }
    07294       return res;
    07295     }
    07297     template<typename t> CImg& operator*=(const CImg<t>& img) { return ((*this)*img).swap(*this); }
    07298
    07300     CImg get_vector(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07301       CImg dest(dim);
    07302       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
    07303       return dest;
    07304     }
    07305
    07307     CImg get_matrix(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07308       const int n = (int)std::sqrt((double)dim);
    07309       CImg dest(n,n);
    07310       cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k);
    07311       return dest;
    07312     }
    07313
    07315     CImg get_tensor(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const {
    07316       if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
    07317                                 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
    07318       if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
    07319       return tensor((*this)(x,y,z,0));
    07320     }
    07321
    07323     CImg& set_vector(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07324       return draw_point(x,y,z,vec.data,1);
    07325     }
    07327     CImg& set_matrix(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07328       return set_vector(mat,x,y,z);
    07329     }
    07331     CImg& set_tensor(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) {
    07332       if (ten.height==2) {
    07333         (*this)(x,y,z,0)=ten[0];
    07334         (*this)(x,y,z,1)=ten[1];
    07335         (*this)(x,y,z,2)=ten[3];
    07336       }
    07337       else {
    07338         (*this)(x,y,z,0)=ten[0];
    07339         (*this)(x,y,z,1)=ten[1];
    07340         (*this)(x,y,z,2)=ten[2];
    07341         (*this)(x,y,z,3)=ten[4];
    07342         (*this)(x,y,z,4)=ten[5];
    07343         (*this)(x,y,z,5)=ten[8];
    07344       }
    07345       return *this;
    07346     }
    07348     CImg& identity_matrix(const unsigned int N) { return get_identity_matrix(N).swap(*this); }
    07349
    07351     static CImg get_identity_matrix(const unsigned int N) {
    07352       CImg<T> res(N,N,1,1,0);
    07353       cimg_mapX(res,x) res(x,x)=1;
    07354       return res;
    07355     }
    07356
    07358     CImg get_transpose() const {
    07359       cimg_test_matrix(*this,"CImg<T>::get_transpose");
    07360       CImg res(height,width);
    07361       cimg_mapXY(res,x,y) res(x,y) = (*this)(y,x);
    07362       return res;
    07363     }
    07365     CImg& transpose() { return get_transpose().swap(*this); }
    07366
    07368     CImg get_diagonal() const {
    07369       cimg_test(*this,"CImg<T>::get_diagonal");
    07370       CImg res(size(),size(),1,1,0);
    07371       cimg_mapoff(*this,off) res(off,off)=(*this)(off);
    07372       return res;
    07373     }
    07375     CImg& diagonal() { return get_diagonal().swap(*this); }
    07376
    07378     CImg& inverse() {
    07379       cimg_test_square(*this,"CImg<T>::inverse");
    07380       switch (width) {
    07381       case 2:
    07382         {
    07383           const double
    07384             a = data[0], c = data[1],
    07385             b = data[2], d = data[3],
    07386             dete = det();
    07387           if (dete) {
    07388             data[0] = (T)(d/dete);  data[1] = (T)(-c/dete);
    07389             data[2] = (T)(-b/dete), data[3] = (T)(a/dete);
    07390           } else {
    07391             cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
    07392             fill(0);
    07393           }
    07394         }
    07395         break;
    07396       case 3:
    07397         {
    07398           const double
    07399             a = data[0], d = data[1], g = data[2],
    07400             b = data[3], e = data[4], h = data[5],
    07401             c = data[6], f = data[7], i = data[8],
    07402             dete = det();
    07403           if (dete) {
    07404             data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
    07405             data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
    07406             data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
    07407           } else {
    07408             cimg::warn(true,"CImg<%s>::inverse() : Matrix determinant is 0, can't invert matrix",pixel_type());
    07409             fill(0);
    07410           }
    07411         }
    07412         break;
    07413       default:
    07414         {
    07415           int N = width, LWORK = 4*N, *IPIV = new int[N], INFO;
    07416           double *A = new double[N*N], *WORK = new double[LWORK];
    07417           for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) A[k*N+l] = (*this)(k,l);
    07418           dgetrf_(&N,&N,A,&N,IPIV,&INFO);
    07419           cimg::warn(INFO!=0,"CImg<%s>::inverse() : LAPACK Error code = %d, from dgetrf_()",pixel_type(),INFO);
    07420           if (!INFO) {
    07421             dgetri_(&N,A,&N,IPIV,WORK,&LWORK,&INFO);
    07422             cimg::warn(INFO!=0,"CImg<%s>::inverse() : LAPACK Error code = %d, from dgetri_()",pixel_type(),INFO);
    07423           }
    07424           if (!INFO) for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) (*this)(k,l) = (T)(A[k*N+l]);
    07425           else fill(0);
    07426           delete[] IPIV; delete[] A; delete[] WORK;
    07427         }
    07428       }
    07429       return *this;
    07430     }
    07432     CImg get_inverse() const { return CImg<T>(*this).inverse(); }
    07433
    07435     double trace() const {
    07436       cimg_test_square(*this,"CImg<T>::trace");
    07437       double res=0;
    07438       cimg_mapX(*this,k) res+=(*this)(k,k);
    07439       return res;
    07440     }
    07442     double dot(const CImg& img) const {
    07443       cimg_test(*this,"CImg<T>::dot"); cimg_test(img,"CImg<T>::dot");
    07444       const unsigned int nb = cimg::min(size(),img.size());
    07445       double res=0;
    07446       for (unsigned int off=0; off<nb; off++) res+=data[off]*img[off];
    07447       return res;
    07448     }
    07449
    07451     CImg& cross(const CImg& img) {
    07452       if (width!=1 || height<3 || img.width!=1 || img.height<3)
    07453         throw CImgInstanceException("CImg<%s>::cross() : cannot get cross product between two matrices (%u,%u) and (%u,%u)",
    07454                                     pixel_type(),width,height,img.width,img.height);
    07455       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
    07456       (*this)[0] = y*img[2]-z*img[1];
    07457       (*this)[1] = z*img[0]-x*img[2];
    07458       (*this)[2] = x*img[1]-y*img[0];
    07459       return *this;
    07460     }
    07462     CImg get_cross(const CImg& img) const { return CImg<T>(*this).cross(img); }
    07463
    07465     double det() const {
    07466       cimg_test_square(*this,"CImg<T>::det");
    07467       switch (width) {
    07468       case 1: return (*this)(0,0);
    07469       case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
    07470       case 3:
    07471         {
    07472           const double
    07473             a = data[0], d = data[1], g = data[2],
    07474             b = data[3], e = data[4], h = data[5],
    07475             c = data[6], f = data[7], i = data[8];
    07476           return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
    07477         }
    07478       }
    07479       return 0;
    07480     }
    07482     double norm(const int ntype=2) const {
    07483       cimg_test(*this,"CImg<T>::norm");
    07484       double res = 0;
    07485       switch (ntype) {
    07486       case -1: { cimg_mapoff(*this,off) if (std::fabs((double)data[off])>res) res = std::fabs((double)data[off]); return res; }
    07487       case 1 : { cimg_mapoff(*this,off) res+=std::fabs((double)data[off]); return res; }
    07488       default: { return std::sqrt(dot(*this)); }
    07489       }
    07490       return 0;
    07491     }
    07493     double sum() const {
    07494       cimg_test(*this,"CImg<T>::sum");
    07495       double res=0;
    07496       cimg_map(*this,ptr,T) res+=*ptr;
    07497       return res;
    07498     }
    07499
    07501     template<typename t> const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
    07502       cimg_test_square(*this,"CImg<T>::eigen");
    07503       if (val.size()<width) val = CImg<t>(width);
    07504       if (vec.size()<width*width) vec = CImg<t>(width,width);
    07505       switch(width) {
    07506       case 1: { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
    07507       case 2: {
    07508         const double
    07509           a = (*this)[0], b = (*this)[1],
    07510           c = (*this)[2], d = (*this)[3],
    07511           e = a+d;
    07512         double f = e*e-4*(a*d-b*c);
    07513         cimg::warn(f<0,"CImg<%s>::eigen() : Complex eigenvalues",pixel_type());
    07514         f = std::sqrt(f);
    07515         const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
    07516         double u, v, n;
    07517         val[0]=(t)l1; val[1]=(t)l2;
    07518         if (std::fabs(b)>std::fabs(a-l1)) { u = 1; v = (l1-a)/b; }
    07519         else { if (a-l1!=0) { u = -b/(a-l1); v = 1; } else { u = 1; v = 0; } }
    07520         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec[0] = (t)u; vec[1] = (t)v;
    07521         if (std::fabs(b)>std::fabs(a-l2)) { u = 1; v = (l2-a)/b; }
    07522         else { if (a-l2!=0) { u = -b/(a-l2); v = 1; } else { u = 0; v = 1; } }
    07523         n = std::sqrt(u*u+v*v); u/=n; v/=n; vec[2] = (t)u; vec[3] = (t)v;
    07524       } break;
    07525       default:
    07526         throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices "
    07527                                     "(given is %ux%u)", pixel_type(),width,height);
    07528       }
    07529       return *this;
    07530     }
    07531
    07533     template<typename t> const CImg<T>& eigen(CImg<t>& val) const { CImg foo; return eigen(val,foo); }
    07534
    07536     CImgl<T> get_eigen() const { CImgl<T> res; eigen(res); return res; }
    07537
    07539     template<typename t> const CImg<T>& eigen(CImgl<t>& eig) const {
    07540       if (!eig.size) eig = CImgl<t>(2);
    07541       if (eig.size<2) eigen(eig[0]); else eigen(eig[0],eig[1]);
    07542       return *this;
    07543     }
    07544
    07546     template<typename t> const CImg<T>& symeigen(CImg<t>& val, CImg<t>& vec) const {
    07547       cimg_test_square(*this,"CImg<T>::symeigen");
    07548       if (val.size()<width) val = CImg<t>(width);
    07549       if (vec.data && vec.size()<width*width) vec = CImg<t>(width,width);
    07550       if (width<3) return eigen(val,vec);
    07551
    07552       char JOBZ=vec.data?'V':'N', UPLO='U';
    07553       int N,INFO=0,LWORK;
    07554       double *WORK,*A,*VAL;
    07555       N = width;
    07556       LWORK = 5*N;
    07557       A    = new double[N*N];
    07558       WORK = new double[LWORK];
    07559       VAL  = new double[width];
    07560       for (unsigned int k=0; k<(unsigned int)N; k++) for (unsigned int l=0; l<(unsigned int)N; l++) A[k*N+l] = (*this)(k,l);
    07561       dsyev_(&JOBZ,&UPLO,&N,A,&N,VAL,WORK,&LWORK,&INFO);
    07562       cimg::warn(INFO!=0,"CImg<%s>::symeigen() : LAPACK Error code = %d, from ssyev_()",pixel_type(),INFO);
    07563       cimg_mapX(*this,x) val(x) = (t)VAL[x];
    07564       if (vec.data) cimg_mapXY(*this,x,y) vec(x,y) = (t)A[x+y*N];
    07565       delete[] A;
    07566       delete[] WORK;
    07567       delete[] VAL;
    07568       return *this;
    07569     }
    07570
    07572     template<typename t> const CImg<T>& symeigen(CImg<t>& val) const { CImg foo; return symeigen(val,foo); }
    07573
    07574     // Compute the eigenvalues and eigenvectors of a symmetric matrix.
    07575     CImgl<T> get_symeigen() const { CImgl<T> res; symeigen(res); return res; }
    07576
    07577     // Compute the eigenvalues and eigenvectors of a symmetric matrix.
    07578     template<typename t> const CImg<T>& symeigen(CImgl<t>& eig) const {
    07579       if (!eig.size) eig = CImgl<t>(CImg<t>(width),CImg<t>(width,width));
    07580       if (eig.size<2) symeigen(eig[0]); else symeigen(eig[0],eig[1]);
    07581       return *this;
    07582     }
    07583
    07585     //------------------------------------------
    07586     //------------------------------------------
    07587     //
    07589
    07590     //------------------------------------------
    07591     //------------------------------------------
    07592
    07594     const CImg& display(CImgDisplay& disp,const unsigned int ymin=0,const unsigned int ymax=~0) const { disp.display(*this,ymin,ymax); return *this; }
    07595
    07597     const CImg& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
    07598
    07602     const CImg& display(const char* title,const int min_size=128,const int max_size=1024) const {
    07603       cimg_test(*this,"CImg<T>::display");
    07604       CImgDisplay *disp;
    07605       unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3];
    07606       print(title);
    07607       const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
    07608       if (dmin<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); }
    07609       const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
    07610       if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); }
    07611       disp = new CImgDisplay(CImg<unsigned char>(w,h,1,1,0),title,0,3);
    07612       XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2;
    07613       while (!disp->closed && !disp->key) feature_selection(NULL,1,*disp,XYZ);
    07614       delete disp;
    07615       return *this;
    07616     }
    07617
    07619     const CImg& display(const int min_size=128,const int max_size=1024) const { return display("",min_size,max_size); }
    07620
    07622     const CImg& feature_selection(int *const selection, const int feature_type,CImgDisplay &disp,
    07623                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
    07624       cimg_test(*this,"CImg<T>::feature_selection");
    07625       if (disp.events<3)
    07626         throw CImgArgumentException("CImg<%s>::feature_selection() : Input display must be able to catch keyboard and mouse events (events>=3). Given display has 'events = %s'.",pixel_type(),disp.events);
    07627       unsigned char fgcolor[3]={255,255,105},bgcolor[3]={0,0,0};
    07628       if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv()));
    07629       int carea=0,area=0,phase=0,
    07630         X0=(XYZ?XYZ[0]:width/2)%width, Y0=(XYZ?XYZ[1]:height/2)%height, Z0=(XYZ?XYZ[2]:depth/2)%depth,
    07631         X=-1,Y=-1,Z=-1,oX=-1,oY=-1,oZ=-1,X1=-1,Y1=-1,Z1=-1;
    07632       unsigned long hatch=feature_type?0xF0F0F0F0:~0L;
    07633       bool feature_selected = false, ytext = false;
    07634       CImg<unsigned char> visu, visu0;
    07635       char text[1024];
    07636
    07637       while (!disp.key && !disp.closed && !feature_selected) {
    07638
    07639         // Init visu0 if necessary
    07640         if (disp.resized || !visu0.data) {
    07641           if (disp.resized) disp.resize();
    07642           if (depth==1) visu0=get_normalize(0,(T)255); else visu0=get_3dplanes(X0,Y0,Z0).get_normalize(0,(T)255);
    07643           visu0.resize(disp.width,disp.height,1,cimg::min(3,dimv()));
    07644         }
    07645         visu = visu0;
    07646
    07647         // Handle motion and selection
    07648         const int mx = disp.mousex, my = disp.mousey, b = disp.button;
    07649         if (mx>=0 && my>=0) {
    07650           const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
    07651           if (mX<dimx() && mY<dimy())   { area=1; X=mX; Y=mY; Z=phase?Z1:Z0; }
    07652           if (mX<dimx() && mY>=dimy())  { area=2; X=mX; Y=phase?Y1:Y0; Z=mY-height; }
    07653           if (mX>=dimx() && mY<dimy())  { area=3; X=phase?X1:X0; Y=mY; Z=mX-width;  }
    07654           if (mX>=dimx() && mY>=dimy()) { X=X0; Y=Y0; Z=Z0; }
    07655           if ((!(phase%2) && (b&1)) || (phase%2 && !(b&1))) {
    07656             if (!carea) carea=area;
    07657             if (!(phase++)) { X0=X; Y0=Y; Z0=Z; }
    07658           }
    07659           if (b&2) { if (!phase) { X0=X; Y0=Y; Z0=Z; } else { X1=Y1=Z1=-1; phase=carea=0; }}
    07660           if ((b&2 || phase) && depth>1)
    07661             visu0 = get_3dplanes(X,Y,Z).normalize(0,(T)255).resize(disp.width,disp.height,1,cimg::min(3,dimv()));
    07662           if (phase) {
    07663             if (!feature_type) feature_selected = phase?true:false;
    07664             else {
    07665               if (depth>1) feature_selected = (phase==3)?true:false;
    07666               else feature_selected = (phase==2)?true:false;
    07667             }
    07668             if (!feature_selected) {
    07669               if (phase<2) { X1=X; Y1=Y; Z1=Z; }
    07670               else switch(carea) {
    07671               case 1: Z1=Z; break;
    07672               case 2: Y1=Y; break;
    07673               case 3: X1=X; break;
    07674               }
    07675             }
    07676           }
    07677           if (!phase || !feature_type) {
    07678             if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y);
    07679             cimg_mapV(*this,k) std::sprintf(text+cimg::strlen(text),"%g ",(double)(*this)(X,Y,Z,k));
    07680             std::sprintf(text+cimg::strlen(text),"}");
    07681             if (!feature_type) { X1=X0; Y1=Y0; Z1=Z0; }
    07682           } else
    07683             switch (feature_type) {
    07684             case 1:
    07685               {
    07686                 const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
    07687                 if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm);
    07688                 else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm);
    07689               }
    07690               break;
    07691             case 2:
    07692               if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)",
    07693                                         X0<X1?X0:X1,Y0<Y1?Y0:Y1,Z0<Z1?Z0:Z1,
    07694                                         X0<X1?X1:X0,Y0<Y1?Y1:Y0,Z0<Z1?Z1:Z0,
    07695                                         1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
    07696               else  std::sprintf(text,"Box (%d,%d)-(%d,%d), Size=(%d,%d)",
    07697                                  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));
    07698               break;
    07699             }
    07700           if (my<12) ytext=true;
    07701           if (my>=visu.dimy()-11) ytext=false;
    07702           visu.draw_text(text,0,ytext?visu.dimy()-11:0,fgcolor,bgcolor,0.7f);
    07703         } else { X=Y=Z=-1; if (phase) disp.button=phase%2; }
    07704
    07705         // Draw image + selection on display window
    07706         if (X>=0 && Y>=0 && Z>=0) {
    07707           hatch=cimg::ror(hatch);
    07708           if (feature_type==1 && phase) {
    07709             const int d=(depth>1)?depth:0,
    07710               x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)),
    07711               x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d));
    07712             visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch);
    07713             if (d) {
    07714               const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)),
    07715                 zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d));
    07716               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);
    07717             }
    07718           } else {
    07719             const bool cond=(phase&&feature_type);
    07720             const int d=(depth>1)?depth:0,
    07721               nX0=cond?X0:X, nY0=cond?Y0:Y, nZ0=cond?Z0:Z,
    07722               nX1=cond?X1:X, nY1=cond?Y1:Y, nZ1=cond?Z1:Z,
    07723               x0=(nX0<nX1?nX0:nX1)*disp.width/(width+d),
    07724               y0=(nY0<nY1?nY0:nY1)*disp.height/(height+d),
    07725               x1=((nX0<nX1?nX1:nX0)+1)*disp.width/(width+d)-1,
    07726               y1=((nY0<nY1?nY1:nY0)+1)*disp.height/(height+d)-1;
    07727             const unsigned long nhatch=phase?hatch:~0L;
    07728             visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,nhatch).
    07729               draw_line(x1,y0,x1,y1,fgcolor,nhatch).draw_line(x1,y1,x0,y1,fgcolor,nhatch).draw_line(x0,y1,x0,y0,fgcolor,nhatch);
    07730             if (d) {
    07731               const int
    07732                 zx0=(int)((width+(nZ0<nZ1?nZ0:nZ1))*disp.width/(width+d)),
    07733                 zy0=(int)((height+(nZ0<nZ1?nZ0:nZ1))*disp.height/(height+d)),
    07734                 zx1=(int)((width+(nZ0<nZ1?nZ1:nZ0)+1)*disp.width/(width+d))-1,
    07735                 zy1=(int)((height+(nZ0<nZ1?nZ1:nZ0)+1)*disp.height/(height+d))-1;
    07736               visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,nhatch).
    07737                 draw_line(zx1,y0,zx1,y1,fgcolor,nhatch).draw_line(zx1,y1,zx0,y1,fgcolor,nhatch).draw_line(zx0,y1,zx0,y0,fgcolor,nhatch);
    07738               visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,nhatch).
    07739                 draw_line(x1,zy0,x1,zy1,fgcolor,nhatch).draw_line(x1,zy1,x0,zy1,fgcolor,nhatch).draw_line(x0,zy1,x0,zy0,fgcolor,nhatch);
    07740             }
    07741           }
    07742         }
    07743         visu.display(disp).wait(32);
    07744         if ((!feature_selected && !phase && oX==X && oY==Y && oZ==Z) || (X<0 || Y<0 || Z<0)) disp.wait();
    07745         oX=X; oY=Y; oZ=Z;
    07746       }
    07747
    07748       // Return result
    07749       if (XYZ) { XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; }
    07750       if (feature_selected) {
    07751         if (feature_type==2) {
    07752           if (X0>X1) cimg::swap(X0,X1);
    07753           if (Y0>Y1) cimg::swap(Y0,Y1);
    07754           if (Z0>Z1) cimg::swap(Z0,Z1);
    07755         }
    07756         if (selection) {
    07757           if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1;
    07758           switch(feature_type) {
    07759           case 1:
    07760           case 2:  selection[3] = X1; selection[4] = Y1; selection[5] = Z1;
    07761           default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0;
    07762           }
    07763         }
    07764       } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1;
    07765       disp.button=0;
    07766       return *this;
    07767     }
    07768
    07770     const CImg& feature_selection(int *const selection, const int feature_type,
    07771                                   unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const {
    07772       unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0);
    07773       const unsigned int dmin = cimg::min(w,h), minsiz = 256;
    07774       if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
    07775       const unsigned int dmax = cimg::max(w,h), maxsiz = 1024;
    07776       if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
    07777       CImgDisplay disp(w,h,"",0,3);
    07778       return feature_selection(selection,feature_type,disp,XYZ,color);
    07779     }
    07780
    07781
    07783     //------------------------------------------
    07784     //------------------------------------------
    07785     //
    07787
    07788     //------------------------------------------
    07789     //------------------------------------------
    07790
    07792
    07798     static CImg load(const char *filename) {
    07799       if (!filename) throw CImgArgumentException("CImg<%s>::load() : Can't load (null) filename",pixel_type());
    07800       const char *ext = cimg::filename_split(filename);
    07801       if (!cimg::strcasecmp(ext,"asc")) return load_ascii(filename);
    07802       if (!cimg::strcasecmp(ext,"dlm")) return load_dlm(filename);
    07803       if (!cimg::strcasecmp(ext,"inr")) return load_inr(filename);
    07804       if (!cimg::strcasecmp(ext,"hdr")) return load_analyze(filename);
    07805       if (!cimg::strcasecmp(ext,"pan")) return load_pandore(filename);
    07806       if (!cimg::strcasecmp(ext,"bmp")) return load_bmp(filename);
    07807       if (!cimg::strcasecmp(ext,"ppm") ||
    07808           !cimg::strcasecmp(ext,"pgm") ||
    07809           !cimg::strcasecmp(ext,"pnm")) return load_pnm(filename);
    07810       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return load_raw(filename);
    07811       return load_convert(filename);
    07812     }
    07813
    07815     static CImg load_ascii(const char *filename) {
    07816       std::FILE *file = cimg::fopen(filename,"rb");
    07817       char line[256] = {0};
    07818       std::fscanf(file,"%255[^\n]",line);
    07819       unsigned int off;
    07820           int err=1, dx=0, dy=1, dz=1, dv=1;
    07821       std::sscanf(line,"%d %d %d %d",&dx,&dy,&dz,&dv);
    07822       if (!dx || !dy || !dz || !dv)
    07823         throw CImgIOException("CImg<%s>::load_ascii() : File '%s' does not appear to be a valid ASC file.\n"
    07824                               "Specified image dimensions are (%d,%d,%d,%d)",pixel_type(),filename,dx,dy,dz,dv);
    07825       CImg dest(dx,dy,dz,dv);
    07826       double val;
    07827       T *ptr = dest.data;
    07828       for (off=0; off<dest.size() && err==1; off++) {
    07829         err = fscanf(file,"%lf%*[^0-9.eE+-]",&val);
    07830         *(ptr++)=(T)val;
    07831       }
    07832       cimg::warn(off<dest.size(),"CImg<%s>::load_ascii() : File '%s', only %u values read, instead of %u",
    07833                  pixel_type(),filename,off,dest.size());
    07834       cimg::fclose(file);
    07835       return dest;
    07836     }
    07837
    07839     static CImg load_dlm(const char *filename) {
    07840       std::FILE *file = cimg::fopen(filename,"r");
    07841       unsigned int cdx=0,dx=0,dy=0;
    07842       double val;
    07843       char c, delimiter[256]={0}, tmp[256];
    07844       int err;
    07845       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
    07846         c=0;
    07847         if (err>0) cdx++;
    07848         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { dx = cimg::max(cdx,dx); dy++; cdx=0; }
    07849       }
    07850       if (!dx || !dy) throw CImgIOException("CImg<%s>::load_dlm() : File '%s' does not appear to be a "
    07851                                             "valid DLM file (width = %d, height = %d)\n",pixel_type(),filename,dx,dy);
    07852       std::rewind(file);
    07853       CImg<T> dest(dx,dy,1,1,0);
    07854       unsigned int x = 0, y = 0;
    07855       while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
    07856         c=0;
    07857         if (err>0) dest(x++,y) = (T)val;
    07858         if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { x=0; y++; }
    07859       }
    07860       cimg::fclose(file);
    07861       return dest;
    07862     }
    07863
    07865     static CImg load_pnm(const char *filename) {
    07866       std::FILE *file=cimg::fopen(filename,"rb");
    07867       char item[1024]={0};
    07868       unsigned int ppm_type,width,height,colormax=255;
    07869       int err;
    07870
    07871       while ((err=std::fscanf(file,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
    07872       if(std::sscanf(item," P%u",&ppm_type)!=1)
    07873         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',PPM header 'P?' not found",pixel_type(),filename);
    07874       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
    07875       if (std::sscanf(item," %u %u",&width,&height)!=2)
    07876         throw CImgIOException("CImg<%s>::load_pnm() : file '%s',WIDTH and HEIGHT not defined",pixel_type(),filename);
    07877       while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file);
    07878       std::fgetc(file);
    07879       cimg::warn(std::sscanf(item,"%u",&colormax)!=1,
    07880                  "CImg<%s>::load_pnm() : file '%s',COLORMAX not defined",pixel_type(),filename);
    07881
    07882       CImg dest;
    07883       int rval,gval,bval;
    07884
    07885       switch (ppm_type) {
    07886       case 2: { // Grey Ascii
    07887         dest = CImg<T>(width,height,1,1);
    07888         T* rdata = dest.ptr();
    07889         cimg_mapoff(dest,off) { std::fscanf(file,"%d",&rval); *(rdata++)=(T)rval; }
    07890       } break;
    07891       case 3: { // Color Ascii
    07892         dest = CImg<T>(width,height,1,3);
    07893         T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2);
    07894         cimg_mapXY(dest,x,y) {
    07895           std::fscanf(file,"%d %d %d",&rval,&gval,&bval);
    07896           *(rdata++)=(T)rval;
    07897           *(gdata++)=(T)gval;
    07898           *(bdata++)=(T)bval; }
    07899       } break;
    07900       case 5: { // Grey Binary
    07901         if (colormax<256) { // 8 bits
    07902           CImg<unsigned char> raw(width,height,1,1);
    07903           cimg::fread(raw.data,sizeof(unsigned char),width*height,file);
    07904           dest = CImg<T>(raw);
    07905         } else { // 16 bits
    07906           CImg<unsigned short> raw(width,height,1,1);
    07907           cimg::fread(raw.data,sizeof(unsigned short),width*height,file);
    07908           dest = CImg<T>(raw);
    07909         }
    07910       } break;
    07911       case 6: { // Color Binary
    07912         if (colormax<256) { // 8 bits
    07913           CImg<unsigned char> raw(width,height,1,3);
    07914           cimg::fread(raw.data,sizeof(unsigned char),width*height*3,file);
    07915           dest = CImg<T>(raw.data,width,height,1,3,true);
    07916         } else { // 16 bits
    07917           CImg<unsigned short> raw(width,height,1,3);
    07918           cimg::fread(raw.data,sizeof(unsigned short),width*height*3,file);
    07919           dest = CImg<T>(raw.data,width,height,1,3,true);
    07920         }
    07921       } break;
    07922       default:
    07923         cimg::fclose(file);
    07924         throw CImgIOException("CImg<%s>::load_pnm() : file '%s', PPM type 'P%d' not supported",pixel_type(),filename,ppm_type);
    07925       }
    07926       cimg::fclose(file);
    07927       return dest;
    07928     }
    07929
    07931     static CImg load_bmp(const char *filename) {
    07932       unsigned char header[64];
    07933       std::FILE *file = cimg::fopen(filename,"rb");
    07934       cimg::fread(header,sizeof(unsigned char),54,file);
    07935       if (header[0]!='B' || header[1]!='M')
    07936         throw CImgIOException("CImg<%s>::load_bmp() : filename '%s' does not appear to be a valid BMP file",
    07937                               pixel_type(),filename);
    07938
    07939       // Read header and pixel buffer
    07940       int
    07941         file_size   = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
    07942         offset      = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
    07943         dx          = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
    07944         dy          = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
    07945         compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
    07946         nb_colors   = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
    07947         bpp         = header[0x1C] + (header[0x1D]<<8),
    07948         *palette    = NULL;
    07949       const int
    07950         dx_bytes   = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
    07951         align      = (4-dx_bytes%4)%4,
    07952         buf_size   = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
    07953
    07954       if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors=0;
    07955       if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,sizeof(int),nb_colors,file); }
    07956       const int xoffset = offset-54-4*nb_colors;
    07957       if (xoffset>0) std::fseek(file,xoffset,SEEK_CUR);
    07958       const unsigned char *buffer  = new unsigned char[buf_size], *ptrs = buffer;
    07959       cimg::fread(buffer,sizeof(unsigned char),buf_size,file);
    07960       cimg::fclose(file);
    07961
    07962       // Decompress buffer (if necessary)
    07963       if (compression) return load_convert(filename);
    07964
    07965       // Read pixel data
    07966       CImg res(dx,cimg::abs(dy),1,3);
    07967       switch (bpp) {
    07968       case 1: { // Monochrome
    07969         for (int y=res.height-1; y>=0; y--) {
    07970           unsigned char mask = 0x80, val = 0;
    07971           cimg_mapX(res,x) {
    07972             if (mask==0x80) val = *(ptrs++);
    07973             const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
    07974             res(x,y,2) = (T)*(col++);
    07975             res(x,y,1) = (T)*(col++);
    07976             res(x,y,0) = (T)*(col++);
    07977             mask = cimg::ror(mask);
    07978           } ptrs+=align; }
    07979       } break;
    07980       case 4: { // 16 colors
    07981         for (int y=res.height-1; y>=0; y--) {
    07982           unsigned char mask = 0xF0, val = 0;
    07983           cimg_mapX(res,x) {
    07984             if (mask==0xF0) val = *(ptrs++);
    07985             const unsigned char color = (mask<16)?(val&mask):((val&mask)>>4);
    07986             unsigned char *col = (unsigned char*)(palette+color);
    07987             res(x,y,2) = (T)*(col++);
    07988             res(x,y,1) = (T)*(col++);
    07989             res(x,y,0) = (T)*(col++);
    07990             mask = cimg::ror(mask,4);
    07991           } ptrs+=align; }
    07992       } break;
    07993       case 8: { //  256 colors
    07994         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
    07995           const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
    07996           res(x,y,2) = (T)*(col++);
    07997           res(x,y,1) = (T)*(col++);
    07998           res(x,y,0) = (T)*(col++);
    07999         } ptrs+=align; }
    08000       } break;
    08001       case 16: { // 16 bits colors
    08002         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
    08003           const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
    08004           const unsigned short col = c1+(c2<<8);
    08005           res(x,y,2) = (T)(col&0x1F);
    08006           res(x,y,1) = (T)((col>>5)&0x1F);
    08007           res(x,y,0) = (T)((col>>10)&0x1F);
    08008         } ptrs+=align; }
    08009       } break;
    08010       case 24: { // 24 bits colors
    08011         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
    08012           res(x,y,2) = (T)*(ptrs++);
    08013           res(x,y,1) = (T)*(ptrs++);
    08014           res(x,y,0) = (T)*(ptrs++);
    08015         } ptrs+=align; }
    08016       } break;
    08017       case 32: { // 32 bits colors
    08018         for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) {
    08019           res(x,y,2) = (T)*(ptrs++);
    08020           res(x,y,1) = (T)*(ptrs++);
    08021           res(x,y,0) = (T)*(ptrs++);
    08022           ptrs++;
    08023         } ptrs+=align; }
    08024       } break;
    08025       }
    08026
    08027       if (palette) delete[] palette;
    08028       if (dy<0) res.flip('y');
    08029       return res;
    08030     }
    08031
    08032
    08034 #define cimg_load_inr_case(Tf,sign,pixsize,Ts)                            \
    08035   if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) {      \
    08036       Ts *xval, *val = new Ts[fopt[0]*fopt[3]];                           \
    08037       cimg_mapYZ(dest,y,z) {                                              \
    08038           cimg::fread(val,pixsize/8,fopt[0]*fopt[3],file);                \
    08039           if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]);    \
    08040           xval = val; cimg_mapX(dest,x) cimg_mapV(dest,k)                 \
    08041                           dest(x,y,z,k) = (T)*(xval++);                   \
    08042         }                                                                 \
    08043       delete[] val;                                                       \
    08044       loaded = true;                                                      \
    08045     }
    08046
    08047     static void _load_inr(std::FILE *file,int out[8],float *voxsize=NULL) {
    08048       char item[1024],tmp1[64],tmp2[64];
    08049       out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1;
    08050       std::fscanf(file,"%63s",item);
    08051       if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
    08052         throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
    08053                               "(INRIMAGE-4 identifier not found)",pixel_type());
    08054       while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
    08055         std::sscanf(item," XDIM%*[^0-9]%d",out);
    08056         std::sscanf(item," YDIM%*[^0-9]%d",out+1);
    08057         std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
    08058         std::sscanf(item," VDIM%*[^0-9]%d",out+3);
    08059         std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
    08060         if (voxsize) {
    08061           std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize);
    08062           std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1);
    08063           std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2);
    08064         }
    08065         if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
    08066         switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
    08067         case 0: break;
    08068         case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
    08069         case 1:
    08070           if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4]=0;
    08071           if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4]=1;
    08072           if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4]=2;
    08073           if (out[4]>=0) break;
    08074         default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
    08075         }
    08076       }
    08077       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
    08078         throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
    08079                               pixel_type(),out[0],out[1],out[2],out[3]);
    08080       if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",pixel_type());
    08081       if(out[6]<0) throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",pixel_type());
    08082       if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",pixel_type());
    08083     }
    08084
    08085     static CImg load_inr(const char *filename, float *voxsize = NULL) {
    08086       std::FILE *file = cimg::fopen(filename,"rb");
    08087           int fopt[8], endian=cimg::endian()?1:0;
    08088       bool loaded = false;
    08089       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
    08090       _load_inr(file,fopt,voxsize);
    08091       CImg<T> dest = CImg<T>(fopt[0],fopt[1],fopt[2],fopt[3]);
    08092       cimg_load_inr_case(0,0,8, unsigned char);
    08093       cimg_load_inr_case(0,1,8, char);
    08094       cimg_load_inr_case(0,0,16,unsigned short);
    08095       cimg_load_inr_case(0,1,16,short);
    08096       cimg_load_inr_case(0,0,32,unsigned int);
    08097       cimg_load_inr_case(0,1,32,int);
    08098       cimg_load_inr_case(1,0,32,float);
    08099       cimg_load_inr_case(1,1,32,float);
    08100       cimg_load_inr_case(1,0,64,double);
    08101       cimg_load_inr_case(1,1,64,double);
    08102       if (!loaded) throw CImgIOException("CImg<%s>::load_inr() : File '%s', can't read images of the type specified in the file",
    08103                                          pixel_type(),filename);
    08104       cimg::fclose(file);
    08105       return dest;
    08106     }
    08107
    08108 #define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype)  \
    08109   case nid: {                                                         \
    08110     cimg::fread(dims,sizeof(unsigned int),nbdim,file);                \
    08111     if (endian) cimg::endian_swap(dims,nbdim);                        \
    08112     dest = CImg<T>(nwidth,nheight,ndepth,ndim);                       \
    08113     stype *buffer = new stype[dest.size()];                           \
    08114     cimg::fread(buffer,sizeof(stype),dest.size(),file);               \
    08115     if (endian) cimg::endian_swap(buffer,dest.size());                \
    08116     T *ptrd = dest.ptr();                                             \
    08117     cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));               \
    08118     buffer-=dest.size();                                              \
    08119     delete[] buffer;                                                  \
    08120    }                                                                  \
    08121    break;
    08122
    08123     static CImg load_pandore(const char *filename) {
    08124       std::FILE *file = cimg::fopen(filename,"rb");
    08125       typedef unsigned char uchar;
    08126       typedef unsigned short ushort;
    08127       typedef unsigned int uint;
    08128       typedef unsigned long ulong;
    08129       CImg dest;
    08130       char tmp[16];
    08131       cimg::fread(tmp,sizeof(char),12,file);
    08132       if (cimg::strncasecmp("PANDORE",tmp,7))
    08133         throw CImgIOException("CImg<%s>::load_pandore() : File '%s' does not appear to be a valid PANDORE file.\n"
    08134                               "(PANDORE identifier not found)",pixel_type(),filename);
    08135       unsigned int id,dims[8];
    08136       long ptbuf[4];
    08137       cimg::fread(&id,sizeof(int),1,file);
    08138       const bool endian = (id>255);
    08139       if (endian) cimg::endian_swap(id);
    08140       cimg::fread(tmp,sizeof(char),20,file);
    08141       switch (id) {
    08142         cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
    08143         cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
    08144         cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
    08145         cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
    08146         cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
    08147         cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
    08148         cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
    08149         cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
    08150         cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
    08151       case 11: { // Region 1D
    08152         cimg::fread(dims,sizeof(unsigned int),3,file);
    08153         if (endian) cimg::endian_swap(dims,3);
    08154         dest = CImg<T>(dims[1],1,1,1);
    08155         if (dims[2]<256) {
    08156           unsigned char *buffer = new unsigned char[dest.size()];
    08157           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    08158           T *ptrd = dest.ptr();
    08159           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08160           buffer-=dest.size();
    08161           delete[] buffer;
    08162         } else {
    08163           if (dims[2]<65536) {
    08164             unsigned short *buffer = new unsigned short[dest.size()];
    08165             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    08166             if (endian) cimg::endian_swap(buffer,dest.size());
    08167             T *ptrd = dest.ptr();
    08168             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08169             buffer-=dest.size();
    08170             delete[] buffer;
    08171           } else {
    08172             unsigned long *buffer = new unsigned long[dest.size()];
    08173             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    08174             if (endian) cimg::endian_swap(buffer,dest.size());
    08175             T *ptrd = dest.ptr();
    08176             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08177             buffer-=dest.size();
    08178             delete[] buffer;
    08179           }
    08180         }
    08181       }
    08182         break;
    08183       case 12: { // Region 2D
    08184         cimg::fread(dims,sizeof(unsigned int),4,file);
    08185         if (endian) cimg::endian_swap(dims,4);
    08186         dest = CImg<T>(dims[2],dims[1],1,1);
    08187         if (dims[3]<256) {
    08188           unsigned char *buffer = new unsigned char[dest.size()];
    08189           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    08190           T *ptrd = dest.ptr();
    08191           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08192           buffer-=dest.size();
    08193           delete[] buffer;
    08194         } else {
    08195           if (dims[3]<65536) {
    08196             unsigned short *buffer = new unsigned short[dest.size()];
    08197             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    08198             if (endian) cimg::endian_swap(buffer,dest.size());
    08199             T *ptrd = dest.ptr();
    08200             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08201             buffer-=dest.size();
    08202             delete[] buffer;
    08203           } else {
    08204             unsigned long *buffer = new unsigned long[dest.size()];
    08205             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    08206             if (endian) cimg::endian_swap(buffer,dest.size());
    08207             T *ptrd = dest.ptr();
    08208             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08209             buffer-=dest.size();
    08210             delete[] buffer;
    08211           }
    08212         }
    08213       }
    08214         break;
    08215       case 13: { // Region 3D
    08216         cimg::fread(dims,sizeof(unsigned int),5,file);
    08217         if (endian) cimg::endian_swap(dims,5);
    08218         dest = CImg<T>(dims[3],dims[2],dims[1],1);
    08219         if (dims[4]<256) {
    08220           unsigned char *buffer = new unsigned char[dest.size()];
    08221           cimg::fread(buffer,sizeof(unsigned char),dest.size(),file);
    08222           T *ptrd = dest.ptr();
    08223           cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08224           buffer-=dest.size();
    08225           delete[] buffer;
    08226         } else {
    08227           if (dims[4]<65536) {
    08228             unsigned short *buffer = new unsigned short[dest.size()];
    08229             cimg::fread(buffer,sizeof(unsigned short),dest.size(),file);
    08230             if (endian) cimg::endian_swap(buffer,dest.size());
    08231             T *ptrd = dest.ptr();
    08232             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08233             buffer-=dest.size();
    08234             delete[] buffer;
    08235           } else {
    08236             unsigned long *buffer = new unsigned long[dest.size()];
    08237             cimg::fread(buffer,sizeof(unsigned long),dest.size(),file);
    08238             if (endian) cimg::endian_swap(buffer,dest.size());
    08239             T *ptrd = dest.ptr();
    08240             cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++));
    08241             buffer-=dest.size();
    08242             delete[] buffer;
    08243           }
    08244         }
    08245       }
    08246         break;
    08247         cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
    08248         cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
    08249         cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
    08250         cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
    08251         cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
    08252         cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
    08253         cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
    08254         cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
    08255         cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
    08256         cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
    08257         cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
    08258         cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
    08259         cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
    08260         cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
    08261         cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
    08262         cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
    08263         cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
    08264         cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);
    08265       case 34: // Points 1D
    08266         cimg::fread(ptbuf,sizeof(long),1,file);
    08267         if (endian) cimg::endian_swap(ptbuf,1);
    08268         dest = CImg<T>(1); dest[0]=(T)ptbuf[0];
    08269         break;
    08270       case 35: // Points 2D
    08271         cimg::fread(ptbuf,sizeof(long),2,file);
    08272         if (endian) cimg::endian_swap(ptbuf,2);
    08273         dest = CImg<T>(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0];
    08274         break;
    08275       case 36: // Points 3D
    08276         cimg::fread(ptbuf,sizeof(long),3,file);
    08277         if (endian) cimg::endian_swap(ptbuf,3);
    08278         dest = CImg<T>(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0];
    08279         break;
    08280       default:
    08281         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', can't read images with ID_type=%d",pixel_type(),filename,id);
    08282       }
    08283       return dest;
    08284     }
    08285
    08286
    08288     static CImg load_analyze(const char *filename, float *voxsize = NULL) {
    08289
    08290       // Open header and data files
    08291       std::FILE *file_header=NULL, *file=NULL;
    08292       char body[1024];
    08293       const char *ext = cimg::filename_split(filename,body);
    08294       if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"img")) {
    08295         std::sprintf(body+cimg::strlen(body),".hdr");
    08296         file_header = cimg::fopen(body,"rb");
    08297         std::sprintf(body+cimg::strlen(body)-3,"img");
    08298         file = cimg::fopen(body,"rb");
    08299       } else throw CImgIOException("CImg<%s>::load_analyze() : Cannot load filename '%s' as an analyze format",pixel_type(),filename);
    08300
    08301       // Read header
    08302       bool endian = false;
    08303       unsigned int header_size;
    08304       cimg::fread(&header_size,sizeof(int),1,file_header);
    08305       if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); }
    08306       unsigned char *header = new unsigned char[header_size];
    08307       cimg::fread(header+sizeof(int),sizeof(char),header_size-sizeof(int),file_header);
    08308       cimg::fclose(file_header);
    08309       if (endian) {
    08310         cimg::endian_swap((short*)(header+40),5);
    08311         cimg::endian_swap((short*)(header+70),1);
    08312         cimg::endian_swap((short*)(header+72),1);
    08313         cimg::endian_swap((float*)(header+76),4);
    08314         cimg::endian_swap((float*)(header+112),1);
    08315       }
    08316       unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1;
    08317       cimg::warn(!dim[0],"CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type());
    08318       cimg::warn(dim[0]>4,"CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions",
    08319                  pixel_type(),dim[0]);
    08320       if (dim[0]>=1) dimx = dim[1];
    08321       if (dim[0]>=2) dimy = dim[2];
    08322       if (dim[0]>=3) dimz = dim[3];
    08323       if (dim[0]>=4) dimv = dim[4];
    08324
    08325       float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
    08326       const unsigned short datatype = *(short*)(header+70);
    08327       if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
    08328       delete[] header;
    08329
    08330       // Read pixel data
    08331       CImg dest(dimx,dimy,dimz,dimv);
    08332       switch (datatype) {
    08333       case 2: {
    08334         unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
    08335         cimg::fread(buffer,sizeof(unsigned char),dimx*dimy*dimz*dimv,file);
    08336         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    08337         delete[] buffer;
    08338       } break;
    08339       case 4: {
    08340         short *buffer = new short[dimx*dimy*dimz*dimv];
    08341         cimg::fread(buffer,sizeof(short),dimx*dimy*dimz*dimv,file);
    08342         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
    08343         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    08344         delete[] buffer;
    08345       } break;
    08346       case 8: {
    08347         int *buffer = new int[dimx*dimy*dimz*dimv];
    08348         cimg::fread(buffer,sizeof(int),dimx*dimy*dimz*dimv,file);
    08349         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
    08350         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    08351         delete[] buffer;
    08352       } break;
    08353       case 16: {
    08354         float *buffer = new float[dimx*dimy*dimz*dimv];
    08355         cimg::fread(buffer,sizeof(float),dimx*dimy*dimz*dimv,file);
    08356         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
    08357         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    08358         delete[] buffer;
    08359       } break;
    08360       case 64: {
    08361         double *buffer = new double[dimx*dimy*dimz*dimv];
    08362         cimg::fread(buffer,sizeof(double),dimx*dimy*dimz*dimv,file);
    08363         if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
    08364         cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor);
    08365         delete[] buffer;
    08366       } break;
    08367       default: throw CImgIOException("CImg<%s>::load_analyze() : Cannot read images width 'datatype = %d'",pixel_type(),datatype);
    08368       }
    08369       cimg::fclose(file);
    08370       return dest;
    08371     }
    08372
    08374     static CImg load_raw(const char *filename,const char axe='v',const char align='p') {
    08375       return CImgl<T>(filename).get_append(axe,align);
    08376     }
    08377
    08381     static CImg load_convert(const char *filename) {
    08382       srand((unsigned int)::time(NULL));
    08383       char command[512], filetmp[512];
    08384       std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),::rand()%10000);
    08385       std::sprintf(command,"\"%s\" \"%s\" %s",cimg::convert_path(),filename,filetmp);
    08386       cimg::system(command);
    08387       std::FILE *file = std::fopen(filetmp,"rb");
    08388       if (!file) {
    08389         std::fclose(cimg::fopen(filename,"r"));
    08390         throw CImgIOException("CImg<%s>::load_convert() : Failed to open image '%s' with 'convert'.\n"
    08391                               "Check that you have installed the ImageMagick package in a standart directory.",
    08392                               pixel_type(),filename);
    08393       } else cimg::fclose(file);
    08394       const CImg dest(filetmp);
    08395       std::remove(filetmp);
    08396       return dest;
    08397     }
    08398
    08399
    08401
    08406     const CImg& save(const char *filename,const int number=-1) const {
    08407       cimg_test(*this,"CImg<T>::save");
    08408       if (!filename) throw CImgArgumentException("CImg<%s>::save() : Can't save with (null) filename",pixel_type());
    08409       const char *ext = cimg::filename_split(filename);
    08410       char nfilename[1024];
    08411       if (number>=0) filename = cimg::filename_number(filename,number,6,nfilename);
    08412       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(filename);
    08413       if (!cimg::strcasecmp(ext,"dlm")) return save_dlm(filename);
    08414       if (!cimg::strcasecmp(ext,"inr")) return save_inr(filename);
    08415       if (!cimg::strcasecmp(ext,"hdr")) return save_analyze(filename);
    08416       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(filename);
    08417       if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(filename);
    08418       if (!cimg::strcasecmp(ext,"raw") || ext[0]=='\0') return save_raw(filename);
    08419       if (!cimg::strcasecmp(ext,"pgm") ||
    08420           !cimg::strcasecmp(ext,"ppm") ||
    08421           !cimg::strcasecmp(ext,"pnm")) return save_pnm(filename);
    08422       return save_convert(filename);
    08423     }
    08424
    08426     const CImg& save_ascii(const char *filename) const {
    08427       cimg_test(*this,"CImg<T>::save_ascii");
    08428       std::FILE *file = cimg::fopen(filename,"w");
    08429       std::fprintf(file,"%u %u %u %u\n",width,height,depth,dim);
    08430       const T* ptrs = data;
    08431       cimg_mapYZV(*this,y,z,v) {
    08432         cimg_mapX(*this,x) std::fprintf(file,"%g ",(double)*(ptrs++));
    08433         std::fputc('\n',file);
    08434       }
    08435       cimg::fclose(file);
    08436       return *this;
    08437     }
    08438
    08440     const CImg& save_dlm(const char *filename) const {
    08441       cimg_test(*this,"CImg<T>::save_dlm");
    08442       std::FILE *file = cimg::fopen(filename,"w");
    08443       const T* ptrs = data;
    08444       cimg_mapYZV(*this,y,z,v) {
    08445         cimg_mapX(*this,x) std::fprintf(file,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":",");
    08446         std::fputc('\n',file);
    08447       }
    08448       cimg::fclose(file);
    08449       return *this;
    08450     }
    08451
    08453     const CImg& save_pnm(const char *filename) const {
    08454       cimg_test(*this,"CImg<T>::save_pnm");
    08455       const char *ext = cimg::filename_split(filename);
    08456       const CImgStats st(*this,false);
    08457
    08458       if (dim>1 && !cimg::strcasecmp(ext,"pgm")) {
    08459                         get_norm_pointwise().normalize(0.0f,(float)st.max).save_pnm(filename);
    08460                         return *this;
    08461       }
    08462       std::FILE *file = cimg::fopen(filename,"wb");
    08463       const T
    08464         *ptrR = ptr(0,0,0,0),
    08465         *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR,
    08466         *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR;
    08467       const unsigned int buf_size = width*height*(dim==1?1:3);
    08468
    08469       std::fprintf(file,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n",
    08470                    (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535);
    08471
    08472       switch(dim) {
    08473       case 1: {
    08474         if ((st.max)<256) { // Binary PGM 8 bits
    08475           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
    08476           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
    08477           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
    08478           delete[] ptrd;
    08479         } else {             // Binary PGM 16 bits
    08480           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
    08481           cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
    08482           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
    08483           delete[] ptrd;
    08484         }
    08485       } break;
    08486       default: {
    08487         if ((st.max)<256) { // Binary PPM 8 bits
    08488           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
    08489           cimg_mapXY(*this,x,y) {
    08490             *(xptrd++) = (unsigned char)*(ptrR++);
    08491             *(xptrd++) = (unsigned char)*(ptrG++);
    08492             *(xptrd++) = (unsigned char)*(ptrB++);
    08493           }
    08494           cimg::fwrite(ptrd,sizeof(unsigned char),buf_size,file);
    08495           delete[] ptrd;
    08496         } else {             // Binary PPM 16 bits
    08497           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
    08498           cimg_mapXY(*this,x,y) {
    08499             *(xptrd++) = (unsigned short)*(ptrR++);
    08500             *(xptrd++) = (unsigned short)*(ptrG++);
    08501             *(xptrd++) = (unsigned short)*(ptrB++);
    08502           }
    08503           cimg::fwrite(ptrd,sizeof(unsigned short),buf_size,file);
    08504           delete[] ptrd;
    08505         }
    08506       } break;
    08507       }
    08508       cimg::fclose(file);
    08509
    08510       return *this;
    08511     }
    08512
    08514     const CImg& save_analyze(const char *filename,const float *const voxsize=NULL) const {
    08515       cimg_test(*this,"CImg<T>::save_analyze");
    08516       std::FILE *file;
    08517       char header[348],hname[1024],iname[1024];
    08518       const char *ext = cimg::filename_split(filename);
    08519       short datatype=-1;
    08520       std::memset(header,0,348);
    08521       if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
    08522       if (!cimg::strncasecmp(ext,"hdr",3)) {
    08523         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img");
    08524       }
    08525       if (!cimg::strncasecmp(ext,"img",3)) {
    08526         std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
    08527       }
    08528       ((int*)(header))[0] = 348;
    08529       std::sprintf(header+4,"CImg");
    08530       std::sprintf(header+14," ");
    08531       ((short*)(header+36))[0] = 4096;
    08532       ((char*)(header+38))[0] = 114;
    08533       ((short*)(header+40))[0] = 4;
    08534       ((short*)(header+40))[1] = width;
    08535       ((short*)(header+40))[2] = height;
    08536       ((short*)(header+40))[3] = depth;
    08537       ((short*)(header+40))[4] = dim;
    08538       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
    08539       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
    08540       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
    08541       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
    08542       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
    08543       ((short*)(header+70))[0] = datatype;
    08544       ((short*)(header+72))[0] = sizeof(T);
    08545       ((float*)(header+112))[0] = 1;
    08546       ((float*)(header+76))[0] = 0;
    08547       if (voxsize) {
    08548         ((float*)(header+76))[1] = voxsize[0];
    08549         ((float*)(header+76))[2] = voxsize[1];
    08550         ((float*)(header+76))[3] = voxsize[2];
    08551       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
    08552       file = cimg::fopen(hname,"wb");
    08553       cimg::fwrite(header,sizeof(char),348,file);
    08554       cimg::fclose(file);
    08555       file = cimg::fopen(iname,"wb");
    08556       cimg::fwrite(data,sizeof(T),size(),file);
    08557       cimg::fclose(file);
    08558       return *this;
    08559     }
    08560
    08562     const CImg& save_raw(const char *filename) const {
    08563       cimg_test(*this,"CImg<T>::save_raw");
    08564       CImgl<T> shared(1);
    08565       shared[0].width = width;
    08566       shared[0].height = height;
    08567       shared[0].depth = depth;
    08568       shared[0].dim = dim;
    08569       shared[0].data = data;
    08570       shared.save_raw(filename);
    08571       shared[0].width = shared[0].height = shared[0].depth = shared[0].dim = 0;
    08572       shared[0].data = NULL;
    08573       return *this;
    08574     }
    08575
    08577
    08583     const CImg& save_convert(const char *filename) const {
    08584       cimg_test(*this,"CImg<T>::save_convert");
    08585       srand((unsigned int)::time(NULL));
    08586       char command[512],filetmp[512];
    08587       std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),::rand()%10000);
    08588       save_pnm(filetmp);
    08589       std::sprintf(command,"\"%s\" -quality 100%% \"%s\" %s",cimg::convert_path(),filetmp,filename);
    08590       cimg::system(command);
    08591       std::FILE *file = std::fopen(filename,"rb");
    08592       if (!file) throw CImgIOException("CImg<%s>::save_convert() : Failed to save image '%s' with 'convert'.\n"
    08593                                        "Check that you have installed the ImageMagick package in a standart directory.",
    08594                                        pixel_type(),filename);
    08595       if (file) cimg::fclose(file);
    08596       std::remove(filetmp);
    08597       return *this;
    08598     }
    08599
    08601     const CImg& save_inr(const char *filename,const float *const voxsize = NULL) const {
    08602       cimg_test(*this,"CImg<T>::save_inr");
    08603       int inrpixsize=-1;
    08604       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
    08605       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
    08606       if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
    08607       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
    08608       if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
    08609       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
    08610       if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
    08611       if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
    08612       if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
    08613       if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",pixel_type(),pixel_type());
    08614       std::FILE *file = cimg::fopen(filename,"wb");
    08615       char header[257];
    08616       int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
    08617       if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
    08618       err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm");
    08619       std::memset(header+err,'\n',252-err);
    08620       std::memcpy(header+252,"##}\n",4);
    08621       cimg::fwrite(header,sizeof(char),256,file);
    08622       cimg_mapXYZ(*this,x,y,z) cimg_mapV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),inrpixsize,1,file);
    08623       cimg::fclose(file);
    08624       return *this;
    08625     }
    08626
    08627 #define cimg_save_pandore_case(sy,sz,sv,stype,id)                           \
    08628    if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
    08629       unsigned int *iheader = (unsigned int*)(header+12);                   \
    08630       nbdims = _save_pandore_header_length((*iheader=id),dims);             \
    08631       cimg::fwrite(header,sizeof(unsigned char),36,file);                   \
    08632       cimg::fwrite(dims,sizeof(unsigned int),nbdims,file);                  \
    08633       if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
    08634         unsigned char *buffer = new unsigned char[size()];                  \
    08635         T *ptrs = ptr();                                                    \
    08636         cimg_mapoff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++));      \
    08637         buffer-=size();                                                     \
    08638         cimg::fwrite(buffer,sizeof(unsigned char),size(),file);             \
    08639         delete[] buffer;                                                    \
    08640       }                                                                     \
    08641       if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
    08642         unsigned long *buffer = new unsigned long[size()];                  \
    08643         T *ptrs = ptr();                                                    \
    08644         cimg_mapoff(*this,off) *(buffer++)=(long)(*(ptrs++));               \
    08645         buffer-=size();                                                     \
    08646         cimg::fwrite(buffer,sizeof(long),size(),file);                      \
    08647         delete[] buffer;                                                    \
    08648       }                                                                     \
    08649       if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
    08650         float *buffer = new float[size()];                                  \
    08651         T *ptrs = ptr();                                                    \
    08652         cimg_mapoff(*this,off) *(buffer++)=(float)(*(ptrs++));              \
    08653         buffer-=size();                                                     \
    08654         cimg::fwrite(buffer,sizeof(float),size(),file);                     \
    08655         delete[] buffer;                                                    \
    08656       }                                                                     \
    08657       saved = true;                                                         \
    08658     }
    08659
    08660     unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims) const {
    08661       unsigned int nbdims=0;
    08662       if (id==2 || id==3 || id==4)    { dims[0]=1; dims[1]=width; nbdims=2; }
    08663       if (id==5 || id==6 || id==7)    { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; }
    08664       if (id==8 || id==9 || id==10)   { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
    08665       if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=1; nbdims=4; }
    08666       if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=0; nbdims=5; }
    08667       if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; }
    08668       if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; }
    08669       if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; }
    08670       return nbdims;
    08671     }
    08672
    08674     const CImg& save_pandore(const char* filename) const {
    08675       cimg_test(*this,"CImg<T>::save_pandore");
    08676       std::FILE *file = cimg::fopen(filename,"wb");
    08677       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
    08678                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,
    08679                                    '2','0','0','0','/','0','1','/','0','1',
    08680                                    0 };
    08681       unsigned int nbdims,dims[5];
    08682       bool saved=false;
    08683       cimg_save_pandore_case(1,1,1,"unsigned char",2);
    08684       cimg_save_pandore_case(1,1,1,"char",3);
    08685       cimg_save_pandore_case(1,1,1,"short",3);
    08686       cimg_save_pandore_case(1,1,1,"unsigned short",3);
    08687       cimg_save_pandore_case(1,1,1,"unsigned int",3);
    08688       cimg_save_pandore_case(1,1,1,"int",3);
    08689       cimg_save_pandore_case(1,1,1,"unsigned long",4);
    08690       cimg_save_pandore_case(1,1,1,"long",3);
    08691       cimg_save_pandore_case(1,1,1,"float",4);
    08692       cimg_save_pandore_case(1,1,1,"double",4);
    08693
    08694       cimg_save_pandore_case(0,1,1,"unsigned char",5);
    08695       cimg_save_pandore_case(0,1,1,"char",6);
    08696       cimg_save_pandore_case(0,1,1,"short",6);
    08697       cimg_save_pandore_case(0,1,1,"unsigned short",6);
    08698       cimg_save_pandore_case(0,1,1,"unsigned int",6);
    08699       cimg_save_pandore_case(0,1,1,"int",6);
    08700       cimg_save_pandore_case(0,1,1,"unsigned long",7);
    08701       cimg_save_pandore_case(0,1,1,"long",6);
    08702       cimg_save_pandore_case(0,1,1,"float",7);
    08703       cimg_save_pandore_case(0,1,1,"double",7);
    08704
    08705       cimg_save_pandore_case(0,0,1,"unsigned char",8);
    08706       cimg_save_pandore_case(0,0,1,"char",9);
    08707       cimg_save_pandore_case(0,0,1,"short",9);
    08708       cimg_save_pandore_case(0,0,1,"unsigned short",9);
    08709       cimg_save_pandore_case(0,0,1,"unsigned int",9);
    08710       cimg_save_pandore_case(0,0,1,"int",9);
    08711       cimg_save_pandore_case(0,0,1,"unsigned long",10);
    08712       cimg_save_pandore_case(0,0,1,"long",9);
    08713       cimg_save_pandore_case(0,0,1,"float",10);
    08714       cimg_save_pandore_case(0,0,1,"double",10);
    08715
    08716       cimg_save_pandore_case(0,1,3,"unsigned char",16);
    08717       cimg_save_pandore_case(0,1,3,"char",17);
    08718       cimg_save_pandore_case(0,1,3,"short",17);
    08719       cimg_save_pandore_case(0,1,3,"unsigned short",17);
    08720       cimg_save_pandore_case(0,1,3,"unsigned int",17);
    08721       cimg_save_pandore_case(0,1,3,"int",17);
    08722       cimg_save_pandore_case(0,1,3,"unsigned long",18);
    08723       cimg_save_pandore_case(0,1,3,"long",17);
    08724       cimg_save_pandore_case(0,1,3,"float",18);
    08725       cimg_save_pandore_case(0,1,3,"double",18);
    08726
    08727       cimg_save_pandore_case(0,0,3,"unsigned char",19);
    08728       cimg_save_pandore_case(0,0,3,"char",20);
    08729       cimg_save_pandore_case(0,0,3,"short",20);
    08730       cimg_save_pandore_case(0,0,3,"unsigned short",20);
    08731       cimg_save_pandore_case(0,0,3,"unsigned int",20);
    08732       cimg_save_pandore_case(0,0,3,"int",20);
    08733       cimg_save_pandore_case(0,0,3,"unsigned long",21);
    08734       cimg_save_pandore_case(0,0,3,"long",20);
    08735       cimg_save_pandore_case(0,0,3,"float",21);
    08736       cimg_save_pandore_case(0,0,3,"double",21);
    08737
    08738       cimg_save_pandore_case(1,1,0,"unsigned char",22);
    08739       cimg_save_pandore_case(1,1,0,"char",23);
    08740       cimg_save_pandore_case(1,1,0,"short",23);
    08741       cimg_save_pandore_case(1,1,0,"unsigned short",23);
    08742       cimg_save_pandore_case(1,1,0,"unsigned int",23);
    08743       cimg_save_pandore_case(1,1,0,"int",23);
    08744       cimg_save_pandore_case(1,1,0,"unsigned long",25);
    08745       cimg_save_pandore_case(1,1,0,"long",23);
    08746       cimg_save_pandore_case(1,1,0,"float",25);
    08747       cimg_save_pandore_case(1,1,0,"double",25);
    08748
    08749       cimg_save_pandore_case(0,1,0,"unsigned char",26);
    08750       cimg_save_pandore_case(0,1,0,"char",27);
    08751       cimg_save_pandore_case(0,1,0,"short",27);
    08752       cimg_save_pandore_case(0,1,0,"unsigned short",27);
    08753       cimg_save_pandore_case(0,1,0,"unsigned int",27);
    08754       cimg_save_pandore_case(0,1,0,"int",27);
    08755       cimg_save_pandore_case(0,1,0,"unsigned long",29);
    08756       cimg_save_pandore_case(0,1,0,"long",27);
    08757       cimg_save_pandore_case(0,1,0,"float",29);
    08758       cimg_save_pandore_case(0,1,0,"double",29);
    08759
    08760       cimg_save_pandore_case(0,0,0,"unsigned char",30);
    08761       cimg_save_pandore_case(0,0,0,"char",31);
    08762       cimg_save_pandore_case(0,0,0,"short",31);
    08763       cimg_save_pandore_case(0,0,0,"unsigned short",31);
    08764       cimg_save_pandore_case(0,0,0,"unsigned int",31);
    08765       cimg_save_pandore_case(0,0,0,"int",31);
    08766       cimg_save_pandore_case(0,0,0,"unsigned long",33);
    08767       cimg_save_pandore_case(0,0,0,"long",31);
    08768       cimg_save_pandore_case(0,0,0,"float",33);
    08769       cimg_save_pandore_case(0,0,0,"double",33);
    08770
    08771       cimg::fclose(file);
    08772       return *this;
    08773     }
    08774
    08776     const CImg& save_bmp(const char* filename) const {
    08777       cimg_test(*this,"CImg<T>::save_bmp");
    08778       std::FILE *file = cimg::fopen(filename,"wb");
    08779
    08780       unsigned char header[54]={0}, align_buf[4]={0};
    08781       const unsigned int
    08782         align     = (4-(3*width)%4)%4,
    08783         buf_size  = (3*width+align)*dimy(),
    08784         file_size = 54+buf_size;
    08785       header[0] = 'B'; header[1] = 'M';
    08786       header[0x02]=file_size&0xFF; header[0x03]=(file_size>>8)&0xFF;
    08787       header[0x04]=(file_size>>16)&0xFF; header[0x05]=(file_size>>24)&0xFF;
    08788       header[0x0A]=0x36;
    08789       header[0x0E]=0x28;
    08790       header[0x12]=width&0xFF; header[0x13]=(width>>8)&0xFF;
    08791       header[0x14]=(width>>16)&0xFF; header[0x15]=(width>>24)&0xFF;
    08792       header[0x16]=height&0xFF; header[0x17]=(height>>8)&0xFF;
    08793       header[0x18]=(height>>16)&0xFF; header[0x19]=(height>>24)&0xFF;
    08794       header[0x1A]=1;  header[0x1B]=0;
    08795       header[0x1C]=24; header[0x1D]=0;
    08796       header[0x22]=buf_size&0xFF; header[0x23]=(buf_size>>8)&0xFF;
    08797       header[0x24]=(buf_size>>16)&0xFF; header[0x25]=(buf_size>>24)&0xFF;
    08798       header[0x27]=0x1; header[0x2B]=0x1;
    08799       cimg::fwrite(header,sizeof(unsigned char),54,file);
    08800
    08801       const T
    08802         *pR = ptr(0,height-1,0,0),
    08803         *pG = (dim>=2)?ptr(0,height-1,0,1):pR,
    08804         *pB = (dim>=3)?ptr(0,height-1,0,2):pR;
    08805
    08806       cimg_mapY(*this,y) {
    08807         cimg_mapX(*this,x) {
    08808           std::fputc((unsigned char)(*(pB++)),file);
    08809           std::fputc((unsigned char)(*(pG++)),file);
    08810           std::fputc((unsigned char)(*(pR++)),file);
    08811         }
    08812         std::fwrite(align_buf,sizeof(unsigned char),align,file);
    08813         pR-=2*width; pG-=2*width; pB-=2*width;
    08814       }
    08815       cimg::fclose(file);
    08816       return *this;
    08817     }
    08818
    08819
    08821     //------------------------------------------
    08822     //------------------------------------------
    08823     //
    08825
    08826     //------------------------------------------
    08827     //------------------------------------------
    08828     CImg& swap(CImg& img) {
    08829       cimg::swap(width,img.width);
    08830       cimg::swap(height,img.height);
    08831       cimg::swap(depth,img.depth);
    08832       cimg::swap(dim,img.dim);
    08833       cimg::swap(data,img.data);
    08834       return img;
    08835     }
    08836
    08837 #ifdef cimg_plugin
    08838 #include cimg_plugin
    08839 #endif
    08840
    08842   };
    08843
    08844
    08845   /*-------------------------------------------------------
    08846
    08847
    08848
    08849
    08850   Definition of the CImgl<> structure
    08851
    08852
    08853
    08854
    08855   ------------------------------------------------------*/
    08856
    08858   template<typename T> struct CImgl {
    08860
    08863     unsigned int size;
    08864
    08866
    08870     CImg<T> *data;
    08871
    08872     //------------------------------------------
    08873     //------------------------------------------
    08874     //
    08876
    08877     //------------------------------------------
    08878     //------------------------------------------
    08879
    08881     static const char* pixel_type() { T val; return cimg::get_type(val); }
    08882
    08884     CImgl(const unsigned int n=0,const unsigned int width=0,const unsigned int height=1,
    08885           const unsigned int depth=1, const unsigned int dim=1):size(n) {
    08886       if (n) {
    08887         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
    08888         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim);
    08889       } else data = NULL;
    08890     }
    08891
    08893     CImgl(const unsigned int n,const unsigned int width,const unsigned int height,
    08894           const unsigned int depth, const unsigned int dim,const T& val):size(n) {
    08895       if (n) {
    08896         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
    08897         cimgl_map(*this,l) data[l]=CImg<T>(width,height,depth,dim,val);
    08898       } else data = NULL;
    08899     }
    08900
    08901     // ! Create a list of \p n copy of the input image.
    08902     template<typename t> CImgl(const unsigned int n, const CImg<t>& img):size(n) {
    08903       if (n) {
    08904         data = new CImg<T>[(n/cimg::lblock+1)*cimg::lblock];
    08905         cimgl_map(*this,l) data[l]=img;
    08906       } else data = NULL;
    08907     }
    08908
    08910     template<typename t> CImgl(const CImgl<t>& list):size(list.size) {
    08911       if (size) {
    08912         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
    08913         cimgl_map(*this,l) data[l] = list[l];
    08914       } else data = NULL;
    08915     }
    08916     CImgl(const CImgl<T>& list):size(list.size) {
    08917       if (size>0) {
    08918         data = new CImg<T>[(size/cimg::lblock+1)*cimg::lblock];
    08919         cimgl_map(*this,l) data[l] = list[l];
    08920       } else data = NULL;
    08921     }
    08922
    08924     CImgl(const char* filename):size(0),data(NULL) { load(filename).swap(*this); }
    08925
    08927     CImgl(const CImg<T>& img):size(0),data(NULL) { CImgl<T>(1,img).swap(*this); }
    08928
    08930     CImgl(const CImg<T>& img1,const CImg<T>& img2):size(2) {
    08931       data = new CImg<T>[cimg::lblock];
    08932       data[0] = img1;
    08933       data[1] = img2;
    08934     }
    08935
    08937     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3):size(3) {
    08938       data = new CImg<T>[cimg::lblock];
    08939       data[0] = img1;
    08940       data[1] = img2;
    08941       data[2] = img3;
    08942     }
    08943
    08945     CImgl(const CImg<T>& img1,const CImg<T>& img2,const CImg<T>& img3,const CImg<T>& img4):size(4) {
    08946       data = new CImg<T>[cimg::lblock];
    08947       data[0] = img1;
    08948       data[1] = img2;
    08949       data[2] = img3;
    08950       data[3] = img4;
    08951     }
    08952
    08954     template<typename t> CImgl& operator=(const CImgl<t>& list) {
    08955       if (list.size>size) return CImgl<T>(list).swap(*this);
    08956       size = list.size;
    08957       cimgl_map(*this,l) data[l] = list[l];
    08958       return *this;
    08959     }
    08960
    08961     CImgl& operator=(const CImgl<T>& list) {
    08962       if (&list==this) return *this;
    08963       if (list.size>size) return CImgl<T>(list).swap(*this);
    08964       size = list.size;
    08965       cimgl_map(*this,l) data[l] = list[l];
    08966       return *this;
    08967     }
    08968
    08970     ~CImgl() { if (data) delete[] data; }
    08971
    08973     CImgl& empty() { return CImgl<T>().swap(*this); }
    08974
    08976     //------------------------------------------
    08977     //------------------------------------------
    08978     //
    08980
    08981     //------------------------------------------
    08982     //------------------------------------------
    08983
    08985     template<typename t> CImgl& operator+=(const CImgl<t>& list) {
    08986       const unsigned int sizemax = min(size,list.size);
    08987       for (unsigned int l=0; l<sizemax; l++) (*this)[l]+=list[l];
    08988       return *this;
    08989     }
    08990
    08992     template<typename t> CImgl& operator-=(const CImgl<t>& list) {
    08993       const unsigned int sizemax = min(size,list.size);
    08994       for (unsigned int l=0; l<sizemax; l++) (*this)[l]-=list[l];
    08995       return *this;
    08996     }
    08997
    08999     CImgl& operator+=(const T& val) { cimgl_map(*this,l) (*this)[l]+=val; return *this; }
    09000
    09002     CImgl& operator-=(const T& val) { cimgl_map(*this,l) (*this)[l]-=val; return *this; }
    09003
    09005     CImgl& operator*=(const double val) { cimgl_map(*this,l) (*this)[l]*=val; return *this; }
    09006
    09008     CImgl& operator/=(const double val) { cimgl_map(*this,l) (*this)[l]/=val; return *this; }
    09009
    09011     CImgl operator+(const T& val) const { return CImgl<T>(*this)+=val;  }
    09012
    09014     CImgl operator*(const double val) const { return CImgl<T>(*this)*=val;  }
    09015
    09017     CImgl operator-(const T& val) const { return CImgl<T>(*this)-=val;  }
    09018
    09020     CImgl operator/(const double val) const { return CImgl<T>(*this)/=val;  }
    09021
    09023     CImgl operator+(const CImgl& list) const { return CImgl<T>(*this)+=list; }
    09024
    09026     CImgl operator-(const CImgl& list) const { return CImgl<T>(*this)-=list; }
    09027
    09029     friend CImgl operator+(const T& val, const CImgl& list) { return CImgl<T>(list)+=val; }
    09030
    09032     friend CImgl operator*(const double val, const CImgl& list) { return CImgl<T>(list)*=val; }
    09033
    09035     //------------------------------------------
    09036     //------------------------------------------
    09037     //
    09039
    09040     //------------------------------------------
    09041     //------------------------------------------
    09042
    09044     CImg<T>& operator[](const unsigned int pos) const {
    09045 #if cimg_debug>1
    09046       if (pos>=size) {
    09047         cimg::warn(true,"CImgl<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size);
    09048         return *data;
    09049       }
    09050 #endif
    09051       return data[pos];
    09052     }
    09053
    09055     CImg<T>& operator()(const unsigned int pos) const { return (*this)[pos]; }
    09056
    09058     CImgl& insert(const CImg<T>& img,const unsigned int pos) {
    09059       if (pos>size) throw CImgArgumentException("CImgl<%s>::insert() : Can't insert at position %u into a list with %u elements",pixel_type(),pos,size);
    09060       CImg<T> *new_data = (!((++size)%cimg::lblock) || !data)?new CImg<T>[(size/cimg::lblock+1)*cimg::lblock]:NULL;
    09061       if (!data) { data=new_data; *data=img; }
    09062       else {
    09063         if (new_data) {
    09064           std::memcpy(new_data,data,sizeof(CImg<T>)*pos);
    09065           if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
    09066           std::memset(data,0,sizeof(CImg<T>)*(size-1));
    09067           delete[] data;
    09068           data = new_data;
    09069         }
    09070         else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos));
    09071         data[pos].data = NULL;
    09072         data[pos] = img;
    09073       }
    09074       return *this;
    09075     }
    09076
    09078     CImgl& insert(const CImg<T>& img) { return insert(img,size); }
    09079
    09081     CImgl& insert(const CImgl<T>& list,const unsigned int pos) { cimgl_map(list,l) insert(list[l],pos+l); return *this; }
    09082
    09084     CImgl& insert(const CImgl<T>& list) { return insert(list,size); }
    09085
    09087     CImgl& remove(const unsigned int pos) {
    09088       if (pos>=size) {
    09089         cimg::warn(true,"CImgl<%s>::remove() : Can't remove an image from a list (%p,%u), at position %u",
    09090                    pixel_type(),data,size,pos);
    09091         return *this;
    09092       }
    09093       CImg<T> tmp; tmp.swap(data[pos]); // the image to remove will be freed
    09094       size--;
    09095       if (pos!=size) {
    09096         memmove(data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
    09097         CImg<T> &tmp = data[size];
    09098         tmp.width = tmp.height = tmp.depth = tmp.dim = 0;
    09099         tmp.data = NULL;
    09100       }
    09101       return *this;
    09102     }
    09103
    09105     CImgl& remove() {
    09106       if (size) return remove(size-1);
    09107       cimg::warn(true,"CImgl<%s>::remove() : List is empty",pixel_type());
    09108       return *this;
    09109     }
    09110
    09112     CImgl& reverse() {
    09113       for (unsigned int l=0; l<size/2; l++) (*this)[l].swap((*this)[size-1-l]);
    09114       return *this;
    09115     }
    09116
    09118     CImgl& get_reverse() { return CImgl<T>(*this).reverse(); }
    09119
    09121     //------------------------------------------
    09122     //------------------------------------------
    09123     //
    09125
    09126     //------------------------------------------
    09127     //------------------------------------------
    09128
    09130     CImgl& FFT(const char axe, const bool inverse=false) {
    09131       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
    09132       CImg<T> &Ir = data[0], &Ii = data[1];
    09133       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
    09134       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
    09135         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
    09136                                     pixel_type());
    09137       switch (cimg::uncase(axe)) {
    09138       case 'x': { // Fourier along X
    09139         const unsigned int N = Ir.width, N2 = (N>>1);
    09140         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
    09141                                                            pixel_type(),N);
    09142         for (unsigned int i=0,j=0; i<N2; i++) {
    09143           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));
    09144           if (j<N2) {
    09145             const unsigned int ri = N-1-i, rj = N-1-j;
    09146             cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
    09147           }}
    09148           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
    09149         }
    09150         for (unsigned int delta=2; delta<=N; delta<<=1) {
    09151           const unsigned int delta2 = (delta>>1);
    09152           for (unsigned int i=0; i<N; i+=delta) {
    09153             float wr = 1, wi = 0;
    09154             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
    09155                         ca = (float)std::cos(angle),
    09156                         sa = (float)std::sin(angle);
    09157             for (unsigned int k=0; k<delta2; k++) {
    09158               const unsigned int j = i + k, nj = j + delta2;
    09159               cimg_mapYZV(Ir,y,z,k) {
    09160                 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);
    09161                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
    09162                 nir = ir - tmpr; nii = ii - tmpi;
    09163                 ir += tmpr; ii += tmpi;
    09164               }
    09165               const float nwr = wr*ca-wi*sa;
    09166               wi = wi*ca + wr*sa;
    09167               wr = nwr;
    09168             }
    09169           }
    09170         }
    09171         if (inverse) (*this)/=N;
    09172       } break;
    09173
    09174       case 'y': { // Fourier along Y
    09175         const unsigned int N = Ir.height, N2 = (N>>1);
    09176         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
    09177                                                            pixel_type(),N);
    09178         for (unsigned int i=0,j=0; i<N2; i++) {
    09179           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));
    09180           if (j<N2) {
    09181             const unsigned int ri = N-1-i, rj = N-1-j;
    09182             cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
    09183           }}
    09184           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
    09185         }
    09186         for (unsigned int delta=2; delta<=N; delta<<=1) {
    09187           const unsigned int delta2 = (delta>>1);
    09188           for (unsigned int i=0; i<N; i+=delta) {
    09189             float wr = 1, wi = 0;
    09190             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
    09191                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
    09192             for (unsigned int k=0; k<delta2; k++) {
    09193               const unsigned int j = i + k, nj = j + delta2;
    09194               cimg_mapXZV(Ir,x,z,k) {
    09195                 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);
    09196                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
    09197                 nir = ir - tmpr; nii = ii - tmpi;
    09198                 ir += tmpr; ii += tmpi;
    09199               }
    09200               const float nwr = wr*ca-wi*sa;
    09201               wi = wi*ca + wr*sa;
    09202               wr = nwr;
    09203             }
    09204           }
    09205         }
    09206         if (inverse) (*this)/=N;
    09207       } break;
    09208
    09209       case 'z': { // Fourier along Z
    09210         const unsigned int N = Ir.depth, N2 = (N>>1);
    09211         if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
    09212                                                            pixel_type(),N);
    09213         for (unsigned int i=0,j=0; i<N2; i++) {
    09214           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));
    09215           if (j<N2) {
    09216             const unsigned int ri = N-1-i, rj = N-1-j;
    09217             cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
    09218           }}
    09219           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
    09220         }
    09221         for (unsigned int delta=2; delta<=N; delta<<=1) {
    09222           const unsigned int delta2 = (delta>>1);
    09223           for (unsigned int i=0; i<N; i+=delta) {
    09224             float wr = 1, wi = 0;
    09225             const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
    09226                         ca = (float)std::cos(angle), sa = (float)std::sin(angle);
    09227             for (unsigned int k=0; k<delta2; k++) {
    09228               const unsigned int j = i + k, nj = j + delta2;
    09229               cimg_mapXYV(Ir,x,y,k) {
    09230                 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);
    09231                 const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir;
    09232                 nir = ir - tmpr; nii = ii - tmpi;
    09233                 ir += tmpr; ii += tmpi;
    09234               }
    09235               const float nwr = wr*ca-wi*sa;
    09236               wi = wi*ca + wr*sa;
    09237               wr = nwr;
    09238             }
    09239           }
    09240         }
    09241         if (inverse) (*this)/=N;
    09242       } break;
    09243
    09244       default: throw CImgArgumentException("CImg<%s>::FFT() : unknown axe '%c', must be 'x','y' or 'z'");
    09245       }
    09246       return *this;
    09247     }
    09248
    09250     CImgl& FFT(const bool inverse=false) {
    09251       if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type());
    09252       CImg<T> &Ir = data[0], &Ii = data[1];
    09253       cimg_test(Ir,"CImg<T>::FFT"); cimg_test(Ii,"CImg<T>::FFT");
    09254       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
    09255         throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",
    09256                                     pixel_type());
    09257       if (Ir.depth>1)  FFT('z',inverse);
    09258       if (Ir.height>1) FFT('y',inverse);
    09259       if (Ir.width>1)  FFT('x',inverse);
    09260       return *this;
    09261     }
    09262
    09264     CImgl get_FFT(const bool inverse=false) const { return CImgl<T>(*this).FFT(inverse); }
    09265
    09267     CImgl get_FFT(const char axe,const bool inverse=false) const { return CImgl<T>(*this).FFT(axe,inverse); }
    09268
    09270     //------------------------------------------
    09271     //------------------------------------------
    09272     //
    09274
    09275     //------------------------------------------
    09276     //------------------------------------------
    09277
    09279     const CImgl& print(const char* title=NULL,const int print_flag=1) const {
    09280       char tmp[1024];
    09281       std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p }\n",title?title:"CImgl",(void*)this,size,(void*)data);
    09282       if (print_flag>0) cimgl_map(*this,l) {
    09283         std::sprintf(tmp,"%s[%d]",title?title:"CImgl",l);
    09284         data[l].print(tmp,print_flag);
    09285       }
    09286       return *this;
    09287     }
    09289 #define cimg_load_raw_case(Ts,Tss)                                               \
    09290   if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l<n; l++) {  \
    09291       Tss *buf;                                                         \
    09292       const bool endian = cimg::endian();                               \
    09293       j=0; while((i=fgetc(file))!='\n') tmp[j++]=(char)i; tmp[j]='\0';  \
    09294       std::sscanf(tmp,"%u %u %u %u",&w,&h,&z,&k);                       \
    09295       buf = new Tss[w*h*z*k]; cimg::fread(buf,sizeof(Tss),w*h*z*k,file);\
    09296       if (endian) cimg::endian_swap(buf,w*h*z*k);                       \
    09297       CImg<T> idest(w,h,z,k); cimg_mapoff(idest,off)                    \
    09298                         idest[off] = (T)(buf[off]); idest.swap(res[l]); \
    09299       delete[] buf;                                                     \
    09300       loaded = true;                                                    \
    09301     }
    09302
    09303     static CImgl load_raw(const char *filename) {
    09304       typedef unsigned char uchar;
    09305       typedef unsigned short ushort;
    09306       typedef unsigned int uint;
    09307       typedef unsigned long ulong;
    09308       std::FILE *file = cimg::fopen(filename,"rb");
    09309       char tmp[256],tmp2[256];
    09310       int i;
    09311       bool loaded = false;
    09312       unsigned int n,j,w,h,z,k,err;
    09313       j=0; while((i=fgetc(file))!='\n' && i!=EOF) tmp[j++]=i; tmp[j]='\0';
    09314       err=std::sscanf(tmp,"%u#%255[A-Za-z ]",&n,tmp2);
    09315       if (err!=2) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', Unknow .raw header",pixel_type(),filename);
    09316       CImgl<T> res(n);
    09317       cimg_load_raw_case("unsigned char",uchar);
    09318       cimg_load_raw_case("uchar",uchar);
    09319       cimg_load_raw_case("char",char);
    09320       cimg_load_raw_case("unsigned short",ushort);
    09321       cimg_load_raw_case("ushort",ushort);
    09322       cimg_load_raw_case("short",short);
    09323       cimg_load_raw_case("unsigned int",uint);
    09324       cimg_load_raw_case("uint",uint);
    09325       cimg_load_raw_case("int",int);
    09326       cimg_load_raw_case("unsigned long",ulong);
    09327       cimg_load_raw_case("ulong",ulong);
    09328       cimg_load_raw_case("long",long);
    09329       cimg_load_raw_case("float",float);
    09330       cimg_load_raw_case("double",double);
    09331       if (!loaded) throw CImgIOException("CImgl<%s>::load_raw() : file '%s', can't read images of %s",pixel_type(),filename,tmp2);
    09332       cimg::fclose(file);
    09333       return res;
    09334     }
    09335
    09337     static CImgl load(const char *filename) {
    09338       CImgl res;
    09339       const char *ext = cimg::filename_split(filename);
    09340       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return load_raw(filename); else return CImg<T>(filename);
    09341     }
    09342
    09343
    09345
    09348     const CImgl& save(const char *filename) const {
    09349       cimgl_test(*this,"CImgl<T>::save");
    09350       const char *ext = cimg::filename_split(filename);
    09351       if (!cimg::strcasecmp(ext,"raw") || !ext[0]) return save_raw(filename);
    09352       else {
    09353         if (size==1) data[0].save(filename,-1);
    09354         else cimgl_map(*this,l) data[l].save(filename,l);
    09355       }
    09356       return *this;
    09357     }
    09358
    09360
    09365     const CImgl& save_raw(const char *filename) const {
    09366       cimgl_test(*this,"CImgl<T>::save_raw");
    09367       std::FILE *file = cimg::fopen(filename,"wb");
    09368       std::fprintf(file,"%u#%s\n",size,pixel_type());
    09369       cimgl_map(*this,l) {
    09370         const CImg<T>& img = data[l];
    09371         std::fprintf(file,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim);
    09372         if (cimg::endian()) {
    09373           CImg<T> tmp(img);
    09374           cimg::endian_swap(tmp.data,tmp.size());
    09375           cimg::fwrite(tmp.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
    09376         } else cimg::fwrite(img.data,sizeof(T),img.width*img.height*img.depth*img.dim,file);
    09377       }
    09378       cimg::fclose(file);
    09379       return *this;
    09380     }
    09381
    09383
    09388     CImg<T> get_append(const char axe='x',const char align='c') const {
    09389       cimgl_test(*this,"CImgl<T>::get_append");
    09390       unsigned int dx=0,dy=0,dz=0,dv=0,pos=0;
    09391       CImg<T> res;
    09392       switch(cimg::uncase(axe)) {
    09393       case 'x': {
    09394         cimgl_map(*this,l) {
    09395           const CImg<T>& img = (*this)[l];
    09396           dx += img.width;
    09397           dy = cimg::max(dy,img.height);
    09398           dz = cimg::max(dz,img.depth);
    09399           dv = cimg::max(dv,img.dim);
    09400         }
    09401         res = CImg<T>(dx,dy,dz,dv,0);
    09402         switch (cimg::uncase(align)) {
    09403         case 'p' : { cimgl_map(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break;
    09404         case 'n' : { cimgl_map(*this,ll) {
    09405               res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width;
    09406             }} break;
    09407         default  : { cimgl_map(*this,ll) {
    09408               res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
    09409               pos+=(*this)[ll].width;
    09410             }} break;
    09411         }
    09412       } break;
    09413       case 'y': {
    09414         cimgl_map(*this,l) {
    09415           const CImg<T>& img = (*this)[l];
    09416           dx = cimg::max(dx,img.width);
    09417           dy += img.height;
    09418           dz = cimg::max(dz,img.depth);
    09419           dv = cimg::max(dv,img.dim);
    09420         }
    09421         res = CImg<T>(dx,dy,dz,dv,0);
    09422         switch (cimg::uncase(align)) {
    09423         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break;
    09424         case 'n': { cimgl_map(*this,ll) {
    09425               res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height;
    09426             }} break;
    09427         default : { cimgl_map(*this,ll) {
    09428               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2);
    09429               pos+=(*this)[ll].height;
    09430             }} break;
    09431         }
    09432       } break;
    09433       case 'z': {
    09434         cimgl_map(*this,l) {
    09435           const CImg<T>& img = (*this)[l];
    09436           dx = cimg::max(dx,img.width);
    09437           dy = cimg::max(dy,img.height);
    09438           dz += img.depth;
    09439           dv = cimg::max(dv,img.dim);
    09440         }
    09441         res = CImg<T>(dx,dy,dz,dv,0);
    09442         switch (cimg::uncase(align)) {
    09443         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break;
    09444         case 'n': { cimgl_map(*this,ll) {
    09445               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth;
    09446             }} break;
    09447         case 'c': { cimgl_map(*this,ll) {
    09448               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2);
    09449               pos+=(*this)[ll].depth;
    09450             }} break;
    09451         }
    09452       } break;
    09453       case 'v': {
    09454         cimgl_map(*this,l) {
    09455           const CImg<T>& img = (*this)[l];
    09456           dx = cimg::max(dx,img.width);
    09457           dy = cimg::max(dy,img.height);
    09458           dz = cimg::max(dz,img.depth);
    09459           dv += img.dim;
    09460         }
    09461         res = CImg<T>(dx,dy,dz,dv,0);
    09462         switch (cimg::uncase(align)) {
    09463         case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break;
    09464         case 'n': { cimgl_map(*this,ll) {
    09465               res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim;
    09466             }} break;
    09467         case 'c': { cimgl_map(*this,ll) {
    09468               res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos);
    09469               pos+=(*this)[ll].dim;
    09470             }} break;
    09471         }
    09472       } break;
    09473       default: throw CImgArgumentException("CImg<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
    09474       }
    09475       return res;
    09476     }
    09477
    09478     // Create an auto-cropped font (along the X axis) from a input font \p font.
    09479     static CImgl<T> get_cropfont(const CImgl<T>& font,const unsigned int padding=2) {
    09480       CImgl<T> res;
    09481       cimgl_map(font,l) {
    09482         int xmin=font[l].width, xmax = 0;
    09483         cimg_mapXY(font[l],x,y) if (font[l](x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
    09484         if (xmin>xmax) res.insert(font[l]);
    09485         else {
    09486           res.insert(CImg<T>(xmax-xmin+1+padding,font[l].height,1,font[l].dim,0));
    09487           cimg_mapYV(res[l],y,k) for (int x=xmin; x<=xmax; x++) res[l](x-xmin,y,0,k) = font[l](x,y,0,k);
    09488         }
    09489       }
    09490       return res;
    09491     }
    09492
    09494
    09497     static CImgl<T> get_font7x11(const bool fixed_size = false) {
    09498       CImgl<T> font(32,1,1,1,3);
    09499       font.insert(CImgl<T>(224,7,11,1,3)).insert(CImgl<T>(32,1,1,1,1)).insert(CImgl<T>(224,7,11,1,1));
    09500       for (unsigned int i=0, off=0, boff=(unsigned int)(1<<31); i<256; i++) for (unsigned int j=0; j<font[i].width*font[i].height; j++) {
    09501         font[256+i](j) = font[i](j,0,0) = font[i](j,0,1) = font[i](j,0,2) = (cimg::font7x11[off]&boff)?(T)1:(T)0;
    09502         if (!(boff>>=1)) { boff=(unsigned int)(1<<31); off++; }
    09503       }
    09504       if (!fixed_size) return get_cropfont(font,2);
    09505       return font;
    09506     }
    09507
    09509
    09518     const CImgl& display(CImgDisplay& disp,const char axe='x',const char align='c') const {
    09519       get_append(axe,align).display(disp); return *this;
    09520     }
    09521
    09523
    09532     const CImgl& display(CImgDisplay* disp,const char axe='x',const char align='c') const {
    09533       if (!disp) throw CImgArgumentException("CImgl<%s>::display() : given display pointer is (null)",pixel_type());
    09534       else display(*disp,axe,align);
    09535       return *this;
    09536     }
    09537
    09539
    09552     const CImgl& display(const char* title,const char axe='x',const char align='c',
    09553                          const int min_size=128,const int max_size=1024) const {
    09554       get_append(axe,align).display(title,min_size,max_size);
    09555       return *this;
    09556     }
    09557
    09559
    09571     const CImgl& display(const char axe='x',const char align='c',
    09572                          const int min_size=128,const int max_size=1024) const {
    09573       return display("",axe,align,min_size,max_size);
    09574     }
    09575
    09577
    09580     const CImgl& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this;  }
    09581
    09582     // Swap fields of two CImgl instances.
    09583     CImgl& swap(CImgl& list) {
    09584       cimg::swap(size,list.size);
    09585       cimg::swap(data,list.data);
    09586       return list;
    09587     }
    09588
    09589 #ifdef cimgl_plugin
    09590 #include cimgl_plugin
    09591 #endif
    09592
    09594   };
    09595
    09596
    09598
    09604   template<typename T> struct CImgROI : public CImg<T> {
    09605     CImgROI(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,T *const pdata) {
    09606       CImg<T>::width = dx; CImg<T>::height = dy; CImg<T>::depth = dz; CImg<T>::dim = dv; CImg<T>::data = pdata;
    09607     }
    09608     CImgROI(const CImgROI& roi) {
    09609       CImg<T>::width = roi.width; CImg<T>::height = roi.height; CImg<T>::depth = roi.depth; CImg<T>::dim = roi.dim;
    09610       CImg<T>::data = roi.data;
    09611     }
    09612     ~CImgROI() { CImg<T>::width=CImg<T>::height=CImg<T>::depth=CImg<T>::dim=0; CImg<T>::data=NULL;}
    09613   };
    09614
    09615 }
    09616
    09617 // Overcome VisualC++ 6.0 and DMC compilers namespace bug
    09618 #if ( defined(_MSC_VER) || defined(__DMC__) ) && defined(std)
    09619 #undef std
    09620 #endif
    09621
    09622 /*--------------------------------------------------------------------------------------
    09623
    09624
    09625
    09626   Additional documentation for the generation of the reference page (using doxygen)
    09627
    09628
    09629
    09630   -------------------------------------------------------------------------------------*/
    09649 //---------------------------------------------------------------------------------------------------------------
    09651
    09791
    09792 //--------------------------------------------------------------------------------------------------------------------
    09794
    09871
    09872 //--------------------------------------------------------------------------------------------------------------------
    09874
    09972
    09973 //----------------------------------------------------------------------------------------------------
    09975
    09997
    09998 //----------------------------------------------------------------------------------------------------
    10000
    10236
    10237 //----------------------------------------------------------------------------------------------------
    10239
    10260
    10261
    10262 //----------------------------------------------------------------------------------------------------
    10264
    10270
    10271
    10272
    10273
    10274 //----------------------------------------------------------------------------------------------------
    10276
    10293
    10294 //----------------------------------------------------------------------------------------------------
    10296
    10382 //----------------------------------------------------------------------------------------------------
    10383 #endif
    10384
    10385 // Local Variables:
    10386 // mode: c++
    10387 // End: