PTdecode/CImg-1.3.0/CImg.h

Tue, 18 Mar 2014 01:27:15 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 18 Mar 2014 01:27:15 +0000
changeset 23
f2c7acb4a258
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

Update PTdecode to handle output from other Ptouch drivers

     1 /*
     2  #
     3  #  File            : CImg.h
     4  #                    ( C++ header file )
     5  #
     6  #  Description     : The C++ Template Image Processing Library.
     7  #                    This file is the main part of the CImg Library project.
     8  #                    ( http://cimg.sourceforge.net )
     9  #
    10  #  Project manager : David Tschumperle.
    11  #                    ( http://www.greyc.ensicaen.fr/~dtschump/ )
    12  #
    13  #                    The complete contributor list can be seen in the 'README.txt' file.
    14  #
    15  #  Licenses        : This file is "dual-licensed", you have to choose one
    16  #                    of the two licenses below to apply on this file.
    17  #
    18  #                    CeCILL-C
    19  #                    The CeCILL-C license is close to the GNU LGPL.
    20  #                    ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
    21  #
    22  #                or  CeCILL v2.0
    23  #                    The CeCILL license is compatible with the GNU GPL.
    24  #                    ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    25  #
    26  #  This software is governed either by the CeCILL or the CeCILL-C license
    27  #  under French law and abiding by the rules of distribution of free software.
    28  #  You can  use, modify and or redistribute the software under the terms of
    29  #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
    30  #  at the following URL : "http://www.cecill.info".
    31  #
    32  #  As a counterpart to the access to the source code and  rights to copy,
    33  #  modify and redistribute granted by the license, users are provided only
    34  #  with a limited warranty  and the software's author,  the holder of the
    35  #  economic rights,  and the successive licensors  have only  limited
    36  #  liability.
    37  #
    38  #  In this respect, the user's attention is drawn to the risks associated
    39  #  with loading,  using,  modifying and/or developing or reproducing the
    40  #  software by the user in light of its specific status of free software,
    41  #  that may mean  that it is complicated to manipulate,  and  that  also
    42  #  therefore means  that it is reserved for developers  and  experienced
    43  #  professionals having in-depth computer knowledge. Users are therefore
    44  #  encouraged to load and test the software's suitability as regards their
    45  #  requirements in conditions enabling the security of their systems and/or
    46  #  data to be ensured and,  more generally, to use and operate it in the
    47  #  same conditions as regards security.
    48  #
    49  #  The fact that you are presently reading this means that you have had
    50  #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
    51  #
    52 */
    54 // Define version number of the current file.
    55 //
    56 #ifndef cimg_version
    57 #define cimg_version 130
    59 /*-----------------------------------------------------------
    60  #
    61  # Test/auto-set CImg configuration variables
    62  # and include required headers.
    63  #
    64  # If you find that default configuration variables are
    65  # not adapted, you can override their values before including
    66  # the header file "CImg.h" (using the #define directive).
    67  #
    68  ------------------------------------------------------------*/
    70 // Include required standard C++ headers.
    71 //
    72 #include <cstdio>
    73 #include <cstdlib>
    74 #include <cstdarg>
    75 #include <cstring>
    76 #include <cmath>
    77 #include <ctime>
    79 // Operating system configuration.
    80 //
    81 // Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
    82 //                       1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
    83 //                       2 for Microsoft Windows.
    84 //
    85 #ifndef cimg_OS
    86 #if defined(unix)        || defined(__unix)      || defined(__unix__) \
    87  || defined(linux)       || defined(__linux)     || defined(__linux__) \
    88  || defined(sun)         || defined(__sun) \
    89  || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
    90  || defined(__FreeBSD__) || defined __DragonFly__ \
    91  || defined(sgi)         || defined(__sgi) \
    92  || defined(__MACOSX__)  || defined(__APPLE__) \
    93  || defined(__CYGWIN__)
    94 #define cimg_OS 1
    95 #elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
    96    || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
    97 #define cimg_OS 2
    98 #else
    99 #define cimg_OS 0
   100 #endif
   101 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
   102 #error CImg Library : Configuration variable 'cimg_OS' is badly defined.
   103 #error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
   104 #endif
   106 // Compiler configuration.
   107 //
   108 // Try to detect Microsoft VC++ compilers.
   109 // (lot of workarounds are needed afterwards to
   110 // make CImg working, particularly with VC++ 6.0).
   111 //
   112 #ifdef _MSC_VER
   113 #pragma warning(push)
   114 #pragma warning(disable:4311)
   115 #pragma warning(disable:4312)
   116 #pragma warning(disable:4800)
   117 #pragma warning(disable:4804)
   118 #pragma warning(disable:4996)
   119 #define _CRT_SECURE_NO_DEPRECATE 1
   120 #define _CRT_NONSTDC_NO_DEPRECATE 1
   121 #if _MSC_VER<1300
   122 #define cimg_use_visualcpp6
   123 #define cimg_std
   124 #define _WIN32_WINNT 0x0500
   125 #endif
   126 #endif
   128 // Include OS-specific headers.
   129 //
   130 #if cimg_OS==1
   131 #include <sys/time.h>
   132 #include <unistd.h>
   133 #elif cimg_OS==2
   134 #include <windows.h>
   135 #ifndef _WIN32_IE
   136 #define _WIN32_IE 0x0400
   137 #endif
   138 #include <shlobj.h>
   139 #endif
   141 // Define defaut pipe for output messages
   142 //
   143 // Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
   144 //                           stderr to print CImg messages on the standart error output (default behavior).
   145 //
   146 #ifndef cimg_std
   147 #define cimg_std std
   148 #endif
   149 #ifndef cimg_stdout
   150 #define cimg_stdout stderr
   151 #endif
   153 // Output messages configuration.
   154 //
   155 // Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
   156 //                          1 to display debug messages on the console.
   157 //                          2 to display debug messages with dialog windows (default behavior).
   158 //                          3 to do as 1 + add extra warnings (may slow down the code !).
   159 //                          4 to do as 2 + add extra warnings (may slow down the code !).
   160 //
   161 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
   162 //
   163 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
   164 //
   165 #ifndef cimg_debug
   166 #define cimg_debug 2
   167 #elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
   168 #error CImg Library : Configuration variable 'cimg_debug' is badly defined.
   169 #error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
   170 #endif
   172 // Display framework configuration.
   173 //
   174 // Define 'cimg_display' to : 0 to disable display capabilities.
   175 //                            1 to use X-Window framework (X11).
   176 //                            2 to use Microsoft GDI32 framework.
   177 //                            3 to use Apple Carbon framework.
   178 //
   179 #ifndef cimg_display
   180 #if cimg_OS==0
   181 #define cimg_display 0
   182 #elif cimg_OS==1
   183 #if defined(__MACOSX__) || defined(__APPLE__)
   184 #define cimg_display 1
   185 #else
   186 #define cimg_display 1
   187 #endif
   188 #elif cimg_OS==2
   189 #define cimg_display 2
   190 #endif
   191 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
   192 #error CImg Library : Configuration variable 'cimg_display' is badly defined.
   193 #error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
   194 #endif
   196 // Include display-specific headers.
   197 //
   198 #if cimg_display==1
   199 #include <X11/Xlib.h>
   200 #include <X11/Xutil.h>
   201 #include <X11/keysym.h>
   202 #include <pthread.h>
   203 #ifdef cimg_use_xshm
   204 #include <sys/ipc.h>
   205 #include <sys/shm.h>
   206 #include <X11/extensions/XShm.h>
   207 #endif
   208 #ifdef cimg_use_xrandr
   209 #include <X11/extensions/Xrandr.h>
   210 #endif
   211 #elif cimg_display==3
   212 #include <Carbon/Carbon.h>
   213 #include <pthread.h>
   214 #endif
   216 // OpenMP configuration.
   217 // (http://www.openmp.org)
   218 //
   219 // Define 'cimg_use_openmp' to enable OpenMP support.
   220 //
   221 // OpenMP directives can be used in few CImg functions to get
   222 // advantages of multi-core CPUs. Using OpenMP is not mandatory.
   223 //
   224 #ifdef cimg_use_openmp
   225 #include "omp.h"
   226 #endif
   228 // LibPNG configuration.
   229 // (http://www.libpng.org)
   230 //
   231 // Define 'cimg_use_png' to enable LibPNG support.
   232 //
   233 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
   234 // to get a builtin support of PNG files. Using LibPNG is not mandatory.
   235 //
   236 #ifdef cimg_use_png
   237 extern "C" {
   238 #include "png.h"
   239 }
   240 #endif
   242 // LibJPEG configuration.
   243 // (http://en.wikipedia.org/wiki/Libjpeg)
   244 //
   245 // Define 'cimg_use_jpeg' to enable LibJPEG support.
   246 //
   247 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
   248 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
   249 //
   250 #ifdef cimg_use_jpeg
   251 extern "C" {
   252 #include "jpeglib.h"
   253 }
   254 #endif
   256 // LibTIFF configuration.
   257 // (http://www.libtiff.org)
   258 //
   259 // Define 'cimg_use_tiff' to enable LibTIFF support.
   260 //
   261 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
   262 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
   263 //
   264 #ifdef cimg_use_tiff
   265 extern "C" {
   266 #include "tiffio.h"
   267 }
   268 #endif
   270 // FFMPEG Avcodec and Avformat libraries configuration.
   271 // (http://www.ffmpeg.org)
   272 //
   273 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
   274 //
   275 // Avcodec and Avformat libraries can be used in functions
   276 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin
   277 // support of various image sequences files.
   278 // Using FFMPEG libraries is not mandatory.
   279 //
   280 #ifdef cimg_use_ffmpeg
   281 extern "C" {
   282 #include "avformat.h"
   283 #include "avcodec.h"
   284 #include "swscale.h"
   285 }
   286 #endif
   288 // Zlib configuration
   289 // (http://www.zlib.net)
   290 //
   291 // Define 'cimg_use_zlib' to enable Zlib support.
   292 //
   293 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
   294 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
   295 //
   296 #ifdef cimg_use_zlib
   297 extern "C" {
   298 #include "zlib.h"
   299 }
   300 #endif
   302 // Magick++ configuration.
   303 // (http://www.imagemagick.org/Magick++)
   304 //
   305 // Define 'cimg_use_magick' to enable Magick++ support.
   306 //
   307 // Magick++ library can be used in functions 'CImg<T>::{load,save}()'
   308 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
   309 // Using Magick++ is not mandatory.
   310 //
   311 #ifdef cimg_use_magick
   312 #include "Magick++.h"
   313 #endif
   315 // FFTW3 configuration.
   316 // (http://www.fftw.org)
   317 //
   318 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
   319 //
   320 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
   321 // efficiently compile the Fast Fourier Transform of image data.
   322 //
   323 #ifdef cimg_use_fftw3
   324 extern "C" {
   325 #include "fftw3.h"
   326 }
   327 #endif
   329 // Board configuration.
   330 // (http://libboard.sourceforge.net/)
   331 //
   332 // Define 'cimg_use_board' to enable Board support.
   333 //
   334 // Board library can be used in functions 'CImg<T>::draw_object3d()'
   335 // to draw objects 3D in vector-graphics canvas that can be saved
   336 // as .PS or .SVG files afterwards.
   337 //
   338 #ifdef cimg_use_board
   339 #include "Board.h"
   340 #endif
   342 // Lapack configuration.
   343 // (http://www.netlib.org/lapack)
   344 //
   345 // Define 'cimg_use_lapack' to enable LAPACK support.
   346 //
   347 // Lapack can be used in various CImg functions dealing with
   348 // matrix computation and algorithms (eigenvalues, inverse, ...).
   349 // Using Lapack is not mandatory.
   350 //
   351 #ifdef cimg_use_lapack
   352 extern "C" {
   353   extern void sgetrf_(int*, int*, float*, int*, int*, int*);
   354   extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
   355   extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
   356   extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
   357   extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
   358   extern void dgetrf_(int*, int*, double*, int*, int*, int*);
   359   extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
   360   extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
   361   extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
   362   extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
   363 }
   364 #endif
   366 // Check if min/max macros are defined.
   367 //
   368 // CImg does not compile if macros 'min' or 'max' are defined,
   369 // because min() and max() functions are also defined in the cimg:: namespace.
   370 // so it '#undef' these macros if necessary, and restore them to reasonable
   371 // values at the end of the file.
   372 //
   373 #ifdef min
   374 #undef min
   375 #define _cimg_redefine_min
   376 #endif
   377 #ifdef max
   378 #undef max
   379 #define _cimg_redefine_max
   380 #endif
   382 // Set the current working directory for native MacOSX bundled applications.
   383 //
   384 // By default, MacOS bundled applications set the cwd at the root directory '/',
   385 // the code below allows to set it to the current exec directory instead when
   386 // a CImg-based program is executed.
   387 //
   388 #if cimg_OS==1 && cimg_display==3
   389 static struct _cimg_macosx_setcwd {
   390   _cimg_macosx_setcwd() {
   391     FSRef location;
   392     ProcessSerialNumber psn;
   393     char filePath[512];
   394     if (GetCurrentProcess(&psn)!=noErr) return;
   395     if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
   396     FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
   397     int p = cimg_std::strlen(filePath);
   398     while (filePath[p] != '/') --p;
   399     filePath[p] = 0;
   400     chdir(filePath);
   401   }
   402 } cimg_macosx_setcwd;
   403 #endif
   405 /*------------------------------------------------------------------------------
   406   #
   407   # Define user-friendly macros.
   408   #
   409   # User macros are prefixed by 'cimg_' and can be used in your own code.
   410   # They are particularly useful for option parsing, and image loops creation.
   411   #
   412   ------------------------------------------------------------------------------*/
   414 // Define the program usage, and retrieve command line arguments.
   415 //
   416 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
   417 #define cimg_help(str)    cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
   418 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
   419 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
   420 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
   421 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
   422 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
   423 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
   424 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
   425 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
   426 #define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) cimg_library::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6)
   427 #define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) cimg_library::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7)
   428 #define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) cimg_library::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8)
   430 // Define and manipulate local neighborhoods.
   431 //
   432 #define CImg_2x2(I,T) T I[4]; \
   433                       T& I##cc = I[0]; T& I##nc = I[1]; \
   434                       T& I##cn = I[2]; T& I##nn = I[3]; \
   435                       I##cc = I##nc = \
   436                       I##cn = I##nn = 0
   438 #define CImg_3x3(I,T) T I[9]; \
   439                       T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
   440                       T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
   441                       T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
   442                       I##pp = I##cp = I##np = \
   443                       I##pc = I##cc = I##nc = \
   444                       I##pn = I##cn = I##nn = 0
   446 #define CImg_4x4(I,T) T I[16]; \
   447                       T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
   448                       T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
   449                       T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
   450                       T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
   451                       I##pp = I##cp = I##np = I##ap = \
   452                       I##pc = I##cc = I##nc = I##ac = \
   453                       I##pn = I##cn = I##nn = I##an = \
   454                       I##pa = I##ca = I##na = I##aa = 0
   456 #define CImg_5x5(I,T) T I[25]; \
   457                       T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \
   458                       T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \
   459                       T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \
   460                       T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \
   461                       T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \
   462                       I##bb = I##pb = I##cb = I##nb = I##ab = \
   463                       I##bp = I##pp = I##cp = I##np = I##ap = \
   464                       I##bc = I##pc = I##cc = I##nc = I##ac = \
   465                       I##bn = I##pn = I##cn = I##nn = I##an = \
   466                       I##ba = I##pa = I##ca = I##na = I##aa = 0
   468 #define CImg_2x2x2(I,T) T I[8]; \
   469                       T& I##ccc = I[0]; T& I##ncc = I[1]; \
   470                       T& I##cnc = I[2]; T& I##nnc = I[3]; \
   471                       T& I##ccn = I[4]; T& I##ncn = I[5]; \
   472                       T& I##cnn = I[6]; T& I##nnn = I[7]; \
   473                       I##ccc = I##ncc = \
   474                       I##cnc = I##nnc = \
   475                       I##ccn = I##ncn = \
   476                       I##cnn = I##nnn = 0
   478 #define CImg_3x3x3(I,T) T I[27]; \
   479                       T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
   480                       T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
   481                       T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
   482                       T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
   483                       T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
   484                       T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
   485                       T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
   486                       T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
   487                       T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
   488                       I##ppp = I##cpp = I##npp = \
   489                       I##pcp = I##ccp = I##ncp = \
   490                       I##pnp = I##cnp = I##nnp = \
   491                       I##ppc = I##cpc = I##npc = \
   492                       I##pcc = I##ccc = I##ncc = \
   493                       I##pnc = I##cnc = I##nnc = \
   494                       I##ppn = I##cpn = I##npn = \
   495                       I##pcn = I##ccn = I##ncn = \
   496                       I##pnn = I##cnn = I##nnn = 0
   498 #define cimg_get2x2(img,x,y,z,v,I) \
   499   I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v)
   501 #define cimg_get3x3(img,x,y,z,v,I) \
   502   I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_p1##x,y,z,v), \
   503   I[4] = (img)(x,y,z,v), I[5] = (img)(_n1##x,y,z,v), I[6] = (img)(_p1##x,_n1##y,z,v), I[7] = (img)(x,_n1##y,z,v), \
   504   I[8] = (img)(_n1##x,_n1##y,z,v)
   506 #define cimg_get4x4(img,x,y,z,v,I) \
   507   I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_n2##x,_p1##y,z,v), \
   508   I[4] = (img)(_p1##x,y,z,v), I[5] = (img)(x,y,z,v), I[6] = (img)(_n1##x,y,z,v), I[7] = (img)(_n2##x,y,z,v), \
   509   I[8] = (img)(_p1##x,_n1##y,z,v), I[9] = (img)(x,_n1##y,z,v), I[10] = (img)(_n1##x,_n1##y,z,v), I[11] = (img)(_n2##x,_n1##y,z,v), \
   510   I[12] = (img)(_p1##x,_n2##y,z,v), I[13] = (img)(x,_n2##y,z,v), I[14] = (img)(_n1##x,_n2##y,z,v), I[15] = (img)(_n2##x,_n2##y,z,v)
   512 #define cimg_get5x5(img,x,y,z,v,I) \
   513   I[0] = (img)(_p2##x,_p2##y,z,v), I[1] = (img)(_p1##x,_p2##y,z,v), I[2] = (img)(x,_p2##y,z,v), I[3] = (img)(_n1##x,_p2##y,z,v), \
   514   I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_p2##x,_p1##y,z,v), I[6] = (img)(_p1##x,_p1##y,z,v), I[7] = (img)(x,_p1##y,z,v), \
   515   I[8] = (img)(_n1##x,_p1##y,z,v), I[9] = (img)(_n2##x,_p1##y,z,v), I[10] = (img)(_p2##x,y,z,v), I[11] = (img)(_p1##x,y,z,v), \
   516   I[12] = (img)(x,y,z,v), I[13] = (img)(_n1##x,y,z,v), I[14] = (img)(_n2##x,y,z,v), I[15] = (img)(_p2##x,_n1##y,z,v), \
   517   I[16] = (img)(_p1##x,_n1##y,z,v), I[17] = (img)(x,_n1##y,z,v), I[18] = (img)(_n1##x,_n1##y,z,v), I[19] = (img)(_n2##x,_n1##y,z,v), \
   518   I[20] = (img)(_p2##x,_n2##y,z,v), I[21] = (img)(_p1##x,_n2##y,z,v), I[22] = (img)(x,_n2##y,z,v), I[23] = (img)(_n1##x,_n2##y,z,v), \
   519   I[24] = (img)(_n2##x,_n2##y,z,v)
   521 #define cimg_get6x6(img,x,y,z,v,I) \
   522  I[0] = (img)(_p2##x,_p2##y,z,v), I[1] = (img)(_p1##x,_p2##y,z,v), I[2] = (img)(x,_p2##y,z,v), I[3] = (img)(_n1##x,_p2##y,z,v), \
   523  I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_n3##x,_p2##y,z,v), I[6] = (img)(_p2##x,_p1##y,z,v), I[7] = (img)(_p1##x,_p1##y,z,v), \
   524  I[8] = (img)(x,_p1##y,z,v), I[9] = (img)(_n1##x,_p1##y,z,v), I[10] = (img)(_n2##x,_p1##y,z,v), I[11] = (img)(_n3##x,_p1##y,z,v), \
   525  I[12] = (img)(_p2##x,y,z,v), I[13] = (img)(_p1##x,y,z,v), I[14] = (img)(x,y,z,v), I[15] = (img)(_n1##x,y,z,v), \
   526  I[16] = (img)(_n2##x,y,z,v), I[17] = (img)(_n3##x,y,z,v), I[18] = (img)(_p2##x,_n1##y,z,v), I[19] = (img)(_p1##x,_n1##y,z,v), \
   527  I[20] = (img)(x,_n1##y,z,v), I[21] = (img)(_n1##x,_n1##y,z,v), I[22] = (img)(_n2##x,_n1##y,z,v), I[23] = (img)(_n3##x,_n1##y,z,v), \
   528  I[24] = (img)(_p2##x,_n2##y,z,v), I[25] = (img)(_p1##x,_n2##y,z,v), I[26] = (img)(x,_n2##y,z,v), I[27] = (img)(_n1##x,_n2##y,z,v), \
   529  I[28] = (img)(_n2##x,_n2##y,z,v), I[29] = (img)(_n3##x,_n2##y,z,v), I[30] = (img)(_p2##x,_n3##y,z,v), I[31] = (img)(_p1##x,_n3##y,z,v), \
   530  I[32] = (img)(x,_n3##y,z,v), I[33] = (img)(_n1##x,_n3##y,z,v), I[34] = (img)(_n2##x,_n3##y,z,v), I[35] = (img)(_n3##x,_n3##y,z,v)
   532 #define cimg_get7x7(img,x,y,z,v,I) \
   533  I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
   534  I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_p3##x,_p2##y,z,v), \
   535  I[8] = (img)(_p2##x,_p2##y,z,v), I[9] = (img)(_p1##x,_p2##y,z,v), I[10] = (img)(x,_p2##y,z,v), I[11] = (img)(_n1##x,_p2##y,z,v), \
   536  I[12] = (img)(_n2##x,_p2##y,z,v), I[13] = (img)(_n3##x,_p2##y,z,v), I[14] = (img)(_p3##x,_p1##y,z,v), I[15] = (img)(_p2##x,_p1##y,z,v), \
   537  I[16] = (img)(_p1##x,_p1##y,z,v), I[17] = (img)(x,_p1##y,z,v), I[18] = (img)(_n1##x,_p1##y,z,v), I[19] = (img)(_n2##x,_p1##y,z,v), \
   538  I[20] = (img)(_n3##x,_p1##y,z,v), I[21] = (img)(_p3##x,y,z,v), I[22] = (img)(_p2##x,y,z,v), I[23] = (img)(_p1##x,y,z,v), \
   539  I[24] = (img)(x,y,z,v), I[25] = (img)(_n1##x,y,z,v), I[26] = (img)(_n2##x,y,z,v), I[27] = (img)(_n3##x,y,z,v), \
   540  I[28] = (img)(_p3##x,_n1##y,z,v), I[29] = (img)(_p2##x,_n1##y,z,v), I[30] = (img)(_p1##x,_n1##y,z,v), I[31] = (img)(x,_n1##y,z,v), \
   541  I[32] = (img)(_n1##x,_n1##y,z,v), I[33] = (img)(_n2##x,_n1##y,z,v), I[34] = (img)(_n3##x,_n1##y,z,v), I[35] = (img)(_p3##x,_n2##y,z,v), \
   542  I[36] = (img)(_p2##x,_n2##y,z,v), I[37] = (img)(_p1##x,_n2##y,z,v), I[38] = (img)(x,_n2##y,z,v), I[39] = (img)(_n1##x,_n2##y,z,v), \
   543  I[40] = (img)(_n2##x,_n2##y,z,v), I[41] = (img)(_n3##x,_n2##y,z,v), I[42] = (img)(_p3##x,_n3##y,z,v), I[43] = (img)(_p2##x,_n3##y,z,v), \
   544  I[44] = (img)(_p1##x,_n3##y,z,v), I[45] = (img)(x,_n3##y,z,v), I[46] = (img)(_n1##x,_n3##y,z,v), I[47] = (img)(_n2##x,_n3##y,z,v), \
   545  I[48] = (img)(_n3##x,_n3##y,z,v)
   547 #define cimg_get8x8(img,x,y,z,v,I) \
   548  I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
   549  I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_n4##x,_p3##y,z,v), \
   550  I[8] = (img)(_p3##x,_p2##y,z,v), I[9] = (img)(_p2##x,_p2##y,z,v), I[10] = (img)(_p1##x,_p2##y,z,v), I[11] = (img)(x,_p2##y,z,v), \
   551  I[12] = (img)(_n1##x,_p2##y,z,v), I[13] = (img)(_n2##x,_p2##y,z,v), I[14] = (img)(_n3##x,_p2##y,z,v), I[15] = (img)(_n4##x,_p2##y,z,v), \
   552  I[16] = (img)(_p3##x,_p1##y,z,v), I[17] = (img)(_p2##x,_p1##y,z,v), I[18] = (img)(_p1##x,_p1##y,z,v), I[19] = (img)(x,_p1##y,z,v), \
   553  I[20] = (img)(_n1##x,_p1##y,z,v), I[21] = (img)(_n2##x,_p1##y,z,v), I[22] = (img)(_n3##x,_p1##y,z,v), I[23] = (img)(_n4##x,_p1##y,z,v), \
   554  I[24] = (img)(_p3##x,y,z,v), I[25] = (img)(_p2##x,y,z,v), I[26] = (img)(_p1##x,y,z,v), I[27] = (img)(x,y,z,v), \
   555  I[28] = (img)(_n1##x,y,z,v), I[29] = (img)(_n2##x,y,z,v), I[30] = (img)(_n3##x,y,z,v), I[31] = (img)(_n4##x,y,z,v), \
   556  I[32] = (img)(_p3##x,_n1##y,z,v), I[33] = (img)(_p2##x,_n1##y,z,v), I[34] = (img)(_p1##x,_n1##y,z,v), I[35] = (img)(x,_n1##y,z,v), \
   557  I[36] = (img)(_n1##x,_n1##y,z,v), I[37] = (img)(_n2##x,_n1##y,z,v), I[38] = (img)(_n3##x,_n1##y,z,v), I[39] = (img)(_n4##x,_n1##y,z,v), \
   558  I[40] = (img)(_p3##x,_n2##y,z,v), I[41] = (img)(_p2##x,_n2##y,z,v), I[42] = (img)(_p1##x,_n2##y,z,v), I[43] = (img)(x,_n2##y,z,v), \
   559  I[44] = (img)(_n1##x,_n2##y,z,v), I[45] = (img)(_n2##x,_n2##y,z,v), I[46] = (img)(_n3##x,_n2##y,z,v), I[47] = (img)(_n4##x,_n2##y,z,v), \
   560  I[48] = (img)(_p3##x,_n3##y,z,v), I[49] = (img)(_p2##x,_n3##y,z,v), I[50] = (img)(_p1##x,_n3##y,z,v), I[51] = (img)(x,_n3##y,z,v), \
   561  I[52] = (img)(_n1##x,_n3##y,z,v), I[53] = (img)(_n2##x,_n3##y,z,v), I[54] = (img)(_n3##x,_n3##y,z,v), I[55] = (img)(_n4##x,_n3##y,z,v), \
   562  I[56] = (img)(_p3##x,_n4##y,z,v), I[57] = (img)(_p2##x,_n4##y,z,v), I[58] = (img)(_p1##x,_n4##y,z,v), I[59] = (img)(x,_n4##y,z,v), \
   563  I[60] = (img)(_n1##x,_n4##y,z,v), I[61] = (img)(_n2##x,_n4##y,z,v), I[62] = (img)(_n3##x,_n4##y,z,v), I[63] = (img)(_n4##x,_n4##y,z,v);
   565 #define cimg_get9x9(img,x,y,z,v,I) \
   566  I[0] = (img)(_p4##x,_p4##y,z,v), I[1] = (img)(_p3##x,_p4##y,z,v), I[2] = (img)(_p2##x,_p4##y,z,v), I[3] = (img)(_p1##x,_p4##y,z,v), \
   567  I[4] = (img)(x,_p4##y,z,v), I[5] = (img)(_n1##x,_p4##y,z,v), I[6] = (img)(_n2##x,_p4##y,z,v), I[7] = (img)(_n3##x,_p4##y,z,v), \
   568  I[8] = (img)(_n4##x,_p4##y,z,v), I[9] = (img)(_p4##x,_p3##y,z,v), I[10] = (img)(_p3##x,_p3##y,z,v), I[11] = (img)(_p2##x,_p3##y,z,v), \
   569  I[12] = (img)(_p1##x,_p3##y,z,v), I[13] = (img)(x,_p3##y,z,v), I[14] = (img)(_n1##x,_p3##y,z,v), I[15] = (img)(_n2##x,_p3##y,z,v), \
   570  I[16] = (img)(_n3##x,_p3##y,z,v), I[17] = (img)(_n4##x,_p3##y,z,v), I[18] = (img)(_p4##x,_p2##y,z,v), I[19] = (img)(_p3##x,_p2##y,z,v), \
   571  I[20] = (img)(_p2##x,_p2##y,z,v), I[21] = (img)(_p1##x,_p2##y,z,v), I[22] = (img)(x,_p2##y,z,v), I[23] = (img)(_n1##x,_p2##y,z,v), \
   572  I[24] = (img)(_n2##x,_p2##y,z,v), I[25] = (img)(_n3##x,_p2##y,z,v), I[26] = (img)(_n4##x,_p2##y,z,v), I[27] = (img)(_p4##x,_p1##y,z,v), \
   573  I[28] = (img)(_p3##x,_p1##y,z,v), I[29] = (img)(_p2##x,_p1##y,z,v), I[30] = (img)(_p1##x,_p1##y,z,v), I[31] = (img)(x,_p1##y,z,v), \
   574  I[32] = (img)(_n1##x,_p1##y,z,v), I[33] = (img)(_n2##x,_p1##y,z,v), I[34] = (img)(_n3##x,_p1##y,z,v), I[35] = (img)(_n4##x,_p1##y,z,v), \
   575  I[36] = (img)(_p4##x,y,z,v), I[37] = (img)(_p3##x,y,z,v), I[38] = (img)(_p2##x,y,z,v), I[39] = (img)(_p1##x,y,z,v), \
   576  I[40] = (img)(x,y,z,v), I[41] = (img)(_n1##x,y,z,v), I[42] = (img)(_n2##x,y,z,v), I[43] = (img)(_n3##x,y,z,v), \
   577  I[44] = (img)(_n4##x,y,z,v), I[45] = (img)(_p4##x,_n1##y,z,v), I[46] = (img)(_p3##x,_n1##y,z,v), I[47] = (img)(_p2##x,_n1##y,z,v), \
   578  I[48] = (img)(_p1##x,_n1##y,z,v), I[49] = (img)(x,_n1##y,z,v), I[50] = (img)(_n1##x,_n1##y,z,v), I[51] = (img)(_n2##x,_n1##y,z,v), \
   579  I[52] = (img)(_n3##x,_n1##y,z,v), I[53] = (img)(_n4##x,_n1##y,z,v), I[54] = (img)(_p4##x,_n2##y,z,v), I[55] = (img)(_p3##x,_n2##y,z,v), \
   580  I[56] = (img)(_p2##x,_n2##y,z,v), I[57] = (img)(_p1##x,_n2##y,z,v), I[58] = (img)(x,_n2##y,z,v), I[59] = (img)(_n1##x,_n2##y,z,v), \
   581  I[60] = (img)(_n2##x,_n2##y,z,v), I[61] = (img)(_n3##x,_n2##y,z,v), I[62] = (img)(_n4##x,_n2##y,z,v), I[63] = (img)(_p4##x,_n3##y,z,v), \
   582  I[64] = (img)(_p3##x,_n3##y,z,v), I[65] = (img)(_p2##x,_n3##y,z,v), I[66] = (img)(_p1##x,_n3##y,z,v), I[67] = (img)(x,_n3##y,z,v), \
   583  I[68] = (img)(_n1##x,_n3##y,z,v), I[69] = (img)(_n2##x,_n3##y,z,v), I[70] = (img)(_n3##x,_n3##y,z,v), I[71] = (img)(_n4##x,_n3##y,z,v), \
   584  I[72] = (img)(_p4##x,_n4##y,z,v), I[73] = (img)(_p3##x,_n4##y,z,v), I[74] = (img)(_p2##x,_n4##y,z,v), I[75] = (img)(_p1##x,_n4##y,z,v), \
   585  I[76] = (img)(x,_n4##y,z,v), I[77] = (img)(_n1##x,_n4##y,z,v), I[78] = (img)(_n2##x,_n4##y,z,v), I[79] = (img)(_n3##x,_n4##y,z,v), \
   586  I[80] = (img)(_n4##x,_n4##y,z,v)
   588 #define cimg_get2x2x2(img,x,y,z,v,I) \
   589   I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v), \
   590   I[4] = (img)(x,y,_n1##z,v), I[5] = (img)(_n1##x,y,_n1##z,v), I[6] = (img)(x,_n1##y,_n1##z,v), I[7] = (img)(_n1##x,_n1##y,_n1##z,v)
   592 #define cimg_get3x3x3(img,x,y,z,v,I) \
   593   I[0] = (img)(_p1##x,_p1##y,_p1##z,v), I[1] = (img)(x,_p1##y,_p1##z,v), I[2] = (img)(_n1##x,_p1##y,_p1##z,v), \
   594   I[3] = (img)(_p1##x,y,_p1##z,v), I[4] = (img)(x,y,_p1##z,v), I[5] = (img)(_n1##x,y,_p1##z,v), \
   595   I[6] = (img)(_p1##x,_n1##y,_p1##z,v), I[7] = (img)(x,_n1##y,_p1##z,v), I[8] = (img)(_n1##x,_n1##y,_p1##z,v), \
   596   I[9] = (img)(_p1##x,_p1##y,z,v), I[10] = (img)(x,_p1##y,z,v), I[11] = (img)(_n1##x,_p1##y,z,v), \
   597   I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
   598   I[15] = (img)(_p1##x,_n1##y,z,v), I[16] = (img)(x,_n1##y,z,v), I[17] = (img)(_n1##x,_n1##y,z,v), \
   599   I[18] = (img)(_p1##x,_p1##y,_n1##z,v), I[19] = (img)(x,_p1##y,_n1##z,v), I[20] = (img)(_n1##x,_p1##y,_n1##z,v), \
   600   I[21] = (img)(_p1##x,y,_n1##z,v), I[22] = (img)(x,y,_n1##z,v), I[23] = (img)(_n1##x,y,_n1##z,v), \
   601   I[24] = (img)(_p1##x,_n1##y,_n1##z,v), I[25] = (img)(x,_n1##y,_n1##z,v), I[26] = (img)(_n1##x,_n1##y,_n1##z,v)
   603 // Define various image loops.
   604 //
   605 // These macros generally avoid the use of iterators, but you are not forced to used them !
   606 //
   607 #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
   608 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
   609 #define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
   610 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
   612 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
   613 #define cimg_forX(img,x) cimg_for1((img).width,x)
   614 #define cimg_forY(img,y) cimg_for1((img).height,y)
   615 #define cimg_forZ(img,z) cimg_for1((img).depth,z)
   616 #define cimg_forV(img,v) cimg_for1((img).dim,v)
   617 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
   618 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
   619 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
   620 #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
   621 #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
   622 #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
   623 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
   624 #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
   625 #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
   626 #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
   627 #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
   629 #define cimg_for_in1(bound,i0,i1,i) \
   630  for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
   631 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
   632 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
   633 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
   634 #define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
   635 #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)
   636 #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)
   637 #define cimg_for_inXV(img,x0,v0,x1,v1,x,v) cimg_for_inV(img,v0,v1,v) cimg_for_inX(img,x0,x1,x)
   638 #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)
   639 #define cimg_for_inYV(img,y0,v0,y1,v1,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inY(img,y0,y1,y)
   640 #define cimg_for_inZV(img,z0,v0,z1,v1,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inZ(img,z0,z1,z)
   641 #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
   642 #define cimg_for_inXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
   643 #define cimg_for_inXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)
   644 #define cimg_for_inYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)
   645 #define cimg_for_inXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   646 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
   647 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
   648 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
   649 #define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
   650 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
   651 #define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
   652 #define cimg_for_insideXYZV(img,x,y,z,v,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
   654 #define cimg_for_out1(boundi,i0,i1,i) \
   655  for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
   656 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
   657  for (int j = 0; j<(int)(boundj); ++j) \
   658  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
   659   ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
   660 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
   661  for (int k = 0; k<(int)(boundk); ++k) \
   662  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
   663  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
   664   ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
   665 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
   666  for (int l = 0; l<(int)(boundl); ++l) \
   667  for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
   668  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
   669  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
   670   ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
   671 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
   672 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
   673 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
   674 #define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
   675 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
   676 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
   677 #define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
   678 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
   679 #define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
   680 #define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
   681 #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_out3((img).width,(img).height,(img).depth,x0,y0,z0,x1,y1,z1,x,y,z)
   682 #define cimg_for_outXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_out3((img).width,(img).height,(img).dim,x0,y0,v0,x1,y1,v1,x,y,v)
   683 #define cimg_for_outXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_out3((img).width,(img).depth,(img).dim,x0,z0,v0,x1,z1,v1,x,z,v)
   684 #define cimg_for_outYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_out3((img).height,(img).depth,(img).dim,y0,z0,v0,y1,z1,v1,y,z,v)
   685 #define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
   686  cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
   687 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
   688 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
   689 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
   690 #define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
   691 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
   692 #define cimg_for_borderXYZ(img,x,y,z,n) cimg_for_outXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
   693 #define cimg_for_borderXYZV(img,x,y,z,v,n) \
   694  cimg_for_outXYZV(img,n,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),(img).dim-1-(n),x,y,z,v)
   696 #define cimg_for_spiralXY(img,x,y) \
   697  for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
   698       --_n1##y, _n1##x += (_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img).width-1-++x:((_n1##x&3)==2?(img).height-1-++y:--x))))?0:1)
   700 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
   701  for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
   702       _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
   703       _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
   704       _counter = _dx, \
   705       _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
   706       _counter>=0; \
   707       --_counter, x+=_steep? \
   708       (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
   709       (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
   711 #define cimg_for2(bound,i) \
   712  for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
   713       _n1##i<(int)(bound) || i==--_n1##i; \
   714       ++i, ++_n1##i)
   715 #define cimg_for2X(img,x) cimg_for2((img).width,x)
   716 #define cimg_for2Y(img,y) cimg_for2((img).height,y)
   717 #define cimg_for2Z(img,z) cimg_for2((img).depth,z)
   718 #define cimg_for2V(img,v) cimg_for2((img).dim,v)
   719 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
   720 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
   721 #define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
   722 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
   723 #define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
   724 #define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
   725 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
   726 #define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
   727 #define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
   728 #define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
   730 #define cimg_for_in2(bound,i0,i1,i) \
   731  for (int i = (int)(i0)<0?0:(int)(i0), \
   732       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
   733       i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
   734       ++i, ++_n1##i)
   735 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
   736 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
   737 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
   738 #define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
   739 #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)
   740 #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)
   741 #define cimg_for_in2XV(img,x0,v0,x1,v1,x,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2X(img,x0,x1,x)
   742 #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)
   743 #define cimg_for_in2YV(img,y0,v0,y1,v1,y,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Y(img,y0,y1,y)
   744 #define cimg_for_in2ZV(img,z0,v0,z1,v1,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Z(img,z0,z1,z)
   745 #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)
   746 #define cimg_for_in2XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)
   747 #define cimg_for_in2YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)
   748 #define cimg_for_in2XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   750 #define cimg_for3(bound,i) \
   751  for (int i = 0, _p1##i = 0, \
   752       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
   753       _n1##i<(int)(bound) || i==--_n1##i; \
   754       _p1##i = i++, ++_n1##i)
   755 #define cimg_for3X(img,x) cimg_for3((img).width,x)
   756 #define cimg_for3Y(img,y) cimg_for3((img).height,y)
   757 #define cimg_for3Z(img,z) cimg_for3((img).depth,z)
   758 #define cimg_for3V(img,v) cimg_for3((img).dim,v)
   759 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
   760 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
   761 #define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
   762 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
   763 #define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
   764 #define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
   765 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
   766 #define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
   767 #define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
   768 #define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
   770 #define cimg_for_in3(bound,i0,i1,i) \
   771  for (int i = (int)(i0)<0?0:(int)(i0), \
   772       _p1##i = i-1<0?0:i-1, \
   773       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
   774       i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
   775       _p1##i = i++, ++_n1##i)
   776 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
   777 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
   778 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
   779 #define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
   780 #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)
   781 #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)
   782 #define cimg_for_in3XV(img,x0,v0,x1,v1,x,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3X(img,x0,x1,x)
   783 #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)
   784 #define cimg_for_in3YV(img,y0,v0,y1,v1,y,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Y(img,y0,y1,y)
   785 #define cimg_for_in3ZV(img,z0,v0,z1,v1,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Z(img,z0,z1,z)
   786 #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)
   787 #define cimg_for_in3XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)
   788 #define cimg_for_in3YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)
   789 #define cimg_for_in3XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   791 #define cimg_for4(bound,i) \
   792  for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   793       _n2##i = 2>=(bound)?(int)(bound)-1:2; \
   794       _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
   795       _p1##i = i++, ++_n1##i, ++_n2##i)
   796 #define cimg_for4X(img,x) cimg_for4((img).width,x)
   797 #define cimg_for4Y(img,y) cimg_for4((img).height,y)
   798 #define cimg_for4Z(img,z) cimg_for4((img).depth,z)
   799 #define cimg_for4V(img,v) cimg_for4((img).dim,v)
   800 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
   801 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
   802 #define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
   803 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
   804 #define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
   805 #define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
   806 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
   807 #define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
   808 #define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
   809 #define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
   811 #define cimg_for_in4(bound,i0,i1,i) \
   812  for (int i = (int)(i0)<0?0:(int)(i0), \
   813       _p1##i = i-1<0?0:i-1, \
   814       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   815       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
   816       i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
   817       _p1##i = i++, ++_n1##i, ++_n2##i)
   818 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
   819 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
   820 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
   821 #define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
   822 #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)
   823 #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)
   824 #define cimg_for_in4XV(img,x0,v0,x1,v1,x,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4X(img,x0,x1,x)
   825 #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)
   826 #define cimg_for_in4YV(img,y0,v0,y1,v1,y,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Y(img,y0,y1,y)
   827 #define cimg_for_in4ZV(img,z0,v0,z1,v1,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Z(img,z0,z1,z)
   828 #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)
   829 #define cimg_for_in4XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)
   830 #define cimg_for_in4YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)
   831 #define cimg_for_in4XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   833 #define cimg_for5(bound,i) \
   834  for (int i = 0, _p2##i = 0, _p1##i = 0, \
   835       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   836       _n2##i = 2>=(bound)?(int)(bound)-1:2; \
   837       _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
   838       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
   839 #define cimg_for5X(img,x) cimg_for5((img).width,x)
   840 #define cimg_for5Y(img,y) cimg_for5((img).height,y)
   841 #define cimg_for5Z(img,z) cimg_for5((img).depth,z)
   842 #define cimg_for5V(img,v) cimg_for5((img).dim,v)
   843 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
   844 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
   845 #define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
   846 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
   847 #define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
   848 #define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
   849 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
   850 #define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
   851 #define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
   852 #define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
   854 #define cimg_for_in5(bound,i0,i1,i) \
   855  for (int i = (int)(i0)<0?0:(int)(i0), \
   856       _p2##i = i-2<0?0:i-2, \
   857       _p1##i = i-1<0?0:i-1, \
   858       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   859       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
   860       i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
   861       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
   862 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
   863 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
   864 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
   865 #define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
   866 #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)
   867 #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)
   868 #define cimg_for_in5XV(img,x0,v0,x1,v1,x,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5X(img,x0,x1,x)
   869 #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)
   870 #define cimg_for_in5YV(img,y0,v0,y1,v1,y,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Y(img,y0,y1,y)
   871 #define cimg_for_in5ZV(img,z0,v0,z1,v1,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Z(img,z0,z1,z)
   872 #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)
   873 #define cimg_for_in5XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)
   874 #define cimg_for_in5YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)
   875 #define cimg_for_in5XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   877 #define cimg_for6(bound,i) \
   878  for (int i = 0, _p2##i = 0, _p1##i = 0, \
   879       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   880       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   881       _n3##i = 3>=(bound)?(int)(bound)-1:3; \
   882       _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
   883       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   884 #define cimg_for6X(img,x) cimg_for6((img).width,x)
   885 #define cimg_for6Y(img,y) cimg_for6((img).height,y)
   886 #define cimg_for6Z(img,z) cimg_for6((img).depth,z)
   887 #define cimg_for6V(img,v) cimg_for6((img).dim,v)
   888 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
   889 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
   890 #define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
   891 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
   892 #define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
   893 #define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
   894 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
   895 #define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
   896 #define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
   897 #define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
   899 #define cimg_for_in6(bound,i0,i1,i) \
   900  for (int i = (int)(i0)<0?0:(int)(i0), \
   901       _p2##i = i-2<0?0:i-2, \
   902       _p1##i = i-1<0?0:i-1, \
   903       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   904       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
   905       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
   906       i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
   907       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   908 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
   909 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
   910 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
   911 #define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
   912 #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)
   913 #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)
   914 #define cimg_for_in6XV(img,x0,v0,x1,v1,x,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6X(img,x0,x1,x)
   915 #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)
   916 #define cimg_for_in6YV(img,y0,v0,y1,v1,y,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Y(img,y0,y1,y)
   917 #define cimg_for_in6ZV(img,z0,v0,z1,v1,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Z(img,z0,z1,z)
   918 #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)
   919 #define cimg_for_in6XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)
   920 #define cimg_for_in6YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)
   921 #define cimg_for_in6XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   923 #define cimg_for7(bound,i) \
   924  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
   925       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   926       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   927       _n3##i = 3>=(bound)?(int)(bound)-1:3; \
   928       _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
   929       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   930 #define cimg_for7X(img,x) cimg_for7((img).width,x)
   931 #define cimg_for7Y(img,y) cimg_for7((img).height,y)
   932 #define cimg_for7Z(img,z) cimg_for7((img).depth,z)
   933 #define cimg_for7V(img,v) cimg_for7((img).dim,v)
   934 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
   935 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
   936 #define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
   937 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
   938 #define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
   939 #define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
   940 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
   941 #define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
   942 #define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
   943 #define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
   945 #define cimg_for_in7(bound,i0,i1,i) \
   946  for (int i = (int)(i0)<0?0:(int)(i0), \
   947       _p3##i = i-3<0?0:i-3, \
   948       _p2##i = i-2<0?0:i-2, \
   949       _p1##i = i-1<0?0:i-1, \
   950       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   951       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
   952       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
   953       i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
   954       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   955 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
   956 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
   957 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
   958 #define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
   959 #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)
   960 #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)
   961 #define cimg_for_in7XV(img,x0,v0,x1,v1,x,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7X(img,x0,x1,x)
   962 #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)
   963 #define cimg_for_in7YV(img,y0,v0,y1,v1,y,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Y(img,y0,y1,y)
   964 #define cimg_for_in7ZV(img,z0,v0,z1,v1,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Z(img,z0,z1,z)
   965 #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)
   966 #define cimg_for_in7XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)
   967 #define cimg_for_in7YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)
   968 #define cimg_for_in7XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
   970 #define cimg_for8(bound,i) \
   971  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
   972       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   973       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   974       _n3##i = 3>=(bound)?(int)(bound)-1:3, \
   975       _n4##i = 4>=(bound)?(int)(bound)-1:4; \
   976       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
   977       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
   978       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
   979 #define cimg_for8X(img,x) cimg_for8((img).width,x)
   980 #define cimg_for8Y(img,y) cimg_for8((img).height,y)
   981 #define cimg_for8Z(img,z) cimg_for8((img).depth,z)
   982 #define cimg_for8V(img,v) cimg_for8((img).dim,v)
   983 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
   984 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
   985 #define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
   986 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
   987 #define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
   988 #define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
   989 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
   990 #define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
   991 #define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
   992 #define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
   994 #define cimg_for_in8(bound,i0,i1,i) \
   995  for (int i = (int)(i0)<0?0:(int)(i0), \
   996       _p3##i = i-3<0?0:i-3, \
   997       _p2##i = i-2<0?0:i-2, \
   998       _p1##i = i-1<0?0:i-1, \
   999       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
  1000       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
  1001       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
  1002       _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
  1003       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1004       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
  1005       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1006 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
  1007 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
  1008 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
  1009 #define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
  1010 #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)
  1011 #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)
  1012 #define cimg_for_in8XV(img,x0,v0,x1,v1,x,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8X(img,x0,x1,x)
  1013 #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)
  1014 #define cimg_for_in8YV(img,y0,v0,y1,v1,y,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Y(img,y0,y1,y)
  1015 #define cimg_for_in8ZV(img,z0,v0,z1,v1,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Z(img,z0,z1,z)
  1016 #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)
  1017 #define cimg_for_in8XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)
  1018 #define cimg_for_in8YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)
  1019 #define cimg_for_in8XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
  1021 #define cimg_for9(bound,i) \
  1022   for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
  1023        _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
  1024        _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
  1025        _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
  1026        _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
  1027        _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1028        i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
  1029        _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1030 #define cimg_for9X(img,x) cimg_for9((img).width,x)
  1031 #define cimg_for9Y(img,y) cimg_for9((img).height,y)
  1032 #define cimg_for9Z(img,z) cimg_for9((img).depth,z)
  1033 #define cimg_for9V(img,v) cimg_for9((img).dim,v)
  1034 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
  1035 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
  1036 #define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
  1037 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
  1038 #define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
  1039 #define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
  1040 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
  1041 #define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
  1042 #define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
  1043 #define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
  1045 #define cimg_for_in9(bound,i0,i1,i) \
  1046   for (int i = (int)(i0)<0?0:(int)(i0), \
  1047        _p4##i = i-4<0?0:i-4, \
  1048        _p3##i = i-3<0?0:i-3, \
  1049        _p2##i = i-2<0?0:i-2, \
  1050        _p1##i = i-1<0?0:i-1, \
  1051        _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
  1052        _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
  1053        _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
  1054        _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
  1055        i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1056        i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
  1057        _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1058 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
  1059 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
  1060 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
  1061 #define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
  1062 #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)
  1063 #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)
  1064 #define cimg_for_in9XV(img,x0,v0,x1,v1,x,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9X(img,x0,x1,x)
  1065 #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)
  1066 #define cimg_for_in9YV(img,y0,v0,y1,v1,y,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Y(img,y0,y1,y)
  1067 #define cimg_for_in9ZV(img,z0,v0,z1,v1,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Z(img,z0,z1,z)
  1068 #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)
  1069 #define cimg_for_in9XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)
  1070 #define cimg_for_in9YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)
  1071 #define cimg_for_in9XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
  1073 #define cimg_for2x2(img,x,y,z,v,I) \
  1074   cimg_for2((img).height,y) for (int x = 0, \
  1075    _n1##x = (int)( \
  1076    (I[0] = (img)(0,y,z,v)), \
  1077    (I[2] = (img)(0,_n1##y,z,v)), \
  1078    1>=(img).width?(int)((img).width)-1:1);  \
  1079    (_n1##x<(int)((img).width) && ( \
  1080    (I[1] = (img)(_n1##x,y,z,v)), \
  1081    (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1082    x==--_n1##x; \
  1083    I[0] = I[1], \
  1084    I[2] = I[3], \
  1085    ++x, ++_n1##x)
  1087 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
  1088   cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1089    _n1##x = (int)( \
  1090    (I[0] = (img)(x,y,z,v)), \
  1091    (I[2] = (img)(x,_n1##y,z,v)), \
  1092    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1093    x<=(int)(x1) && ((_n1##x<(int)((img).width) && (  \
  1094    (I[1] = (img)(_n1##x,y,z,v)), \
  1095    (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1096    x==--_n1##x); \
  1097    I[0] = I[1], \
  1098    I[2] = I[3], \
  1099    ++x, ++_n1##x)
  1101 #define cimg_for3x3(img,x,y,z,v,I) \
  1102   cimg_for3((img).height,y) for (int x = 0, \
  1103    _p1##x = 0, \
  1104    _n1##x = (int)( \
  1105    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
  1106    (I[3] = I[4] = (img)(0,y,z,v)), \
  1107    (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
  1108    1>=(img).width?(int)((img).width)-1:1); \
  1109    (_n1##x<(int)((img).width) && ( \
  1110    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1111    (I[5] = (img)(_n1##x,y,z,v)), \
  1112    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1113    x==--_n1##x; \
  1114    I[0] = I[1], I[1] = I[2], \
  1115    I[3] = I[4], I[4] = I[5], \
  1116    I[6] = I[7], I[7] = I[8], \
  1117    _p1##x = x++, ++_n1##x)
  1119 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
  1120   cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1121    _p1##x = x-1<0?0:x-1, \
  1122    _n1##x = (int)( \
  1123    (I[0] = (img)(_p1##x,_p1##y,z,v)), \
  1124    (I[3] = (img)(_p1##x,y,z,v)), \
  1125    (I[6] = (img)(_p1##x,_n1##y,z,v)), \
  1126    (I[1] = (img)(x,_p1##y,z,v)), \
  1127    (I[4] = (img)(x,y,z,v)), \
  1128    (I[7] = (img)(x,_n1##y,z,v)), \
  1129    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1130    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1131    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1132    (I[5] = (img)(_n1##x,y,z,v)), \
  1133    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1134    x==--_n1##x);            \
  1135    I[0] = I[1], I[1] = I[2], \
  1136    I[3] = I[4], I[4] = I[5], \
  1137    I[6] = I[7], I[7] = I[8], \
  1138    _p1##x = x++, ++_n1##x)
  1140 #define cimg_for4x4(img,x,y,z,v,I) \
  1141   cimg_for4((img).height,y) for (int x = 0, \
  1142    _p1##x = 0, \
  1143    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1144    _n2##x = (int)( \
  1145    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
  1146    (I[4] = I[5] = (img)(0,y,z,v)), \
  1147    (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
  1148    (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
  1149    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1150    (I[6] = (img)(_n1##x,y,z,v)), \
  1151    (I[10] = (img)(_n1##x,_n1##y,z,v)), \
  1152    (I[14] = (img)(_n1##x,_n2##y,z,v)), \
  1153    2>=(img).width?(int)((img).width)-1:2); \
  1154    (_n2##x<(int)((img).width) && ( \
  1155    (I[3] = (img)(_n2##x,_p1##y,z,v)), \
  1156    (I[7] = (img)(_n2##x,y,z,v)), \
  1157    (I[11] = (img)(_n2##x,_n1##y,z,v)), \
  1158    (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1159    _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
  1160    I[0] = I[1], I[1] = I[2], I[2] = I[3], \
  1161    I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1162    I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1163    I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1164    _p1##x = x++, ++_n1##x, ++_n2##x)
  1166 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
  1167   cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1168    _p1##x = x-1<0?0:x-1, \
  1169    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1170    _n2##x = (int)( \
  1171    (I[0] = (img)(_p1##x,_p1##y,z,v)), \
  1172    (I[4] = (img)(_p1##x,y,z,v)), \
  1173    (I[8] = (img)(_p1##x,_n1##y,z,v)), \
  1174    (I[12] = (img)(_p1##x,_n2##y,z,v)), \
  1175    (I[1] = (img)(x,_p1##y,z,v)), \
  1176    (I[5] = (img)(x,y,z,v)), \
  1177    (I[9] = (img)(x,_n1##y,z,v)), \
  1178    (I[13] = (img)(x,_n2##y,z,v)), \
  1179    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1180    (I[6] = (img)(_n1##x,y,z,v)), \
  1181    (I[10] = (img)(_n1##x,_n1##y,z,v)), \
  1182    (I[14] = (img)(_n1##x,_n2##y,z,v)), \
  1183    x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
  1184    x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
  1185    (I[3] = (img)(_n2##x,_p1##y,z,v)), \
  1186    (I[7] = (img)(_n2##x,y,z,v)), \
  1187    (I[11] = (img)(_n2##x,_n1##y,z,v)), \
  1188    (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1189    _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
  1190    I[0] = I[1], I[1] = I[2], I[2] = I[3], \
  1191    I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1192    I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1193    I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1194    _p1##x = x++, ++_n1##x, ++_n2##x)
  1196 #define cimg_for5x5(img,x,y,z,v,I) \
  1197  cimg_for5((img).height,y) for (int x = 0, \
  1198    _p2##x = 0, _p1##x = 0, \
  1199    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1200    _n2##x = (int)( \
  1201    (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
  1202    (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
  1203    (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
  1204    (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
  1205    (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
  1206    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1207    (I[8] = (img)(_n1##x,_p1##y,z,v)), \
  1208    (I[13] = (img)(_n1##x,y,z,v)), \
  1209    (I[18] = (img)(_n1##x,_n1##y,z,v)), \
  1210    (I[23] = (img)(_n1##x,_n2##y,z,v)),     \
  1211    2>=(img).width?(int)((img).width)-1:2); \
  1212    (_n2##x<(int)((img).width) && ( \
  1213    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1214    (I[9] = (img)(_n2##x,_p1##y,z,v)), \
  1215    (I[14] = (img)(_n2##x,y,z,v)), \
  1216    (I[19] = (img)(_n2##x,_n1##y,z,v)), \
  1217    (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1218    _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
  1219    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
  1220    I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
  1221    I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
  1222    I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
  1223    I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
  1224    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
  1226 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
  1227  cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1228    _p2##x = x-2<0?0:x-2, \
  1229    _p1##x = x-1<0?0:x-1, \
  1230    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1231    _n2##x = (int)( \
  1232    (I[0] = (img)(_p2##x,_p2##y,z,v)), \
  1233    (I[5] = (img)(_p2##x,_p1##y,z,v)), \
  1234    (I[10] = (img)(_p2##x,y,z,v)), \
  1235    (I[15] = (img)(_p2##x,_n1##y,z,v)), \
  1236    (I[20] = (img)(_p2##x,_n2##y,z,v)), \
  1237    (I[1] = (img)(_p1##x,_p2##y,z,v)), \
  1238    (I[6] = (img)(_p1##x,_p1##y,z,v)), \
  1239    (I[11] = (img)(_p1##x,y,z,v)), \
  1240    (I[16] = (img)(_p1##x,_n1##y,z,v)), \
  1241    (I[21] = (img)(_p1##x,_n2##y,z,v)), \
  1242    (I[2] = (img)(x,_p2##y,z,v)), \
  1243    (I[7] = (img)(x,_p1##y,z,v)), \
  1244    (I[12] = (img)(x,y,z,v)), \
  1245    (I[17] = (img)(x,_n1##y,z,v)), \
  1246    (I[22] = (img)(x,_n2##y,z,v)), \
  1247    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1248    (I[8] = (img)(_n1##x,_p1##y,z,v)), \
  1249    (I[13] = (img)(_n1##x,y,z,v)), \
  1250    (I[18] = (img)(_n1##x,_n1##y,z,v)), \
  1251    (I[23] = (img)(_n1##x,_n2##y,z,v)), \
  1252    x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
  1253    x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
  1254    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1255    (I[9] = (img)(_n2##x,_p1##y,z,v)), \
  1256    (I[14] = (img)(_n2##x,y,z,v)), \
  1257    (I[19] = (img)(_n2##x,_n1##y,z,v)), \
  1258    (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1259    _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
  1260    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
  1261    I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
  1262    I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
  1263    I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
  1264    I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
  1265    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
  1267 #define cimg_for6x6(img,x,y,z,v,I) \
  1268  cimg_for6((img).height,y) for (int x = 0, \
  1269    _p2##x = 0, _p1##x = 0, \
  1270    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1271    _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
  1272    _n3##x = (int)( \
  1273    (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
  1274    (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
  1275    (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
  1276    (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
  1277    (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
  1278    (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
  1279    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1280    (I[9] = (img)(_n1##x,_p1##y,z,v)), \
  1281    (I[15] = (img)(_n1##x,y,z,v)), \
  1282    (I[21] = (img)(_n1##x,_n1##y,z,v)), \
  1283    (I[27] = (img)(_n1##x,_n2##y,z,v)), \
  1284    (I[33] = (img)(_n1##x,_n3##y,z,v)), \
  1285    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1286    (I[10] = (img)(_n2##x,_p1##y,z,v)), \
  1287    (I[16] = (img)(_n2##x,y,z,v)), \
  1288    (I[22] = (img)(_n2##x,_n1##y,z,v)), \
  1289    (I[28] = (img)(_n2##x,_n2##y,z,v)), \
  1290    (I[34] = (img)(_n2##x,_n3##y,z,v)), \
  1291    3>=(img).width?(int)((img).width)-1:3); \
  1292    (_n3##x<(int)((img).width) && ( \
  1293    (I[5] = (img)(_n3##x,_p2##y,z,v)), \
  1294    (I[11] = (img)(_n3##x,_p1##y,z,v)), \
  1295    (I[17] = (img)(_n3##x,y,z,v)), \
  1296    (I[23] = (img)(_n3##x,_n1##y,z,v)), \
  1297    (I[29] = (img)(_n3##x,_n2##y,z,v)), \
  1298    (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1299    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
  1300    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
  1301    I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1302    I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1303    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1304    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
  1305    I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1306    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1308 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
  1309   cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
  1310    _p2##x = x-2<0?0:x-2, \
  1311    _p1##x = x-1<0?0:x-1, \
  1312    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1313    _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
  1314    _n3##x = (int)( \
  1315    (I[0] = (img)(_p2##x,_p2##y,z,v)), \
  1316    (I[6] = (img)(_p2##x,_p1##y,z,v)), \
  1317    (I[12] = (img)(_p2##x,y,z,v)), \
  1318    (I[18] = (img)(_p2##x,_n1##y,z,v)), \
  1319    (I[24] = (img)(_p2##x,_n2##y,z,v)), \
  1320    (I[30] = (img)(_p2##x,_n3##y,z,v)), \
  1321    (I[1] = (img)(_p1##x,_p2##y,z,v)), \
  1322    (I[7] = (img)(_p1##x,_p1##y,z,v)), \
  1323    (I[13] = (img)(_p1##x,y,z,v)), \
  1324    (I[19] = (img)(_p1##x,_n1##y,z,v)), \
  1325    (I[25] = (img)(_p1##x,_n2##y,z,v)), \
  1326    (I[31] = (img)(_p1##x,_n3##y,z,v)), \
  1327    (I[2] = (img)(x,_p2##y,z,v)), \
  1328    (I[8] = (img)(x,_p1##y,z,v)), \
  1329    (I[14] = (img)(x,y,z,v)), \
  1330    (I[20] = (img)(x,_n1##y,z,v)), \
  1331    (I[26] = (img)(x,_n2##y,z,v)), \
  1332    (I[32] = (img)(x,_n3##y,z,v)), \
  1333    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1334    (I[9] = (img)(_n1##x,_p1##y,z,v)), \
  1335    (I[15] = (img)(_n1##x,y,z,v)), \
  1336    (I[21] = (img)(_n1##x,_n1##y,z,v)), \
  1337    (I[27] = (img)(_n1##x,_n2##y,z,v)), \
  1338    (I[33] = (img)(_n1##x,_n3##y,z,v)), \
  1339    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1340    (I[10] = (img)(_n2##x,_p1##y,z,v)), \
  1341    (I[16] = (img)(_n2##x,y,z,v)), \
  1342    (I[22] = (img)(_n2##x,_n1##y,z,v)), \
  1343    (I[28] = (img)(_n2##x,_n2##y,z,v)), \
  1344    (I[34] = (img)(_n2##x,_n3##y,z,v)), \
  1345    x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
  1346    x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
  1347    (I[5] = (img)(_n3##x,_p2##y,z,v)), \
  1348    (I[11] = (img)(_n3##x,_p1##y,z,v)), \
  1349    (I[17] = (img)(_n3##x,y,z,v)), \
  1350    (I[23] = (img)(_n3##x,_n1##y,z,v)), \
  1351    (I[29] = (img)(_n3##x,_n2##y,z,v)), \
  1352    (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1353    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
  1354    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
  1355    I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1356    I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1357    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1358    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
  1359    I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1360    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1362 #define cimg_for7x7(img,x,y,z,v,I) \
  1363   cimg_for7((img).height,y) for (int x = 0, \
  1364    _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1365    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1366    _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
  1367    _n3##x = (int)( \
  1368    (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
  1369    (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
  1370    (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
  1371    (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
  1372    (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
  1373    (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
  1374    (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
  1375    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1376    (I[11] = (img)(_n1##x,_p2##y,z,v)), \
  1377    (I[18] = (img)(_n1##x,_p1##y,z,v)), \
  1378    (I[25] = (img)(_n1##x,y,z,v)), \
  1379    (I[32] = (img)(_n1##x,_n1##y,z,v)), \
  1380    (I[39] = (img)(_n1##x,_n2##y,z,v)), \
  1381    (I[46] = (img)(_n1##x,_n3##y,z,v)), \
  1382    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1383    (I[12] = (img)(_n2##x,_p2##y,z,v)), \
  1384    (I[19] = (img)(_n2##x,_p1##y,z,v)), \
  1385    (I[26] = (img)(_n2##x,y,z,v)), \
  1386    (I[33] = (img)(_n2##x,_n1##y,z,v)), \
  1387    (I[40] = (img)(_n2##x,_n2##y,z,v)), \
  1388    (I[47] = (img)(_n2##x,_n3##y,z,v)), \
  1389    3>=(img).width?(int)((img).width)-1:3); \
  1390    (_n3##x<(int)((img).width) && ( \
  1391    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1392    (I[13] = (img)(_n3##x,_p2##y,z,v)), \
  1393    (I[20] = (img)(_n3##x,_p1##y,z,v)), \
  1394    (I[27] = (img)(_n3##x,y,z,v)), \
  1395    (I[34] = (img)(_n3##x,_n1##y,z,v)), \
  1396    (I[41] = (img)(_n3##x,_n2##y,z,v)), \
  1397    (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1398    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
  1399    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
  1400    I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
  1401    I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
  1402    I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
  1403    I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
  1404    I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
  1405    I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
  1406    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1408 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
  1409   cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1410    _p3##x = x-3<0?0:x-3, \
  1411    _p2##x = x-2<0?0:x-2, \
  1412    _p1##x = x-1<0?0:x-1, \
  1413    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1414    _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
  1415    _n3##x = (int)( \
  1416    (I[0] = (img)(_p3##x,_p3##y,z,v)), \
  1417    (I[7] = (img)(_p3##x,_p2##y,z,v)), \
  1418    (I[14] = (img)(_p3##x,_p1##y,z,v)), \
  1419    (I[21] = (img)(_p3##x,y,z,v)), \
  1420    (I[28] = (img)(_p3##x,_n1##y,z,v)), \
  1421    (I[35] = (img)(_p3##x,_n2##y,z,v)), \
  1422    (I[42] = (img)(_p3##x,_n3##y,z,v)), \
  1423    (I[1] = (img)(_p2##x,_p3##y,z,v)), \
  1424    (I[8] = (img)(_p2##x,_p2##y,z,v)), \
  1425    (I[15] = (img)(_p2##x,_p1##y,z,v)), \
  1426    (I[22] = (img)(_p2##x,y,z,v)), \
  1427    (I[29] = (img)(_p2##x,_n1##y,z,v)), \
  1428    (I[36] = (img)(_p2##x,_n2##y,z,v)), \
  1429    (I[43] = (img)(_p2##x,_n3##y,z,v)), \
  1430    (I[2] = (img)(_p1##x,_p3##y,z,v)), \
  1431    (I[9] = (img)(_p1##x,_p2##y,z,v)), \
  1432    (I[16] = (img)(_p1##x,_p1##y,z,v)), \
  1433    (I[23] = (img)(_p1##x,y,z,v)), \
  1434    (I[30] = (img)(_p1##x,_n1##y,z,v)), \
  1435    (I[37] = (img)(_p1##x,_n2##y,z,v)), \
  1436    (I[44] = (img)(_p1##x,_n3##y,z,v)), \
  1437    (I[3] = (img)(x,_p3##y,z,v)), \
  1438    (I[10] = (img)(x,_p2##y,z,v)), \
  1439    (I[17] = (img)(x,_p1##y,z,v)), \
  1440    (I[24] = (img)(x,y,z,v)), \
  1441    (I[31] = (img)(x,_n1##y,z,v)), \
  1442    (I[38] = (img)(x,_n2##y,z,v)), \
  1443    (I[45] = (img)(x,_n3##y,z,v)), \
  1444    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1445    (I[11] = (img)(_n1##x,_p2##y,z,v)), \
  1446    (I[18] = (img)(_n1##x,_p1##y,z,v)), \
  1447    (I[25] = (img)(_n1##x,y,z,v)), \
  1448    (I[32] = (img)(_n1##x,_n1##y,z,v)), \
  1449    (I[39] = (img)(_n1##x,_n2##y,z,v)), \
  1450    (I[46] = (img)(_n1##x,_n3##y,z,v)), \
  1451    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1452    (I[12] = (img)(_n2##x,_p2##y,z,v)), \
  1453    (I[19] = (img)(_n2##x,_p1##y,z,v)), \
  1454    (I[26] = (img)(_n2##x,y,z,v)), \
  1455    (I[33] = (img)(_n2##x,_n1##y,z,v)), \
  1456    (I[40] = (img)(_n2##x,_n2##y,z,v)), \
  1457    (I[47] = (img)(_n2##x,_n3##y,z,v)), \
  1458    x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
  1459    x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
  1460    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1461    (I[13] = (img)(_n3##x,_p2##y,z,v)), \
  1462    (I[20] = (img)(_n3##x,_p1##y,z,v)), \
  1463    (I[27] = (img)(_n3##x,y,z,v)), \
  1464    (I[34] = (img)(_n3##x,_n1##y,z,v)), \
  1465    (I[41] = (img)(_n3##x,_n2##y,z,v)), \
  1466    (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1467    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
  1468    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
  1469    I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
  1470    I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
  1471    I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
  1472    I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
  1473    I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
  1474    I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
  1475    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1477 #define cimg_for8x8(img,x,y,z,v,I) \
  1478   cimg_for8((img).height,y) for (int x = 0, \
  1479    _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1480    _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
  1481    _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
  1482    _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
  1483    _n4##x = (int)( \
  1484    (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
  1485    (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
  1486    (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
  1487    (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
  1488    (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
  1489    (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
  1490    (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
  1491    (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
  1492    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1493    (I[12] = (img)(_n1##x,_p2##y,z,v)), \
  1494    (I[20] = (img)(_n1##x,_p1##y,z,v)), \
  1495    (I[28] = (img)(_n1##x,y,z,v)), \
  1496    (I[36] = (img)(_n1##x,_n1##y,z,v)), \
  1497    (I[44] = (img)(_n1##x,_n2##y,z,v)), \
  1498    (I[52] = (img)(_n1##x,_n3##y,z,v)), \
  1499    (I[60] = (img)(_n1##x,_n4##y,z,v)), \
  1500    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1501    (I[13] = (img)(_n2##x,_p2##y,z,v)), \
  1502    (I[21] = (img)(_n2##x,_p1##y,z,v)), \
  1503    (I[29] = (img)(_n2##x,y,z,v)), \
  1504    (I[37] = (img)(_n2##x,_n1##y,z,v)), \
  1505    (I[45] = (img)(_n2##x,_n2##y,z,v)), \
  1506    (I[53] = (img)(_n2##x,_n3##y,z,v)), \
  1507    (I[61] = (img)(_n2##x,_n4##y,z,v)), \
  1508    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1509    (I[14] = (img)(_n3##x,_p2##y,z,v)), \
  1510    (I[22] = (img)(_n3##x,_p1##y,z,v)), \
  1511    (I[30] = (img)(_n3##x,y,z,v)), \
  1512    (I[38] = (img)(_n3##x,_n1##y,z,v)), \
  1513    (I[46] = (img)(_n3##x,_n2##y,z,v)), \
  1514    (I[54] = (img)(_n3##x,_n3##y,z,v)), \
  1515    (I[62] = (img)(_n3##x,_n4##y,z,v)), \
  1516    4>=((img).width)?(int)((img).width)-1:4); \
  1517    (_n4##x<(int)((img).width) && ( \
  1518    (I[7] = (img)(_n4##x,_p3##y,z,v)), \
  1519    (I[15] = (img)(_n4##x,_p2##y,z,v)), \
  1520    (I[23] = (img)(_n4##x,_p1##y,z,v)), \
  1521    (I[31] = (img)(_n4##x,y,z,v)), \
  1522    (I[39] = (img)(_n4##x,_n1##y,z,v)), \
  1523    (I[47] = (img)(_n4##x,_n2##y,z,v)), \
  1524    (I[55] = (img)(_n4##x,_n3##y,z,v)), \
  1525    (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1526    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
  1527    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1528    I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1529    I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1530    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
  1531    I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
  1532    I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
  1533    I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
  1534    I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
  1535    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1537 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
  1538   cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1539    _p3##x = x-3<0?0:x-3, \
  1540    _p2##x = x-2<0?0:x-2, \
  1541    _p1##x = x-1<0?0:x-1, \
  1542    _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
  1543    _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
  1544    _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
  1545    _n4##x = (int)( \
  1546    (I[0] = (img)(_p3##x,_p3##y,z,v)), \
  1547    (I[8] = (img)(_p3##x,_p2##y,z,v)), \
  1548    (I[16] = (img)(_p3##x,_p1##y,z,v)), \
  1549    (I[24] = (img)(_p3##x,y,z,v)), \
  1550    (I[32] = (img)(_p3##x,_n1##y,z,v)), \
  1551    (I[40] = (img)(_p3##x,_n2##y,z,v)), \
  1552    (I[48] = (img)(_p3##x,_n3##y,z,v)), \
  1553    (I[56] = (img)(_p3##x,_n4##y,z,v)), \
  1554    (I[1] = (img)(_p2##x,_p3##y,z,v)), \
  1555    (I[9] = (img)(_p2##x,_p2##y,z,v)), \
  1556    (I[17] = (img)(_p2##x,_p1##y,z,v)), \
  1557    (I[25] = (img)(_p2##x,y,z,v)), \
  1558    (I[33] = (img)(_p2##x,_n1##y,z,v)), \
  1559    (I[41] = (img)(_p2##x,_n2##y,z,v)), \
  1560    (I[49] = (img)(_p2##x,_n3##y,z,v)), \
  1561    (I[57] = (img)(_p2##x,_n4##y,z,v)), \
  1562    (I[2] = (img)(_p1##x,_p3##y,z,v)), \
  1563    (I[10] = (img)(_p1##x,_p2##y,z,v)), \
  1564    (I[18] = (img)(_p1##x,_p1##y,z,v)), \
  1565    (I[26] = (img)(_p1##x,y,z,v)), \
  1566    (I[34] = (img)(_p1##x,_n1##y,z,v)), \
  1567    (I[42] = (img)(_p1##x,_n2##y,z,v)), \
  1568    (I[50] = (img)(_p1##x,_n3##y,z,v)), \
  1569    (I[58] = (img)(_p1##x,_n4##y,z,v)), \
  1570    (I[3] = (img)(x,_p3##y,z,v)), \
  1571    (I[11] = (img)(x,_p2##y,z,v)), \
  1572    (I[19] = (img)(x,_p1##y,z,v)), \
  1573    (I[27] = (img)(x,y,z,v)), \
  1574    (I[35] = (img)(x,_n1##y,z,v)), \
  1575    (I[43] = (img)(x,_n2##y,z,v)), \
  1576    (I[51] = (img)(x,_n3##y,z,v)), \
  1577    (I[59] = (img)(x,_n4##y,z,v)), \
  1578    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1579    (I[12] = (img)(_n1##x,_p2##y,z,v)), \
  1580    (I[20] = (img)(_n1##x,_p1##y,z,v)), \
  1581    (I[28] = (img)(_n1##x,y,z,v)), \
  1582    (I[36] = (img)(_n1##x,_n1##y,z,v)), \
  1583    (I[44] = (img)(_n1##x,_n2##y,z,v)), \
  1584    (I[52] = (img)(_n1##x,_n3##y,z,v)), \
  1585    (I[60] = (img)(_n1##x,_n4##y,z,v)), \
  1586    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1587    (I[13] = (img)(_n2##x,_p2##y,z,v)), \
  1588    (I[21] = (img)(_n2##x,_p1##y,z,v)), \
  1589    (I[29] = (img)(_n2##x,y,z,v)), \
  1590    (I[37] = (img)(_n2##x,_n1##y,z,v)), \
  1591    (I[45] = (img)(_n2##x,_n2##y,z,v)), \
  1592    (I[53] = (img)(_n2##x,_n3##y,z,v)), \
  1593    (I[61] = (img)(_n2##x,_n4##y,z,v)), \
  1594    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1595    (I[14] = (img)(_n3##x,_p2##y,z,v)), \
  1596    (I[22] = (img)(_n3##x,_p1##y,z,v)), \
  1597    (I[30] = (img)(_n3##x,y,z,v)), \
  1598    (I[38] = (img)(_n3##x,_n1##y,z,v)), \
  1599    (I[46] = (img)(_n3##x,_n2##y,z,v)), \
  1600    (I[54] = (img)(_n3##x,_n3##y,z,v)), \
  1601    (I[62] = (img)(_n3##x,_n4##y,z,v)), \
  1602    x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
  1603    x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
  1604    (I[7] = (img)(_n4##x,_p3##y,z,v)), \
  1605    (I[15] = (img)(_n4##x,_p2##y,z,v)), \
  1606    (I[23] = (img)(_n4##x,_p1##y,z,v)), \
  1607    (I[31] = (img)(_n4##x,y,z,v)), \
  1608    (I[39] = (img)(_n4##x,_n1##y,z,v)), \
  1609    (I[47] = (img)(_n4##x,_n2##y,z,v)), \
  1610    (I[55] = (img)(_n4##x,_n3##y,z,v)), \
  1611    (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1612    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
  1613    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1614    I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1615    I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1616    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
  1617    I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
  1618    I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
  1619    I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
  1620    I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
  1621    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1623 #define cimg_for9x9(img,x,y,z,v,I) \
  1624   cimg_for9((img).height,y) for (int x = 0, \
  1625    _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1626    _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
  1627    _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
  1628    _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
  1629    _n4##x = (int)( \
  1630    (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
  1631    (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
  1632    (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
  1633    (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
  1634    (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
  1635    (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
  1636    (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
  1637    (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
  1638    (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
  1639    (I[5] = (img)(_n1##x,_p4##y,z,v)), \
  1640    (I[14] = (img)(_n1##x,_p3##y,z,v)), \
  1641    (I[23] = (img)(_n1##x,_p2##y,z,v)), \
  1642    (I[32] = (img)(_n1##x,_p1##y,z,v)), \
  1643    (I[41] = (img)(_n1##x,y,z,v)), \
  1644    (I[50] = (img)(_n1##x,_n1##y,z,v)), \
  1645    (I[59] = (img)(_n1##x,_n2##y,z,v)), \
  1646    (I[68] = (img)(_n1##x,_n3##y,z,v)), \
  1647    (I[77] = (img)(_n1##x,_n4##y,z,v)), \
  1648    (I[6] = (img)(_n2##x,_p4##y,z,v)), \
  1649    (I[15] = (img)(_n2##x,_p3##y,z,v)), \
  1650    (I[24] = (img)(_n2##x,_p2##y,z,v)), \
  1651    (I[33] = (img)(_n2##x,_p1##y,z,v)), \
  1652    (I[42] = (img)(_n2##x,y,z,v)), \
  1653    (I[51] = (img)(_n2##x,_n1##y,z,v)), \
  1654    (I[60] = (img)(_n2##x,_n2##y,z,v)), \
  1655    (I[69] = (img)(_n2##x,_n3##y,z,v)), \
  1656    (I[78] = (img)(_n2##x,_n4##y,z,v)), \
  1657    (I[7] = (img)(_n3##x,_p4##y,z,v)), \
  1658    (I[16] = (img)(_n3##x,_p3##y,z,v)), \
  1659    (I[25] = (img)(_n3##x,_p2##y,z,v)), \
  1660    (I[34] = (img)(_n3##x,_p1##y,z,v)), \
  1661    (I[43] = (img)(_n3##x,y,z,v)), \
  1662    (I[52] = (img)(_n3##x,_n1##y,z,v)), \
  1663    (I[61] = (img)(_n3##x,_n2##y,z,v)), \
  1664    (I[70] = (img)(_n3##x,_n3##y,z,v)), \
  1665    (I[79] = (img)(_n3##x,_n4##y,z,v)), \
  1666    4>=((img).width)?(int)((img).width)-1:4); \
  1667    (_n4##x<(int)((img).width) && ( \
  1668    (I[8] = (img)(_n4##x,_p4##y,z,v)), \
  1669    (I[17] = (img)(_n4##x,_p3##y,z,v)), \
  1670    (I[26] = (img)(_n4##x,_p2##y,z,v)), \
  1671    (I[35] = (img)(_n4##x,_p1##y,z,v)), \
  1672    (I[44] = (img)(_n4##x,y,z,v)), \
  1673    (I[53] = (img)(_n4##x,_n1##y,z,v)), \
  1674    (I[62] = (img)(_n4##x,_n2##y,z,v)), \
  1675    (I[71] = (img)(_n4##x,_n3##y,z,v)), \
  1676    (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1677    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
  1678    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
  1679    I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1680    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
  1681    I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1682    I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
  1683    I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
  1684    I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
  1685    I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
  1686    I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
  1687    _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1689 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
  1690   cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1691    _p4##x = x-4<0?0:x-4, \
  1692    _p3##x = x-3<0?0:x-3, \
  1693    _p2##x = x-2<0?0:x-2, \
  1694    _p1##x = x-1<0?0:x-1, \
  1695    _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
  1696    _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
  1697    _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
  1698    _n4##x = (int)( \
  1699    (I[0] = (img)(_p4##x,_p4##y,z,v)), \
  1700    (I[9] = (img)(_p4##x,_p3##y,z,v)), \
  1701    (I[18] = (img)(_p4##x,_p2##y,z,v)), \
  1702    (I[27] = (img)(_p4##x,_p1##y,z,v)), \
  1703    (I[36] = (img)(_p4##x,y,z,v)), \
  1704    (I[45] = (img)(_p4##x,_n1##y,z,v)), \
  1705    (I[54] = (img)(_p4##x,_n2##y,z,v)), \
  1706    (I[63] = (img)(_p4##x,_n3##y,z,v)), \
  1707    (I[72] = (img)(_p4##x,_n4##y,z,v)), \
  1708    (I[1] = (img)(_p3##x,_p4##y,z,v)), \
  1709    (I[10] = (img)(_p3##x,_p3##y,z,v)), \
  1710    (I[19] = (img)(_p3##x,_p2##y,z,v)), \
  1711    (I[28] = (img)(_p3##x,_p1##y,z,v)), \
  1712    (I[37] = (img)(_p3##x,y,z,v)), \
  1713    (I[46] = (img)(_p3##x,_n1##y,z,v)), \
  1714    (I[55] = (img)(_p3##x,_n2##y,z,v)), \
  1715    (I[64] = (img)(_p3##x,_n3##y,z,v)), \
  1716    (I[73] = (img)(_p3##x,_n4##y,z,v)), \
  1717    (I[2] = (img)(_p2##x,_p4##y,z,v)), \
  1718    (I[11] = (img)(_p2##x,_p3##y,z,v)), \
  1719    (I[20] = (img)(_p2##x,_p2##y,z,v)), \
  1720    (I[29] = (img)(_p2##x,_p1##y,z,v)), \
  1721    (I[38] = (img)(_p2##x,y,z,v)), \
  1722    (I[47] = (img)(_p2##x,_n1##y,z,v)), \
  1723    (I[56] = (img)(_p2##x,_n2##y,z,v)), \
  1724    (I[65] = (img)(_p2##x,_n3##y,z,v)), \
  1725    (I[74] = (img)(_p2##x,_n4##y,z,v)), \
  1726    (I[3] = (img)(_p1##x,_p4##y,z,v)), \
  1727    (I[12] = (img)(_p1##x,_p3##y,z,v)), \
  1728    (I[21] = (img)(_p1##x,_p2##y,z,v)), \
  1729    (I[30] = (img)(_p1##x,_p1##y,z,v)), \
  1730    (I[39] = (img)(_p1##x,y,z,v)), \
  1731    (I[48] = (img)(_p1##x,_n1##y,z,v)), \
  1732    (I[57] = (img)(_p1##x,_n2##y,z,v)), \
  1733    (I[66] = (img)(_p1##x,_n3##y,z,v)), \
  1734    (I[75] = (img)(_p1##x,_n4##y,z,v)), \
  1735    (I[4] = (img)(x,_p4##y,z,v)), \
  1736    (I[13] = (img)(x,_p3##y,z,v)), \
  1737    (I[22] = (img)(x,_p2##y,z,v)), \
  1738    (I[31] = (img)(x,_p1##y,z,v)), \
  1739    (I[40] = (img)(x,y,z,v)), \
  1740    (I[49] = (img)(x,_n1##y,z,v)), \
  1741    (I[58] = (img)(x,_n2##y,z,v)), \
  1742    (I[67] = (img)(x,_n3##y,z,v)), \
  1743    (I[76] = (img)(x,_n4##y,z,v)), \
  1744    (I[5] = (img)(_n1##x,_p4##y,z,v)), \
  1745    (I[14] = (img)(_n1##x,_p3##y,z,v)), \
  1746    (I[23] = (img)(_n1##x,_p2##y,z,v)), \
  1747    (I[32] = (img)(_n1##x,_p1##y,z,v)), \
  1748    (I[41] = (img)(_n1##x,y,z,v)), \
  1749    (I[50] = (img)(_n1##x,_n1##y,z,v)), \
  1750    (I[59] = (img)(_n1##x,_n2##y,z,v)), \
  1751    (I[68] = (img)(_n1##x,_n3##y,z,v)), \
  1752    (I[77] = (img)(_n1##x,_n4##y,z,v)), \
  1753    (I[6] = (img)(_n2##x,_p4##y,z,v)), \
  1754    (I[15] = (img)(_n2##x,_p3##y,z,v)), \
  1755    (I[24] = (img)(_n2##x,_p2##y,z,v)), \
  1756    (I[33] = (img)(_n2##x,_p1##y,z,v)), \
  1757    (I[42] = (img)(_n2##x,y,z,v)), \
  1758    (I[51] = (img)(_n2##x,_n1##y,z,v)), \
  1759    (I[60] = (img)(_n2##x,_n2##y,z,v)), \
  1760    (I[69] = (img)(_n2##x,_n3##y,z,v)), \
  1761    (I[78] = (img)(_n2##x,_n4##y,z,v)), \
  1762    (I[7] = (img)(_n3##x,_p4##y,z,v)), \
  1763    (I[16] = (img)(_n3##x,_p3##y,z,v)), \
  1764    (I[25] = (img)(_n3##x,_p2##y,z,v)), \
  1765    (I[34] = (img)(_n3##x,_p1##y,z,v)), \
  1766    (I[43] = (img)(_n3##x,y,z,v)), \
  1767    (I[52] = (img)(_n3##x,_n1##y,z,v)), \
  1768    (I[61] = (img)(_n3##x,_n2##y,z,v)), \
  1769    (I[70] = (img)(_n3##x,_n3##y,z,v)), \
  1770    (I[79] = (img)(_n3##x,_n4##y,z,v)), \
  1771    x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
  1772    x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
  1773    (I[8] = (img)(_n4##x,_p4##y,z,v)), \
  1774    (I[17] = (img)(_n4##x,_p3##y,z,v)), \
  1775    (I[26] = (img)(_n4##x,_p2##y,z,v)), \
  1776    (I[35] = (img)(_n4##x,_p1##y,z,v)), \
  1777    (I[44] = (img)(_n4##x,y,z,v)), \
  1778    (I[53] = (img)(_n4##x,_n1##y,z,v)), \
  1779    (I[62] = (img)(_n4##x,_n2##y,z,v)), \
  1780    (I[71] = (img)(_n4##x,_n3##y,z,v)), \
  1781    (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1782    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
  1783    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
  1784    I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1785    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
  1786    I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1787    I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
  1788    I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
  1789    I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
  1790    I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
  1791    I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
  1792    _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1794 #define cimg_for2x2x2(img,x,y,z,v,I) \
  1795  cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
  1796    _n1##x = (int)( \
  1797    (I[0] = (img)(0,y,z,v)), \
  1798    (I[2] = (img)(0,_n1##y,z,v)), \
  1799    (I[4] = (img)(0,y,_n1##z,v)), \
  1800    (I[6] = (img)(0,_n1##y,_n1##z,v)), \
  1801    1>=(img).width?(int)((img).width)-1:1); \
  1802    (_n1##x<(int)((img).width) && ( \
  1803    (I[1] = (img)(_n1##x,y,z,v)), \
  1804    (I[3] = (img)(_n1##x,_n1##y,z,v)), \
  1805    (I[5] = (img)(_n1##x,y,_n1##z,v)), \
  1806    (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1807    x==--_n1##x; \
  1808    I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
  1809    ++x, ++_n1##x)
  1811 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
  1812  cimg_for_in2((img).depth,z0,z1,z) cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1813    _n1##x = (int)( \
  1814    (I[0] = (img)(x,y,z,v)), \
  1815    (I[2] = (img)(x,_n1##y,z,v)), \
  1816    (I[4] = (img)(x,y,_n1##z,v)), \
  1817    (I[6] = (img)(x,_n1##y,_n1##z,v)), \
  1818    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1819    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1820    (I[1] = (img)(_n1##x,y,z,v)), \
  1821    (I[3] = (img)(_n1##x,_n1##y,z,v)), \
  1822    (I[5] = (img)(_n1##x,y,_n1##z,v)), \
  1823    (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1824    x==--_n1##x); \
  1825    I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
  1826    ++x, ++_n1##x)
  1828 #define cimg_for3x3x3(img,x,y,z,v,I) \
  1829  cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
  1830    _p1##x = 0, \
  1831    _n1##x = (int)( \
  1832    (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
  1833    (I[3] = I[4] = (img)(0,y,_p1##z,v)),  \
  1834    (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
  1835    (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
  1836    (I[12] = I[13] = (img)(0,y,z,v)), \
  1837    (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
  1838    (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
  1839    (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
  1840    (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
  1841    1>=(img).width?(int)((img).width)-1:1); \
  1842    (_n1##x<(int)((img).width) && ( \
  1843    (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
  1844    (I[5] = (img)(_n1##x,y,_p1##z,v)), \
  1845    (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
  1846    (I[11] = (img)(_n1##x,_p1##y,z,v)), \
  1847    (I[14] = (img)(_n1##x,y,z,v)), \
  1848    (I[17] = (img)(_n1##x,_n1##y,z,v)), \
  1849    (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
  1850    (I[23] = (img)(_n1##x,y,_n1##z,v)), \
  1851    (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1852    x==--_n1##x; \
  1853    I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
  1854    I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
  1855    I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
  1856    _p1##x = x++, ++_n1##x)
  1858 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
  1859  cimg_for_in3((img).depth,z0,z1,z) cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1860    _p1##x = x-1<0?0:x-1, \
  1861    _n1##x = (int)( \
  1862    (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
  1863    (I[3] = (img)(_p1##x,y,_p1##z,v)),  \
  1864    (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
  1865    (I[9] = (img)(_p1##x,_p1##y,z,v)), \
  1866    (I[12] = (img)(_p1##x,y,z,v)), \
  1867    (I[15] = (img)(_p1##x,_n1##y,z,v)), \
  1868    (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
  1869    (I[21] = (img)(_p1##x,y,_n1##z,v)), \
  1870    (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
  1871    (I[1] = (img)(x,_p1##y,_p1##z,v)), \
  1872    (I[4] = (img)(x,y,_p1##z,v)),  \
  1873    (I[7] = (img)(x,_n1##y,_p1##z,v)), \
  1874    (I[10] = (img)(x,_p1##y,z,v)), \
  1875    (I[13] = (img)(x,y,z,v)), \
  1876    (I[16] = (img)(x,_n1##y,z,v)), \
  1877    (I[19] = (img)(x,_p1##y,_n1##z,v)), \
  1878    (I[22] = (img)(x,y,_n1##z,v)), \
  1879    (I[25] = (img)(x,_n1##y,_n1##z,v)), \
  1880    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1881    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1882    (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
  1883    (I[5] = (img)(_n1##x,y,_p1##z,v)), \
  1884    (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
  1885    (I[11] = (img)(_n1##x,_p1##y,z,v)), \
  1886    (I[14] = (img)(_n1##x,y,z,v)), \
  1887    (I[17] = (img)(_n1##x,_n1##y,z,v)), \
  1888    (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
  1889    (I[23] = (img)(_n1##x,y,_n1##z,v)), \
  1890    (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1891    x==--_n1##x); \
  1892    I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
  1893    I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
  1894    I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
  1895    _p1##x = x++, ++_n1##x)
  1897 /*------------------------------------------------
  1900  #  Definition of the cimg_library:: namespace
  1903  -------------------------------------------------*/
  1904 //! This namespace encompasses all classes and functions of the %CImg library.
  1905 /**
  1906    This namespace is defined to avoid functions and class names collisions
  1907    that could happen with the include of other C++ header files.
  1908    Anyway, it should not happen often and you should reasonnably start most of your
  1909    %CImg-based programs with
  1910    \code
  1911    #include "CImg.h"
  1912    using namespace cimg_library;
  1913    \endcode
  1914    to simplify the declaration of %CImg Library variables afterwards.
  1915 **/
  1916 namespace cimg_library {
  1918   // Declare the only four classes of the CImg Library.
  1919   //
  1920   template<typename T=float> struct CImg;
  1921   template<typename T=float> struct CImgList;
  1922   struct CImgDisplay;
  1923   struct CImgException;
  1925   // (Pre)declare the cimg namespace.
  1926   // This is not the complete namespace declaration. It only contains some
  1927   // necessary stuffs to ensure a correct declaration order of classes and functions
  1928   // defined afterwards.
  1929   //
  1930   namespace cimg {
  1932 #ifdef cimg_use_vt100
  1933     const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
  1934     const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
  1935     const char t_bold[] = { 0x1b,'[','1','m','\0' };
  1936     const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
  1937     const char t_green[] = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
  1938 #else
  1939     const char t_normal[] = { '\0' };
  1940     const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
  1941       *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
  1942 #endif
  1944     inline void info();
  1946     //! Get/set the current CImg exception mode.
  1947     /**
  1948        The way error messages are handled by CImg can be changed dynamically, using this function.
  1949        Possible values are :
  1950        - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
  1951        - 1 to display debug messages on standard error (console).
  1952        - 2 to display debug messages in modal windows (default behavior).
  1953        - 3 to do as 1 + add extra warnings (may slow down the code !).
  1954        - 4 to do as 2 + add extra warnings (may slow down the code !).
  1955      **/
  1956     inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
  1958     inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
  1959                       const char *button2_txt=0, const char *button3_txt=0,
  1960                       const char *button4_txt=0, const char *button5_txt=0,
  1961                       const char *button6_txt=0, const bool centering=false);
  1964   /*----------------------------------------------
  1966    # Definition of the CImgException structures
  1968    ----------------------------------------------*/
  1969   //! Instances of this class are thrown when errors occur during a %CImg library function call.
  1970   /**
  1971      \section ex1 Overview
  1973       CImgException is the base class of %CImg exceptions.
  1974       Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
  1975       CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
  1976       are generally used instead. These sub-classes are :
  1978       - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
  1979       correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
  1980       below will throw a \a CImgInstanceException.
  1981       \code
  1982       CImg<float> img;        // Construct an empty image.
  1983       img.blur(10);           // Try to blur the image.
  1984       \endcode
  1986       - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
  1987       Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
  1988       The example below will throw a \a CImgArgumentException.
  1989       \code
  1990       CImg<float> img(100,100,1,3);   // Define a 100x100 color image with float pixels.
  1991       img = 0;                     // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
  1992       \endcode
  1994       - \b CImgIOException : Thrown when an error occured when trying to load or save image files.
  1995       The example below will throw a \a CImgIOException.
  1996       \code
  1997       CImg<float> img("file_doesnt_exist.jpg");    // Try to load a file that doesn't exist.
  1998       \endcode
  2000       - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window.
  2001       This exception is thrown when image display request cannot be satisfied.
  2003       The parent class CImgException may be thrown itself when errors that cannot be classified in one of
  2004       the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
  2005       reserved to %CImg Library functions.
  2006       \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple
  2007       subclasses of CImgException and are thus not detailled more in this reference documentation.
  2009       \section ex2 Exception handling
  2011       When an error occurs, the %CImg Library first displays the error in a modal window.
  2012       Then, it throws an instance of the corresponding exception class, generally leading the program to stop
  2013       (this is the default behavior).
  2014       You can bypass this default behavior by handling the exceptions yourself,
  2015       using a code block <tt>try { ... } catch() { ... }</tt>.
  2016       In this case, you can avoid the apparition of the modal window, by
  2017       defining the environment variable <tt>cimg_debug</tt> to 0 before including the %CImg header file.
  2018       The example below shows how to cleanly handle %CImg Library exceptions :
  2019       \code
  2020       #define cimg_debug 0     // Disable modal window in CImg exceptions.
  2021       #define "CImg.h"
  2022       int main() {
  2023         try {
  2024           ...; // Here, do what you want.
  2026         catch (CImgInstanceException &e) {
  2027           std::fprintf(stderr,"CImg Library Error : %s",e.message);  // Display your own error message
  2028           ...                                                        // Do what you want now.
  2031       \endcode
  2032   **/
  2033   struct CImgException {
  2034 #define _cimg_exception_err(etype,disp_flag) \
  2035   cimg_std::va_list ap; va_start(ap,format); cimg_std::vsprintf(message,format,ap); va_end(ap); \
  2036   switch (cimg::exception_mode()) { \
  2037   case 0 : break; \
  2038   case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
  2039     cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
  2040   } break; \
  2041   default : cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
  2042   } \
  2043   if (cimg::exception_mode()>=3) cimg_library::cimg::info();
  2045     char message[1024]; //!< Message associated with the error that thrown the exception.
  2046     CImgException() { message[0]='\0'; }
  2047     CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
  2048   };
  2050   // The \ref CImgInstanceException class is used to throw an exception related
  2051   // to a non suitable instance encountered in a library function call.
  2052   struct CImgInstanceException: public CImgException {
  2053     CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
  2054   };
  2056   // The \ref CImgArgumentException class is used to throw an exception related
  2057   // to invalid arguments encountered in a library function call.
  2058   struct CImgArgumentException: public CImgException {
  2059     CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
  2060   };
  2062   // The \ref CImgIOException class is used to throw an exception related
  2063   // to Input/Output file problems encountered in a library function call.
  2064   struct CImgIOException: public CImgException {
  2065     CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
  2066   };
  2068   // The CImgDisplayException class is used to throw an exception related to display problems
  2069   // encountered in a library function call.
  2070   struct CImgDisplayException: public CImgException {
  2071     CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
  2072   };
  2074   // The CImgWarningException class is used to throw an exception for warnings
  2075   // encountered in a library function call.
  2076   struct CImgWarningException: public CImgException {
  2077     CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
  2078   };
  2080   /*-------------------------------------
  2082    # Definition of the namespace 'cimg'
  2084    --------------------------------------*/
  2085   //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
  2086   /**
  2087      Most of the functions and variables within this namespace are used by the library for low-level processing.
  2088      Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
  2090      \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
  2091      <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
  2092   **/
  2093   namespace cimg {
  2095     // Define the traits that will be used to determine the best data type to work with.
  2096     //
  2097     template<typename T> struct type {
  2098       static const char* string() {
  2099         static const char* s[] = { "unknown",   "unknown8",   "unknown16",  "unknown24",
  2100                                    "unknown32", "unknown40",  "unknown48",  "unknown56",
  2101                                    "unknown64", "unknown72",  "unknown80",  "unknown88",
  2102                                    "unknown96", "unknown104", "unknown112", "unknown120",
  2103                                    "unknown128" };
  2104         return s[(sizeof(T)<17)?sizeof(T):0];
  2106       static bool is_float() { return false; }
  2107       static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
  2108       static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
  2109       static const char* format() { return "%s"; }
  2110       static const char* format(const T val) { static const char *s = "unknown"; return s; }
  2111     };
  2113     template<> struct type<bool> {
  2114       static const char* string() { static const char *const s = "bool"; return s; }
  2115       static bool is_float() { return false; }
  2116       static bool min() { return false; }
  2117       static bool max() { return true; }
  2118       static const char* format() { return "%s"; }
  2119       static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
  2120     };
  2122     template<> struct type<unsigned char> {
  2123       static const char* string() { static const char *const s = "unsigned char"; return s; }
  2124       static bool is_float() { return false; }
  2125       static unsigned char min() { return 0; }
  2126       static unsigned char max() { return (unsigned char)~0U; }
  2127       static const char* format() { return "%u"; }
  2128       static unsigned int format(const unsigned char val) { return (unsigned int)val; }
  2129     };
  2131     template<> struct type<char> {
  2132       static const char* string() { static const char *const s = "char"; return s; }
  2133       static bool is_float() { return false; }
  2134       static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
  2135       static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
  2136       static const char* format() { return "%d"; }
  2137       static int format(const char val) { return (int)val; }
  2138     };
  2140     template<> struct type<signed char> {
  2141       static const char* string() { static const char *const s = "signed char"; return s; }
  2142       static bool is_float() { return false; }
  2143       static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
  2144       static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
  2145       static const char* format() { return "%d"; }
  2146       static unsigned int format(const signed char val) { return (int)val; }
  2147     };
  2149     template<> struct type<unsigned short> {
  2150       static const char* string() { static const char *const s = "unsigned short"; return s; }
  2151       static bool is_float() { return false; }
  2152       static unsigned short min() { return 0; }
  2153       static unsigned short max() { return (unsigned short)~0U; }
  2154       static const char* format() { return "%u"; }
  2155       static unsigned int format(const unsigned short val) { return (unsigned int)val; }
  2156     };
  2158     template<> struct type<short> {
  2159       static const char* string() { static const char *const s = "short"; return s; }
  2160       static bool is_float() { return false; }
  2161       static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
  2162       static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
  2163       static const char* format() { return "%d"; }
  2164       static int format(const short val) { return (int)val; }
  2165     };
  2167     template<> struct type<unsigned int> {
  2168       static const char* string() { static const char *const s = "unsigned int"; return s; }
  2169       static bool is_float() { return false; }
  2170       static unsigned int min() { return 0; }
  2171       static unsigned int max() { return (unsigned int)~0U; }
  2172       static const char* format() { return "%u"; }
  2173       static unsigned int format(const unsigned int val) { return val; }
  2174     };
  2176     template<> struct type<int> {
  2177       static const char* string() { static const char *const s = "int"; return s; }
  2178       static bool is_float() { return false; }
  2179       static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
  2180       static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
  2181       static const char* format() { return "%d"; }
  2182       static int format(const int val) { return val; }
  2183     };
  2185     template<> struct type<unsigned long> {
  2186       static const char* string() { static const char *const s = "unsigned long"; return s; }
  2187       static bool is_float() { return false; }
  2188       static unsigned long min() { return 0; }
  2189       static unsigned long max() { return (unsigned long)~0UL; }
  2190       static const char* format() { return "%lu"; }
  2191       static unsigned long format(const unsigned long val) { return val; }
  2192     };
  2194     template<> struct type<long> {
  2195       static const char* string() { static const char *const s = "long"; return s; }
  2196       static bool is_float() { return false; }
  2197       static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
  2198       static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
  2199       static const char* format() { return "%ld"; }
  2200       static long format(const long val) { return val; }
  2201     };
  2203     template<> struct type<float> {
  2204       static const char* string() { static const char *const s = "float"; return s; }
  2205       static bool is_float() { return true; }
  2206       static float min() { return -3.4E38f; }
  2207       static float max() { return  3.4E38f; }
  2208       static const char* format() { return "%g"; }
  2209       static double format(const float val) { return (double)val; }
  2210     };
  2212     template<> struct type<double> {
  2213       static const char* string() { static const char *const s = "double"; return s; }
  2214       static bool is_float() { return true; }
  2215       static double min() { return -1.7E308; }
  2216       static double max() { return  1.7E308; }
  2217       static const char* format() { return "%g"; }
  2218       static double format(const double val) { return val; }
  2219     };
  2221     template<typename T, typename t> struct superset { typedef T type; };
  2222     template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
  2223     template<> struct superset<bool,char> { typedef char type; };
  2224     template<> struct superset<bool,signed char> { typedef signed char type; };
  2225     template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
  2226     template<> struct superset<bool,short> { typedef short type; };
  2227     template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
  2228     template<> struct superset<bool,int> { typedef int type; };
  2229     template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
  2230     template<> struct superset<bool,long> { typedef long type; };
  2231     template<> struct superset<bool,float> { typedef float type; };
  2232     template<> struct superset<bool,double> { typedef double type; };
  2233     template<> struct superset<unsigned char,char> { typedef short type; };
  2234     template<> struct superset<unsigned char,signed char> { typedef short type; };
  2235     template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
  2236     template<> struct superset<unsigned char,short> { typedef short type; };
  2237     template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
  2238     template<> struct superset<unsigned char,int> { typedef int type; };
  2239     template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
  2240     template<> struct superset<unsigned char,long> { typedef long type; };
  2241     template<> struct superset<unsigned char,float> { typedef float type; };
  2242     template<> struct superset<unsigned char,double> { typedef double type; };
  2243     template<> struct superset<signed char,unsigned char> { typedef short type; };
  2244     template<> struct superset<signed char,char> { typedef short type; };
  2245     template<> struct superset<signed char,unsigned short> { typedef int type; };
  2246     template<> struct superset<signed char,short> { typedef short type; };
  2247     template<> struct superset<signed char,unsigned int> { typedef long type; };
  2248     template<> struct superset<signed char,int> { typedef int type; };
  2249     template<> struct superset<signed char,unsigned long> { typedef long type; };
  2250     template<> struct superset<signed char,long> { typedef long type; };
  2251     template<> struct superset<signed char,float> { typedef float type; };
  2252     template<> struct superset<signed char,double> { typedef double type; };
  2253     template<> struct superset<char,unsigned char> { typedef short type; };
  2254     template<> struct superset<char,signed char> { typedef short type; };
  2255     template<> struct superset<char,unsigned short> { typedef int type; };
  2256     template<> struct superset<char,short> { typedef short type; };
  2257     template<> struct superset<char,unsigned int> { typedef long type; };
  2258     template<> struct superset<char,int> { typedef int type; };
  2259     template<> struct superset<char,unsigned long> { typedef long type; };
  2260     template<> struct superset<char,long> { typedef long type; };
  2261     template<> struct superset<char,float> { typedef float type; };
  2262     template<> struct superset<char,double> { typedef double type; };
  2263     template<> struct superset<unsigned short,char> { typedef int type; };
  2264     template<> struct superset<unsigned short,signed char> { typedef int type; };
  2265     template<> struct superset<unsigned short,short> { typedef int type; };
  2266     template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
  2267     template<> struct superset<unsigned short,int> { typedef int type; };
  2268     template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
  2269     template<> struct superset<unsigned short,long> { typedef long type; };
  2270     template<> struct superset<unsigned short,float> { typedef float type; };
  2271     template<> struct superset<unsigned short,double> { typedef double type; };
  2272     template<> struct superset<short,unsigned short> { typedef int type; };
  2273     template<> struct superset<short,unsigned int> { typedef long type; };
  2274     template<> struct superset<short,int> { typedef int type; };
  2275     template<> struct superset<short,unsigned long> { typedef long type; };
  2276     template<> struct superset<short,long> { typedef long type; };
  2277     template<> struct superset<short,float> { typedef float type; };
  2278     template<> struct superset<short,double> { typedef double type; };
  2279     template<> struct superset<unsigned int,char> { typedef long type; };
  2280     template<> struct superset<unsigned int,signed char> { typedef long type; };
  2281     template<> struct superset<unsigned int,short> { typedef long type; };
  2282     template<> struct superset<unsigned int,int> { typedef long type; };
  2283     template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
  2284     template<> struct superset<unsigned int,long> { typedef long type; };
  2285     template<> struct superset<unsigned int,float> { typedef float type; };
  2286     template<> struct superset<unsigned int,double> { typedef double type; };
  2287     template<> struct superset<int,unsigned int> { typedef long type; };
  2288     template<> struct superset<int,unsigned long> { typedef long type; };
  2289     template<> struct superset<int,long> { typedef long type; };
  2290     template<> struct superset<int,float> { typedef float type; };
  2291     template<> struct superset<int,double> { typedef double type; };
  2292     template<> struct superset<unsigned long,char> { typedef long type; };
  2293     template<> struct superset<unsigned long,signed char> { typedef long type; };
  2294     template<> struct superset<unsigned long,short> { typedef long type; };
  2295     template<> struct superset<unsigned long,int> { typedef long type; };
  2296     template<> struct superset<unsigned long,long> { typedef long type; };
  2297     template<> struct superset<unsigned long,float> { typedef float type; };
  2298     template<> struct superset<unsigned long,double> { typedef double type; };
  2299     template<> struct superset<long,float> { typedef float type; };
  2300     template<> struct superset<long,double> { typedef double type; };
  2301     template<> struct superset<float,double> { typedef double type; };
  2303     template<typename t1, typename t2, typename t3> struct superset2 {
  2304       typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
  2305     };
  2307     template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
  2308       typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
  2309     };
  2311     template<typename t1, typename t2> struct last { typedef t2 type; };
  2313 #define _cimg_Tuchar  typename cimg::superset<T,unsigned char>::type
  2314 #define _cimg_Tint    typename cimg::superset<T,int>::type
  2315 #define _cimg_Tfloat  typename cimg::superset<T,float>::type
  2316 #define _cimg_Tdouble typename cimg::superset<T,double>::type
  2317 #define _cimg_Tt      typename cimg::superset<T,t>::type
  2319     // Define internal library variables.
  2320     //
  2321 #if cimg_display==1
  2322     struct X11info {
  2323       volatile unsigned int nb_wins;
  2324       pthread_t*       event_thread;
  2325       CImgDisplay*     wins[1024];
  2326       Display*         display;
  2327       unsigned int     nb_bits;
  2328       GC*              gc;
  2329       bool             blue_first;
  2330       bool             byte_order;
  2331       bool             shm_enabled;
  2332 #ifdef cimg_use_xrandr
  2333       XRRScreenSize *resolutions;
  2334       Rotation curr_rotation;
  2335       unsigned int curr_resolution;
  2336       unsigned int nb_resolutions;
  2337 #endif
  2338       X11info():nb_wins(0),event_thread(0),display(0),
  2339                 nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
  2340 #ifdef cimg_use_xrandr
  2341         resolutions = 0;
  2342         curr_rotation = 0;
  2343         curr_resolution = nb_resolutions = 0;
  2344 #endif
  2346     };
  2347 #if defined(cimg_module)
  2348     X11info& X11attr();
  2349 #elif defined(cimg_main)
  2350     X11info& X11attr() { static X11info val; return val; }
  2351 #else
  2352     inline X11info& X11attr() { static X11info val; return val; }
  2353 #endif
  2355 #elif cimg_display==2
  2356     struct Win32info {
  2357       HANDLE wait_event;
  2358       Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
  2359     };
  2360 #if defined(cimg_module)
  2361     Win32info& Win32attr();
  2362 #elif defined(cimg_main)
  2363     Win32info& Win32attr() { static Win32info val; return val; }
  2364 #else
  2365     inline Win32info& Win32attr() { static Win32info val; return val; }
  2366 #endif
  2368 #elif cimg_display==3
  2369     struct CarbonInfo {
  2370       MPCriticalRegionID windowListCR; // Protects access to the list of windows
  2371       int windowCount;                 // Count of displays used on the screen
  2372       pthread_t event_thread;          // The background event thread
  2373       MPSemaphoreID sync_event;        // Event used to perform tasks synchronizations
  2374       MPSemaphoreID wait_event;        // Event used to notify that new events occured on the display
  2375       MPQueueID com_queue;             // The message queue
  2376       CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
  2377         if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
  2378           throw CImgDisplayException("MPCreateCriticalRegion failed.");
  2379         if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
  2380           throw CImgDisplayException("MPCreateSemaphore failed.");
  2381         if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
  2382           throw CImgDisplayException("MPCreateSemaphore failed.");
  2383         if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
  2384           throw CImgDisplayException("MPCreateQueue failed.");
  2386       ~CarbonInfo() {
  2387         if (event_thread != 0) { // Terminates the resident thread, if needed
  2388           pthread_cancel(event_thread);
  2389           pthread_join(event_thread, NULL);
  2390           event_thread = 0;
  2392         if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
  2393           throw CImgDisplayException("MPDeleteCriticalRegion failed.");
  2394         if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
  2395           throw CImgDisplayException("MPDeleteEvent failed.");
  2396         if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
  2397           throw CImgDisplayException("MPDeleteEvent failed.");
  2398         if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
  2399           throw CImgDisplayException("MPDeleteQueue failed.");
  2401     };
  2402 #if defined(cimg_module)
  2403     CarbonInfo& CarbonAttr();
  2404 #elif defined(cimg_main)
  2405     CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
  2406 #else
  2407     inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
  2408 #endif
  2409 #endif
  2411 #if cimg_display==1
  2412     // Keycodes for X11-based graphical systems.
  2413     //
  2414     const unsigned int keyESC        = XK_Escape;
  2415     const unsigned int keyF1         = XK_F1;
  2416     const unsigned int keyF2         = XK_F2;
  2417     const unsigned int keyF3         = XK_F3;
  2418     const unsigned int keyF4         = XK_F4;
  2419     const unsigned int keyF5         = XK_F5;
  2420     const unsigned int keyF6         = XK_F6;
  2421     const unsigned int keyF7         = XK_F7;
  2422     const unsigned int keyF8         = XK_F8;
  2423     const unsigned int keyF9         = XK_F9;
  2424     const unsigned int keyF10        = XK_F10;
  2425     const unsigned int keyF11        = XK_F11;
  2426     const unsigned int keyF12        = XK_F12;
  2427     const unsigned int keyPAUSE      = XK_Pause;
  2428     const unsigned int key1          = XK_1;
  2429     const unsigned int key2          = XK_2;
  2430     const unsigned int key3          = XK_3;
  2431     const unsigned int key4          = XK_4;
  2432     const unsigned int key5          = XK_5;
  2433     const unsigned int key6          = XK_6;
  2434     const unsigned int key7          = XK_7;
  2435     const unsigned int key8          = XK_8;
  2436     const unsigned int key9          = XK_9;
  2437     const unsigned int key0          = XK_0;
  2438     const unsigned int keyBACKSPACE  = XK_BackSpace;
  2439     const unsigned int keyINSERT     = XK_Insert;
  2440     const unsigned int keyHOME       = XK_Home;
  2441     const unsigned int keyPAGEUP     = XK_Page_Up;
  2442     const unsigned int keyTAB        = XK_Tab;
  2443     const unsigned int keyQ          = XK_q;
  2444     const unsigned int keyW          = XK_w;
  2445     const unsigned int keyE          = XK_e;
  2446     const unsigned int keyR          = XK_r;
  2447     const unsigned int keyT          = XK_t;
  2448     const unsigned int keyY          = XK_y;
  2449     const unsigned int keyU          = XK_u;
  2450     const unsigned int keyI          = XK_i;
  2451     const unsigned int keyO          = XK_o;
  2452     const unsigned int keyP          = XK_p;
  2453     const unsigned int keyDELETE     = XK_Delete;
  2454     const unsigned int keyEND        = XK_End;
  2455     const unsigned int keyPAGEDOWN   = XK_Page_Down;
  2456     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
  2457     const unsigned int keyA          = XK_a;
  2458     const unsigned int keyS          = XK_s;
  2459     const unsigned int keyD          = XK_d;
  2460     const unsigned int keyF          = XK_f;
  2461     const unsigned int keyG          = XK_g;
  2462     const unsigned int keyH          = XK_h;
  2463     const unsigned int keyJ          = XK_j;
  2464     const unsigned int keyK          = XK_k;
  2465     const unsigned int keyL          = XK_l;
  2466     const unsigned int keyENTER      = XK_Return;
  2467     const unsigned int keySHIFTLEFT  = XK_Shift_L;
  2468     const unsigned int keyZ          = XK_z;
  2469     const unsigned int keyX          = XK_x;
  2470     const unsigned int keyC          = XK_c;
  2471     const unsigned int keyV          = XK_v;
  2472     const unsigned int keyB          = XK_b;
  2473     const unsigned int keyN          = XK_n;
  2474     const unsigned int keyM          = XK_m;
  2475     const unsigned int keySHIFTRIGHT = XK_Shift_R;
  2476     const unsigned int keyARROWUP    = XK_Up;
  2477     const unsigned int keyCTRLLEFT   = XK_Control_L;
  2478     const unsigned int keyAPPLEFT    = XK_Super_L;
  2479     const unsigned int keyALT        = XK_Alt_L;
  2480     const unsigned int keySPACE      = XK_space;
  2481     const unsigned int keyALTGR      = XK_Alt_R;
  2482     const unsigned int keyAPPRIGHT   = XK_Super_R;
  2483     const unsigned int keyMENU       = XK_Menu;
  2484     const unsigned int keyCTRLRIGHT  = XK_Control_R;
  2485     const unsigned int keyARROWLEFT  = XK_Left;
  2486     const unsigned int keyARROWDOWN  = XK_Down;
  2487     const unsigned int keyARROWRIGHT = XK_Right;
  2488     const unsigned int keyPAD0       = XK_KP_0;
  2489     const unsigned int keyPAD1       = XK_KP_1;
  2490     const unsigned int keyPAD2       = XK_KP_2;
  2491     const unsigned int keyPAD3       = XK_KP_3;
  2492     const unsigned int keyPAD4       = XK_KP_4;
  2493     const unsigned int keyPAD5       = XK_KP_5;
  2494     const unsigned int keyPAD6       = XK_KP_6;
  2495     const unsigned int keyPAD7       = XK_KP_7;
  2496     const unsigned int keyPAD8       = XK_KP_8;
  2497     const unsigned int keyPAD9       = XK_KP_9;
  2498     const unsigned int keyPADADD     = XK_KP_Add;
  2499     const unsigned int keyPADSUB     = XK_KP_Subtract;
  2500     const unsigned int keyPADMUL     = XK_KP_Multiply;
  2501     const unsigned int keyPADDIV     = XK_KP_Divide;
  2503 #elif cimg_display==2
  2504     // Keycodes for Windows.
  2505     //
  2506     const unsigned int keyESC        = VK_ESCAPE;
  2507     const unsigned int keyF1         = VK_F1;
  2508     const unsigned int keyF2         = VK_F2;
  2509     const unsigned int keyF3         = VK_F3;
  2510     const unsigned int keyF4         = VK_F4;
  2511     const unsigned int keyF5         = VK_F5;
  2512     const unsigned int keyF6         = VK_F6;
  2513     const unsigned int keyF7         = VK_F7;
  2514     const unsigned int keyF8         = VK_F8;
  2515     const unsigned int keyF9         = VK_F9;
  2516     const unsigned int keyF10        = VK_F10;
  2517     const unsigned int keyF11        = VK_F11;
  2518     const unsigned int keyF12        = VK_F12;
  2519     const unsigned int keyPAUSE      = VK_PAUSE;
  2520     const unsigned int key1          = '1';
  2521     const unsigned int key2          = '2';
  2522     const unsigned int key3          = '3';
  2523     const unsigned int key4          = '4';
  2524     const unsigned int key5          = '5';
  2525     const unsigned int key6          = '6';
  2526     const unsigned int key7          = '7';
  2527     const unsigned int key8          = '8';
  2528     const unsigned int key9          = '9';
  2529     const unsigned int key0          = '0';
  2530     const unsigned int keyBACKSPACE  = VK_BACK;
  2531     const unsigned int keyINSERT     = VK_INSERT;
  2532     const unsigned int keyHOME       = VK_HOME;
  2533     const unsigned int keyPAGEUP     = VK_PRIOR;
  2534     const unsigned int keyTAB        = VK_TAB;
  2535     const unsigned int keyQ          = 'Q';
  2536     const unsigned int keyW          = 'W';
  2537     const unsigned int keyE          = 'E';
  2538     const unsigned int keyR          = 'R';
  2539     const unsigned int keyT          = 'T';
  2540     const unsigned int keyY          = 'Y';
  2541     const unsigned int keyU          = 'U';
  2542     const unsigned int keyI          = 'I';
  2543     const unsigned int keyO          = 'O';
  2544     const unsigned int keyP          = 'P';
  2545     const unsigned int keyDELETE     = VK_DELETE;
  2546     const unsigned int keyEND        = VK_END;
  2547     const unsigned int keyPAGEDOWN   = VK_NEXT;
  2548     const unsigned int keyCAPSLOCK   = VK_CAPITAL;
  2549     const unsigned int keyA          = 'A';
  2550     const unsigned int keyS          = 'S';
  2551     const unsigned int keyD          = 'D';
  2552     const unsigned int keyF          = 'F';
  2553     const unsigned int keyG          = 'G';
  2554     const unsigned int keyH          = 'H';
  2555     const unsigned int keyJ          = 'J';
  2556     const unsigned int keyK          = 'K';
  2557     const unsigned int keyL          = 'L';
  2558     const unsigned int keyENTER      = VK_RETURN;
  2559     const unsigned int keySHIFTLEFT  = VK_SHIFT;
  2560     const unsigned int keyZ          = 'Z';
  2561     const unsigned int keyX          = 'X';
  2562     const unsigned int keyC          = 'C';
  2563     const unsigned int keyV          = 'V';
  2564     const unsigned int keyB          = 'B';
  2565     const unsigned int keyN          = 'N';
  2566     const unsigned int keyM          = 'M';
  2567     const unsigned int keySHIFTRIGHT = VK_SHIFT;
  2568     const unsigned int keyARROWUP    = VK_UP;
  2569     const unsigned int keyCTRLLEFT   = VK_CONTROL;
  2570     const unsigned int keyAPPLEFT    = VK_LWIN;
  2571     const unsigned int keyALT        = VK_LMENU;
  2572     const unsigned int keySPACE      = VK_SPACE;
  2573     const unsigned int keyALTGR      = VK_CONTROL;
  2574     const unsigned int keyAPPRIGHT   = VK_RWIN;
  2575     const unsigned int keyMENU       = VK_APPS;
  2576     const unsigned int keyCTRLRIGHT  = VK_CONTROL;
  2577     const unsigned int keyARROWLEFT  = VK_LEFT;
  2578     const unsigned int keyARROWDOWN  = VK_DOWN;
  2579     const unsigned int keyARROWRIGHT = VK_RIGHT;
  2580     const unsigned int keyPAD0       = 0x60;
  2581     const unsigned int keyPAD1       = 0x61;
  2582     const unsigned int keyPAD2       = 0x62;
  2583     const unsigned int keyPAD3       = 0x63;
  2584     const unsigned int keyPAD4       = 0x64;
  2585     const unsigned int keyPAD5       = 0x65;
  2586     const unsigned int keyPAD6       = 0x66;
  2587     const unsigned int keyPAD7       = 0x67;
  2588     const unsigned int keyPAD8       = 0x68;
  2589     const unsigned int keyPAD9       = 0x69;
  2590     const unsigned int keyPADADD     = VK_ADD;
  2591     const unsigned int keyPADSUB     = VK_SUBTRACT;
  2592     const unsigned int keyPADMUL     = VK_MULTIPLY;
  2593     const unsigned int keyPADDIV     = VK_DIVIDE;
  2595 #elif cimg_display==3
  2596     // Keycodes for MacOSX, when using the Carbon framework.
  2597     //
  2598     const unsigned int keyESC        = kEscapeCharCode;
  2599     const unsigned int keyF1         = 2U;
  2600     const unsigned int keyF2         = 3U;
  2601     const unsigned int keyF3         = 4U;
  2602     const unsigned int keyF4         = 5U;
  2603     const unsigned int keyF5         = 6U;
  2604     const unsigned int keyF6         = 7U;
  2605     const unsigned int keyF7         = 8U;
  2606     const unsigned int keyF8         = 9U;
  2607     const unsigned int keyF9         = 10U;
  2608     const unsigned int keyF10        = 11U;
  2609     const unsigned int keyF11        = 12U;
  2610     const unsigned int keyF12        = 13U;
  2611     const unsigned int keyPAUSE      = 14U;
  2612     const unsigned int key1          = '1';
  2613     const unsigned int key2          = '2';
  2614     const unsigned int key3          = '3';
  2615     const unsigned int key4          = '4';
  2616     const unsigned int key5          = '5';
  2617     const unsigned int key6          = '6';
  2618     const unsigned int key7          = '7';
  2619     const unsigned int key8          = '8';
  2620     const unsigned int key9          = '9';
  2621     const unsigned int key0          = '0';
  2622     const unsigned int keyBACKSPACE  = kBackspaceCharCode;
  2623     const unsigned int keyINSERT     = 26U;
  2624     const unsigned int keyHOME       = kHomeCharCode;
  2625     const unsigned int keyPAGEUP     = kPageUpCharCode;
  2626     const unsigned int keyTAB        = kTabCharCode;
  2627     const unsigned int keyQ          = 'q';
  2628     const unsigned int keyW          = 'w';
  2629     const unsigned int keyE          = 'e';
  2630     const unsigned int keyR          = 'r';
  2631     const unsigned int keyT          = 't';
  2632     const unsigned int keyY          = 'y';
  2633     const unsigned int keyU          = 'u';
  2634     const unsigned int keyI          = 'i';
  2635     const unsigned int keyO          = 'o';
  2636     const unsigned int keyP          = 'p';
  2637     const unsigned int keyDELETE     = kDeleteCharCode;
  2638     const unsigned int keyEND        = kEndCharCode;
  2639     const unsigned int keyPAGEDOWN   = kPageDownCharCode;
  2640     const unsigned int keyCAPSLOCK   = 43U;
  2641     const unsigned int keyA          = 'a';
  2642     const unsigned int keyS          = 's';
  2643     const unsigned int keyD          = 'd';
  2644     const unsigned int keyF          = 'f';
  2645     const unsigned int keyG          = 'g';
  2646     const unsigned int keyH          = 'h';
  2647     const unsigned int keyJ          = 'j';
  2648     const unsigned int keyK          = 'k';
  2649     const unsigned int keyL          = 'l';
  2650     const unsigned int keyENTER      = kEnterCharCode;
  2651     const unsigned int keySHIFTLEFT  = 54U; //Macintosh modifier key, emulated
  2652     const unsigned int keyZ          = 'z';
  2653     const unsigned int keyX          = 'x';
  2654     const unsigned int keyC          = 'c';
  2655     const unsigned int keyV          = 'v';
  2656     const unsigned int keyB          = 'b';
  2657     const unsigned int keyN          = 'n';
  2658     const unsigned int keyM          = 'm';
  2659     const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
  2660     const unsigned int keyARROWUP    = kUpArrowCharCode;
  2661     const unsigned int keyCTRLLEFT   = 64U; //Macintosh modifier key, emulated
  2662     const unsigned int keyAPPLEFT    = 65U; //Macintosh modifier key, emulated
  2663     const unsigned int keyALT        = 66U;
  2664     const unsigned int keySPACE      = kSpaceCharCode;
  2665     const unsigned int keyALTGR      = 67U; //Macintosh modifier key, emulated
  2666     const unsigned int keyAPPRIGHT   = 68U; //Aliased on keyAPPLEFT
  2667     const unsigned int keyMENU       = 69U;
  2668     const unsigned int keyCTRLRIGHT  = 70U; //Macintosh modifier key, emulated
  2669     const unsigned int keyARROWLEFT  = kLeftArrowCharCode;
  2670     const unsigned int keyARROWDOWN  = kDownArrowCharCode;
  2671     const unsigned int keyARROWRIGHT = kRightArrowCharCode;
  2672     const unsigned int keyPAD0       = 74U;
  2673     const unsigned int keyPAD1       = 75U;
  2674     const unsigned int keyPAD2       = 76U;
  2675     const unsigned int keyPAD3       = 77U;
  2676     const unsigned int keyPAD4       = 78U;
  2677     const unsigned int keyPAD5       = 79U;
  2678     const unsigned int keyPAD6       = 80U;
  2679     const unsigned int keyPAD7       = 81U;
  2680     const unsigned int keyPAD8       = 82U;
  2681     const unsigned int keyPAD9       = 83U;
  2682     const unsigned int keyPADADD     = 84U;
  2683     const unsigned int keyPADSUB     = 85U;
  2684     const unsigned int keyPADMUL     = 86U;
  2685     const unsigned int keyPADDIV     = 87U;
  2687 #else
  2688     // Define unknow keycodes when no display are available.
  2689     // (should rarely be used then !).
  2690     //
  2691     const unsigned int keyESC        = 1U;
  2692     const unsigned int keyF1         = 2U;
  2693     const unsigned int keyF2         = 3U;
  2694     const unsigned int keyF3         = 4U;
  2695     const unsigned int keyF4         = 5U;
  2696     const unsigned int keyF5         = 6U;
  2697     const unsigned int keyF6         = 7U;
  2698     const unsigned int keyF7         = 8U;
  2699     const unsigned int keyF8         = 9U;
  2700     const unsigned int keyF9         = 10U;
  2701     const unsigned int keyF10        = 11U;
  2702     const unsigned int keyF11        = 12U;
  2703     const unsigned int keyF12        = 13U;
  2704     const unsigned int keyPAUSE      = 14U;
  2705     const unsigned int key1          = 15U;
  2706     const unsigned int key2          = 16U;
  2707     const unsigned int key3          = 17U;
  2708     const unsigned int key4          = 18U;
  2709     const unsigned int key5          = 19U;
  2710     const unsigned int key6          = 20U;
  2711     const unsigned int key7          = 21U;
  2712     const unsigned int key8          = 22U;
  2713     const unsigned int key9          = 23U;
  2714     const unsigned int key0          = 24U;
  2715     const unsigned int keyBACKSPACE  = 25U;
  2716     const unsigned int keyINSERT     = 26U;
  2717     const unsigned int keyHOME       = 27U;
  2718     const unsigned int keyPAGEUP     = 28U;
  2719     const unsigned int keyTAB        = 29U;
  2720     const unsigned int keyQ          = 30U;
  2721     const unsigned int keyW          = 31U;
  2722     const unsigned int keyE          = 32U;
  2723     const unsigned int keyR          = 33U;
  2724     const unsigned int keyT          = 34U;
  2725     const unsigned int keyY          = 35U;
  2726     const unsigned int keyU          = 36U;
  2727     const unsigned int keyI          = 37U;
  2728     const unsigned int keyO          = 38U;
  2729     const unsigned int keyP          = 39U;
  2730     const unsigned int keyDELETE     = 40U;
  2731     const unsigned int keyEND        = 41U;
  2732     const unsigned int keyPAGEDOWN   = 42U;
  2733     const unsigned int keyCAPSLOCK   = 43U;
  2734     const unsigned int keyA          = 44U;
  2735     const unsigned int keyS          = 45U;
  2736     const unsigned int keyD          = 46U;
  2737     const unsigned int keyF          = 47U;
  2738     const unsigned int keyG          = 48U;
  2739     const unsigned int keyH          = 49U;
  2740     const unsigned int keyJ          = 50U;
  2741     const unsigned int keyK          = 51U;
  2742     const unsigned int keyL          = 52U;
  2743     const unsigned int keyENTER      = 53U;
  2744     const unsigned int keySHIFTLEFT  = 54U;
  2745     const unsigned int keyZ          = 55U;
  2746     const unsigned int keyX          = 56U;
  2747     const unsigned int keyC          = 57U;
  2748     const unsigned int keyV          = 58U;
  2749     const unsigned int keyB          = 59U;
  2750     const unsigned int keyN          = 60U;
  2751     const unsigned int keyM          = 61U;
  2752     const unsigned int keySHIFTRIGHT = 62U;
  2753     const unsigned int keyARROWUP    = 63U;
  2754     const unsigned int keyCTRLLEFT   = 64U;
  2755     const unsigned int keyAPPLEFT    = 65U;
  2756     const unsigned int keyALT        = 66U;
  2757     const unsigned int keySPACE      = 67U;
  2758     const unsigned int keyALTGR      = 68U;
  2759     const unsigned int keyAPPRIGHT   = 69U;
  2760     const unsigned int keyMENU       = 70U;
  2761     const unsigned int keyCTRLRIGHT  = 71U;
  2762     const unsigned int keyARROWLEFT  = 72U;
  2763     const unsigned int keyARROWDOWN  = 73U;
  2764     const unsigned int keyARROWRIGHT = 74U;
  2765     const unsigned int keyPAD0       = 75U;
  2766     const unsigned int keyPAD1       = 76U;
  2767     const unsigned int keyPAD2       = 77U;
  2768     const unsigned int keyPAD3       = 78U;
  2769     const unsigned int keyPAD4       = 79U;
  2770     const unsigned int keyPAD5       = 80U;
  2771     const unsigned int keyPAD6       = 81U;
  2772     const unsigned int keyPAD7       = 82U;
  2773     const unsigned int keyPAD8       = 83U;
  2774     const unsigned int keyPAD9       = 84U;
  2775     const unsigned int keyPADADD     = 85U;
  2776     const unsigned int keyPADSUB     = 86U;
  2777     const unsigned int keyPADMUL     = 87U;
  2778     const unsigned int keyPADDIV     = 88U;
  2779 #endif
  2781     const double valuePI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI
  2783     // Definition of a 7x11 font, used to return a default font for drawing text.
  2784     const unsigned int font7x11[7*11*256/32] = {
  2785       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2786       0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
  2787       0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
  2788       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2789       0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
  2790       0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
  2791       0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
  2792       0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
  2793       0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
  2794       0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
  2795       0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2796       0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
  2797       0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2798       0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
  2799       0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2800       0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
  2801       0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2802       0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
  2803       0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2804       0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
  2805       0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2806       0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
  2807       0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2808       0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
  2809       0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
  2810       0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
  2811       0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
  2812       0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
  2813       0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
  2814       0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
  2815       0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
  2816       0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
  2817       0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
  2818       0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
  2819       0x400000,0x44,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x62018,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x80000800,
  2820       0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
  2821       0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
  2822     };
  2824     // Definition of a 10x13 font (used in dialog boxes).
  2825     const unsigned int font10x13[256*10*13/32] = {
  2826       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2827       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0,
  2828       0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2829       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2830       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120,
  2831       0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2832       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2833       0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2834       0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
  2835       0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
  2836       0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
  2837       0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
  2838       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
  2839       0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
  2840       0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
  2841       0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
  2842       0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
  2843       0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
  2844       0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
  2845       0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
  2846       0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
  2847       0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
  2848       0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
  2849       0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
  2850       0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
  2851       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
  2852       0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
  2853       0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2854       0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
  2855       0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
  2856       0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
  2857       0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
  2858       0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
  2859       0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
  2860       0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
  2861       0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
  2862       0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
  2863       0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
  2864       0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2865       0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
  2866       0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
  2867       0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
  2868       0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
  2869       0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
  2870       0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
  2871       0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
  2872       0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
  2873       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
  2874       0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
  2875       0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
  2876       0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
  2877       0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
  2878       0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
  2879       0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
  2880       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
  2881       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,
  2882       0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
  2883       0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0,
  2884       0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
  2885     };
  2887     // Definition of a 8x17 font.
  2888     const unsigned int font8x17[8*17*256/32] = {
  2889       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2890       0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
  2891       0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
  2892       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
  2893       0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
  2894       0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
  2895       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
  2896       0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
  2897       0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
  2898       0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
  2899       0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
  2900       0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
  2901       0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
  2902       0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
  2903       0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
  2904       0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
  2905       0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
  2906       0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
  2907       0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
  2908       0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
  2909       0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
  2910       0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
  2911       0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
  2912       0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
  2913       0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
  2914       0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
  2915       0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
  2916       0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
  2917       0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
  2918       0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
  2919       0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
  2920       0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
  2921       0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
  2922       0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
  2923       0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
  2924       0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
  2925       0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
  2926       0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
  2927       0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
  2928       0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
  2929       0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
  2930       0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
  2931       0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
  2932       0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
  2933       0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
  2934       0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
  2935       0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
  2936       0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
  2937       0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
  2938       0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
  2939       0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
  2940       0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
  2941       0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
  2942       0x0,0x0,0x0,0x1000,0x1078,0x0,0x0,0x0,0x400500,0x0,0x1e081e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2943       0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
  2944       0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
  2945       0x0,0x0,0x400000,0x8000000,0x41e0400,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x104010,0x0,0x0,0x0,0x0,
  2946       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x1c,0x7000,0x0,0x40020000,0x0,0x300000,
  2947       0x0,0xe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x0,0x0,0x0,0x400000,0x38000000,0x0,0x0,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2948       0x1c,0x0,0x0,0x0,0x0,0x0,0x304030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2949       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2950       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2951       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2952       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  2954     // Definition of a 10x19 font.
  2955     const unsigned int font10x19[10*19*256/32] = {
  2956       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2957       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3600000,0x36000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2958       0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
  2959       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2960       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x1c000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,
  2961       0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
  2962       0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  2963       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x2200000,
  2964       0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
  2965       0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
  2966       0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
  2967       0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
  2968       0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
  2969       0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
  2970       0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
  2971       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
  2972       0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
  2973       0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
  2974       0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
  2975       0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
  2976       0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
  2977       0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
  2978       0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
  2979       0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
  2980       0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
  2981       0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
  2982       0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
  2983       0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
  2984       0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
  2985       0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
  2986       0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
  2987       0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
  2988       0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
  2989       0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
  2990       0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
  2991       0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
  2992       0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
  2993       0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
  2994       0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
  2995       0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
  2996       0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
  2997       0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
  2998       0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
  2999       0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
  3000       0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
  3001       0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
  3002       0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
  3003       0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
  3004       0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
  3005       0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
  3006       0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
  3007       0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
  3008       0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
  3009       0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
  3010       0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
  3011       0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
  3012       0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
  3013       0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
  3014       0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
  3015       0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
  3016       0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
  3017       0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
  3018       0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
  3019       0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
  3020       0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
  3021       0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
  3022       0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
  3023       0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
  3024       0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
  3025       0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
  3026       0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
  3027       0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
  3028       0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
  3029       0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
  3030       0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
  3031       0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
  3032       0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
  3033       0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
  3034       0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
  3035       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0xc06,0xc,0x100,0x0,0x0,0x0,0x3000,0x0,0x20000000,0x0,0x0,0x0,0x0,0xc000,
  3036       0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
  3037       0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3038       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1040010,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x60c,0x18,0x0,
  3039       0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
  3040       0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
  3041       0x2,0x1e02000,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x2040020,0x0,0x0,0x0,0x0,
  3042       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x4000,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3043       0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
  3044       0x0,0x0,0x0,0x1000,0x1c00,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0xe0400e0,
  3045       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc,
  3046       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3047       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  3049     // Definition of a 12x24 font.
  3050      const unsigned int font12x24[12*24*256/32] = {
  3051        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3052        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0,
  3053        0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
  3054        0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3055        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3056        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,
  3057        0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
  3058        0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3059        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3060        0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019,
  3061        0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
  3062        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3063        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000,
  3064        0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
  3065        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
  3066        0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
  3067        0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
  3068        0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
  3069        0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
  3070        0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
  3071        0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
  3072        0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
  3073        0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
  3074        0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
  3075        0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
  3076        0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
  3077        0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
  3078        0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
  3079        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
  3080        0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
  3081        0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
  3082        0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
  3083        0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
  3084        0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
  3085        0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
  3086        0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
  3087        0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
  3088        0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
  3089        0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
  3090        0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
  3091        0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
  3092        0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
  3093        0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
  3094        0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
  3095        0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
  3096        0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
  3097        0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
  3098        0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
  3099        0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
  3100        0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
  3101        0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
  3102        0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
  3103        0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
  3104        0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
  3105        0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
  3106        0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
  3107        0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
  3108        0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
  3109        0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
  3110        0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
  3111        0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
  3112        0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
  3113        0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
  3114        0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
  3115        0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
  3116        0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
  3117        0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
  3118        0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
  3119        0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
  3120        0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
  3121        0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
  3122        0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
  3123        0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
  3124        0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
  3125        0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
  3126        0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
  3127        0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
  3128        0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
  3129        0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
  3130        0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
  3131        0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
  3132        0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
  3133        0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
  3134        0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
  3135        0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
  3136        0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
  3137        0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
  3138        0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
  3139        0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
  3140        0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
  3141        0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
  3142        0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
  3143        0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
  3144        0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
  3145        0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
  3146        0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
  3147        0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
  3148        0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
  3149        0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
  3150        0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
  3151        0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
  3152        0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
  3153        0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
  3154        0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
  3155        0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
  3156        0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
  3157        0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
  3158        0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
  3159        0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
  3160        0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
  3161        0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
  3162        0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
  3163        0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
  3164        0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
  3165        0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
  3166        0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
  3167        0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
  3168        0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
  3169        0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
  3170        0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
  3171        0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3172        0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,
  3173        0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
  3174        0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
  3175        0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0,
  3176        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0,
  3177        0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
  3178        0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0,
  3179        0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3180        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,
  3181        0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3182        0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,
  3183        0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3184        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3185        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3186        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  3188     // Definition of a 16x32 font.
  3189     const unsigned int font16x32[16*32*256/32] = {
  3190       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3191       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3192       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3193       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
  3194       0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3195       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3196       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3197       0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3198       0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
  3199       0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3200       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3201       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
  3202       0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380,
  3203       0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
  3204       0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3205       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3206       0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,
  3207       0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
  3208       0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
  3209       0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3210       0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3211       0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
  3212       0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
  3213       0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3214       0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
  3215       0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
  3216       0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
  3217       0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
  3218       0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
  3219       0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
  3220       0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
  3221       0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
  3222       0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
  3223       0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
  3224       0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
  3225       0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
  3226       0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
  3227       0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
  3228       0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
  3229       0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
  3230       0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
  3231       0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
  3232       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
  3233       0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
  3234       0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
  3235       0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
  3236       0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
  3237       0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
  3238       0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
  3239       0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
  3240       0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
  3241       0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
  3242       0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
  3243       0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
  3244       0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
  3245       0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
  3246       0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
  3247       0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
  3248       0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
  3249       0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
  3250       0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
  3251       0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
  3252       0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
  3253       0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
  3254       0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
  3255       0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
  3256       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
  3257       0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
  3258       0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
  3259       0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
  3260       0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
  3261       0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
  3262       0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
  3263       0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
  3264       0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
  3265       0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
  3266       0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
  3267       0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
  3268       0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
  3269       0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
  3270       0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
  3271       0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
  3272       0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
  3273       0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
  3274       0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3275       0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
  3276       0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
  3277       0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
  3278       0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
  3279       0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
  3280       0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
  3281       0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
  3282       0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
  3283       0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3284       0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
  3285       0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
  3286       0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
  3287       0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
  3288       0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
  3289       0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
  3290       0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
  3291       0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
  3292       0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
  3293       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
  3294       0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
  3295       0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
  3296       0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
  3297       0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
  3298       0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
  3299       0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
  3300       0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
  3301       0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
  3302       0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
  3303       0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
  3304       0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
  3305       0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
  3306       0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
  3307       0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
  3308       0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
  3309       0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
  3310       0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
  3311       0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
  3312       0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
  3313       0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
  3314       0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
  3315       0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
  3316       0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
  3317       0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
  3318       0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
  3319       0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
  3320       0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
  3321       0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
  3322       0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
  3323       0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
  3324       0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
  3325       0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
  3326       0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  3327       0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
  3328       0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
  3329       0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
  3330       0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
  3331       0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
  3332       0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
  3333       0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
  3334       0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
  3335       0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  3336       0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
  3337       0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
  3338       0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
  3339       0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
  3340       0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
  3341       0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
  3342       0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
  3343       0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
  3344       0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
  3345       0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
  3346       0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
  3347       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
  3348       0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
  3349       0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
  3350       0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
  3351       0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
  3352       0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
  3353       0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  3354       0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
  3355       0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
  3356       0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
  3357       0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
  3358       0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
  3359       0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
  3360       0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
  3361       0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
  3362       0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
  3363       0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
  3364       0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
  3365       0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
  3366       0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
  3367       0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
  3368       0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
  3369       0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
  3370       0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
  3371       0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
  3372       0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
  3373       0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
  3374       0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
  3375       0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
  3376       0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
  3377       0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
  3378       0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
  3379       0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
  3380       0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
  3381       0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
  3382       0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
  3383       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0,
  3384       0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000,
  3385       0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3386       0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
  3387       0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,
  3388       0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000,
  3389       0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0,
  3390       0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
  3391       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
  3392       0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,
  3393       0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,
  3394       0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,
  3395       0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
  3396       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
  3397       0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,
  3398       0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,
  3399       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3400       0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
  3401       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
  3402       0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3403       0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3404       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000,
  3405       0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3406       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3407       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3408       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3409       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0,
  3410       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3411       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3412       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3413       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3414       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3415       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3416       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3417       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3418       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3419       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3420       0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  3422     // Definition of a 19x38 font.
  3423     const unsigned int font19x38[19*38*256/32] = {
  3424       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3425       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3426       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c380000,0x0,0x1c380,0x0,0x0,0x0,0x0,0x0,
  3427       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800007,0x3c003,0x86000000,
  3428       0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
  3429       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3430       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3431       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3432       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe700000,0x0,0xe700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3433       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
  3434       0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
  3435       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3436       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3437       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3438       0x0,0x0,0x0,0x7e00000,0x0,0x7e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3439       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
  3440       0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0,
  3441       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3442       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3443       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
  3444       0x0,0x3c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3445       0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
  3446       0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3447       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3448       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3449       0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60000000,0x0,0x0,
  3450       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c38,0x0,0x1,0xc3800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x0,
  3451       0x0,0x0,0x0,0x0,0x0,0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000003,0x80018000,0x0,0xc180000,
  3452       0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
  3453       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3454       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,0x0,0x0,0x0,
  3455       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78c00,0xc30,
  3456       0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
  3457       0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
  3458       0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3459       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3460       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x3800000,0x700000,0x38,
  3461       0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
  3462       0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
  3463       0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3464       0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
  3465       0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3466       0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
  3467       0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
  3468       0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
  3469       0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
  3470       0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
  3471       0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
  3472       0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
  3473       0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
  3474       0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
  3475       0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61800600,0x7f8001ff,0x70000,
  3476       0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
  3477       0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
  3478       0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
  3479       0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
  3480       0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
  3481       0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
  3482       0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
  3483       0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
  3484       0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3485       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
  3486       0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
  3487       0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
  3488       0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
  3489       0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
  3490       0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
  3491       0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
  3492       0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
  3493       0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
  3494       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
  3495       0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
  3496       0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
  3497       0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
  3498       0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
  3499       0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
  3500       0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
  3501       0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
  3502       0x0,0x0,0x0,0x0,0x0,0x0,0xff0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3503       0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
  3504       0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
  3505       0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
  3506       0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
  3507       0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
  3508       0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
  3509       0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
  3510       0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
  3511       0x0,0x0,0x0,0x7,0x80000080,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,
  3512       0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
  3513       0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
  3514       0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
  3515       0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
  3516       0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
  3517       0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
  3518       0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
  3519       0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
  3520       0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
  3521       0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3522       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
  3523       0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
  3524       0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
  3525       0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
  3526       0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
  3527       0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
  3528       0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
  3529       0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
  3530       0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
  3531       0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
  3532       0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3533       0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
  3534       0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
  3535       0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
  3536       0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
  3537       0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
  3538       0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
  3539       0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
  3540       0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
  3541       0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
  3542       0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
  3543       0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
  3544       0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
  3545       0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
  3546       0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
  3547       0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
  3548       0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
  3549       0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
  3550       0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
  3551       0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
  3552       0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
  3553       0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
  3554       0xc1e0e03c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1,0x8701c600,0x1e0f01e0,0x1,
  3555       0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
  3556       0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
  3557       0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
  3558       0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
  3559       0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
  3560       0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
  3561       0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
  3562       0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
  3563       0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
  3564       0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
  3565       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
  3566       0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
  3567       0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
  3568       0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
  3569       0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
  3570       0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
  3571       0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
  3572       0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
  3573       0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
  3574       0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
  3575       0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3576       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
  3577       0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
  3578       0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
  3579       0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
  3580       0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
  3581       0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
  3582       0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
  3583       0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
  3584       0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
  3585       0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
  3586       0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3587       0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
  3588       0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
  3589       0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
  3590       0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
  3591       0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
  3592       0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
  3593       0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
  3594       0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
  3595       0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
  3596       0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
  3597       0xe0381c0,0x700e1c07,0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0xc000ff0,
  3598       0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
  3599       0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
  3600       0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
  3601       0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
  3602       0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
  3603       0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
  3604       0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
  3605       0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
  3606       0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
  3607       0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
  3608       0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x7f,0xffc00678,0x707f9c1e,0x38000001,
  3609       0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
  3610       0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
  3611       0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
  3612       0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
  3613       0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
  3614       0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
  3615       0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
  3616       0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
  3617       0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
  3618       0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3619       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
  3620       0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
  3621       0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
  3622       0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
  3623       0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
  3624       0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
  3625       0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
  3626       0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
  3627       0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
  3628       0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
  3629       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0061c,0xc0dc07,0xf0000001,0xc0000700,
  3630       0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
  3631       0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
  3632       0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
  3633       0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
  3634       0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
  3635       0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
  3636       0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
  3637       0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
  3638       0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
  3639       0xe0381c0,0x70077807,0x701de0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x1c00061c,
  3640       0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
  3641       0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
  3642       0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
  3643       0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
  3644       0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
  3645       0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
  3646       0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
  3647       0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
  3648       0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
  3649       0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3650       0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
  3651       0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
  3652       0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
  3653       0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
  3654       0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
  3655       0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
  3656       0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
  3657       0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
  3658       0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
  3659       0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
  3660       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
  3661       0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
  3662       0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
  3663       0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
  3664       0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
  3665       0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
  3666       0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
  3667       0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
  3668       0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
  3669       0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
  3670       0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3671       0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
  3672       0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
  3673       0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
  3674       0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
  3675       0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
  3676       0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
  3677       0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
  3678       0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
  3679       0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
  3680       0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3681       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
  3682       0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
  3683       0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
  3684       0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
  3685       0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
  3686       0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
  3687       0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
  3688       0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
  3689       0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
  3690       0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
  3691       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x30007fc0,0x1e00f8,0x78000000,0x70001c00,
  3692       0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
  3693       0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
  3694       0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
  3695       0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
  3696       0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
  3697       0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
  3698       0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
  3699       0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
  3700       0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
  3701       0x1f000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x70001c00,0x0,
  3702       0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
  3703       0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
  3704       0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  3705       0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
  3706       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,
  3707       0x0,0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x30001800,
  3708       0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
  3709       0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
  3710       0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  3711       0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
  3712       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3713       0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x38003800,
  3714       0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
  3715       0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
  3716       0x78000e,0x3c000,0x0,0x0,0x180001,0xc0018300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,
  3717       0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
  3718       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3719       0x38007,0xe00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x18003000,
  3720       0x0,0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,
  3721       0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
  3722       0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  3723       0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
  3724       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78007,
  3725       0x1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,
  3726       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,
  3727       0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
  3728       0x0,0x10007f,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x38,0x0,0x0,0x0,0x0,
  3729       0x0,0x0,0x0,0x0,0x3800,0x0,0x1f800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3730       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f8007,0xfe00,0x0,0x0,0x0,0x0,
  3731       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3732       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x7fe000,0x0,
  3733       0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3734       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1f000,0x0,0x0,0x0,0x0,0x0,
  3735       0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,
  3736       0x0,0x0,0x0,0x0,0x0,0x0,0x3f0007,0xfc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3737       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3738       0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
  3739       0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3740       0x0,0x0,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3741       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0007,0xf000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3742       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3743       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3744       0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3745       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3746       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  3748     // Definition of a 29x57 font.
  3749     const unsigned int font29x57[29*57*256/32] = {
  3750       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3751       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3752       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3753       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3754       0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3755       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7,
  3756       0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
  3757       0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3758       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3759       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3760       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3761       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3762       0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,
  3763       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,
  3764       0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
  3765       0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
  3766       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3767       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3768       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3769       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3770       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
  3771       0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3772       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
  3773       0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
  3774       0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3775       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3776       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3777       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3778       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3779       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
  3780       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3781       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
  3782       0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
  3783       0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3784       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3785       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3786       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3787       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3788       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3789       0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3790       0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
  3791       0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
  3792       0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3793       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3794       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3795       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3796       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3797       0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,
  3798       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003,
  3799       0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
  3800       0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
  3801       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3802       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3803       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3804       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3805       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3806       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3807       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3808       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3809       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3810       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3811       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3812       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3813       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3814       0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0,
  3815       0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3816       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
  3817       0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
  3818       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3819       0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3820       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000,
  3821       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3822       0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0,
  3823       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00,
  3824       0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,
  3825       0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
  3826       0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3827       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0,
  3828       0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
  3829       0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0,
  3830       0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
  3831       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0,
  3832       0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000,
  3833       0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
  3834       0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
  3835       0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
  3836       0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
  3837       0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3838       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
  3839       0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
  3840       0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
  3841       0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
  3842       0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
  3843       0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
  3844       0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
  3845       0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
  3846       0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
  3847       0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
  3848       0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
  3849       0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
  3850       0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
  3851       0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3852       0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
  3853       0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
  3854       0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
  3855       0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
  3856       0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
  3857       0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
  3858       0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
  3859       0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
  3860       0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
  3861       0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
  3862       0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
  3863       0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
  3864       0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
  3865       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
  3866       0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
  3867       0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
  3868       0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
  3869       0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
  3870       0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
  3871       0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
  3872       0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
  3873       0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
  3874       0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
  3875       0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
  3876       0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
  3877       0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
  3878       0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
  3879       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000,
  3880       0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
  3881       0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
  3882       0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
  3883       0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
  3884       0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
  3885       0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
  3886       0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
  3887       0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
  3888       0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
  3889       0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
  3890       0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
  3891       0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
  3892       0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3893       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f,
  3894       0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
  3895       0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
  3896       0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
  3897       0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
  3898       0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
  3899       0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
  3900       0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
  3901       0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
  3902       0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  3903       0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
  3904       0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
  3905       0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
  3906       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3907       0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
  3908       0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
  3909       0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
  3910       0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
  3911       0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
  3912       0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
  3913       0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
  3914       0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
  3915       0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
  3916       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
  3917       0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
  3918       0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
  3919       0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3920       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
  3921       0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
  3922       0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
  3923       0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
  3924       0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
  3925       0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
  3926       0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
  3927       0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
  3928       0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
  3929       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
  3930       0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3931       0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3932       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
  3933       0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
  3934       0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
  3935       0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
  3936       0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
  3937       0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,
  3938       0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
  3939       0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
  3940       0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
  3941       0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
  3942       0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
  3943       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000,
  3944       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3945       0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
  3946       0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
  3947       0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
  3948       0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
  3949       0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
  3950       0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
  3951       0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
  3952       0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
  3953       0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
  3954       0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
  3955       0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
  3956       0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
  3957       0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
  3958       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,
  3959       0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
  3960       0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
  3961       0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
  3962       0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
  3963       0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
  3964       0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
  3965       0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
  3966       0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
  3967       0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
  3968       0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
  3969       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
  3970       0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
  3971       0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
  3972       0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
  3973       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
  3974       0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
  3975       0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
  3976       0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
  3977       0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
  3978       0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
  3979       0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
  3980       0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
  3981       0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
  3982       0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
  3983       0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
  3984       0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
  3985       0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
  3986       0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
  3987       0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
  3988       0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  3989       0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
  3990       0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
  3991       0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
  3992       0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
  3993       0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
  3994       0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
  3995       0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
  3996       0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
  3997       0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
  3998       0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
  3999       0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
  4000       0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
  4001       0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
  4002       0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
  4003       0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
  4004       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
  4005       0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
  4006       0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
  4007       0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
  4008       0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
  4009       0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
  4010       0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
  4011       0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
  4012       0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
  4013       0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
  4014       0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
  4015       0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
  4016       0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
  4017       0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
  4018       0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
  4019       0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4020       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
  4021       0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
  4022       0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
  4023       0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
  4024       0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
  4025       0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
  4026       0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
  4027       0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
  4028       0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
  4029       0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
  4030       0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
  4031       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
  4032       0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
  4033       0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
  4034       0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
  4035       0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4036       0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
  4037       0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
  4038       0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
  4039       0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
  4040       0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
  4041       0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
  4042       0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
  4043       0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
  4044       0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
  4045       0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
  4046       0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
  4047       0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
  4048       0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
  4049       0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
  4050       0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4051       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
  4052       0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
  4053       0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
  4054       0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
  4055       0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
  4056       0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
  4057       0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
  4058       0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
  4059       0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
  4060       0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
  4061       0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
  4062       0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
  4063       0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
  4064       0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
  4065       0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
  4066       0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4067       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
  4068       0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
  4069       0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
  4070       0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
  4071       0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
  4072       0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
  4073       0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
  4074       0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
  4075       0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
  4076       0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
  4077       0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
  4078       0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
  4079       0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
  4080       0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
  4081       0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4082       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007,
  4083       0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
  4084       0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
  4085       0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
  4086       0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
  4087       0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
  4088       0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
  4089       0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
  4090       0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
  4091       0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
  4092       0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
  4093       0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
  4094       0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
  4095       0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
  4096       0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
  4097       0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4098       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
  4099       0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
  4100       0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
  4101       0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
  4102       0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
  4103       0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
  4104       0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
  4105       0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
  4106       0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
  4107       0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
  4108       0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
  4109       0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
  4110       0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
  4111       0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
  4112       0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
  4113       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007,
  4114       0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
  4115       0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
  4116       0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
  4117       0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
  4118       0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
  4119       0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
  4120       0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
  4121       0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
  4122       0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
  4123       0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
  4124       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
  4125       0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
  4126       0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
  4127       0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
  4128       0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4129       0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
  4130       0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
  4131       0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
  4132       0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
  4133       0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
  4134       0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
  4135       0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
  4136       0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
  4137       0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
  4138       0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
  4139       0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  4140       0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
  4141       0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
  4142       0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
  4143       0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4144       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f,
  4145       0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
  4146       0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
  4147       0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
  4148       0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
  4149       0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
  4150       0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
  4151       0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
  4152       0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
  4153       0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
  4154       0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
  4155       0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
  4156       0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
  4157       0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
  4158       0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
  4159       0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4160       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
  4161       0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
  4162       0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
  4163       0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
  4164       0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
  4165       0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
  4166       0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
  4167       0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
  4168       0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
  4169       0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
  4170       0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  4171       0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
  4172       0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
  4173       0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
  4174       0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4175       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
  4176       0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
  4177       0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
  4178       0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
  4179       0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
  4180       0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
  4181       0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
  4182       0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
  4183       0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
  4184       0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
  4185       0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
  4186       0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
  4187       0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
  4188       0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
  4189       0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
  4190       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001,
  4191       0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
  4192       0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
  4193       0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
  4194       0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
  4195       0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
  4196       0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
  4197       0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
  4198       0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
  4199       0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
  4200       0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
  4201       0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
  4202       0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
  4203       0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
  4204       0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4205       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
  4206       0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
  4207       0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
  4208       0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
  4209       0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
  4210       0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
  4211       0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
  4212       0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
  4213       0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
  4214       0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
  4215       0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  4216       0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
  4217       0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
  4218       0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
  4219       0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4220       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
  4221       0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
  4222       0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
  4223       0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
  4224       0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
  4225       0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
  4226       0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
  4227       0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
  4228       0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
  4229       0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
  4230       0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
  4231       0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
  4232       0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
  4233       0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
  4234       0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4235       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
  4236       0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
  4237       0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
  4238       0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
  4239       0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
  4240       0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
  4241       0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
  4242       0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
  4243       0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
  4244       0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
  4245       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
  4246       0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
  4247       0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
  4248       0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
  4249       0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4250       0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
  4251       0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
  4252       0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
  4253       0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
  4254       0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
  4255       0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
  4256       0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
  4257       0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
  4258       0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
  4259       0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
  4260       0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
  4261       0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
  4262       0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
  4263       0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
  4264       0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4265       0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
  4266       0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
  4267       0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
  4268       0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
  4269       0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
  4270       0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
  4271       0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
  4272       0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
  4273       0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
  4274       0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
  4275       0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
  4276       0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
  4277       0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
  4278       0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
  4279       0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4280       0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
  4281       0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
  4282       0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
  4283       0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
  4284       0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
  4285       0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
  4286       0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
  4287       0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
  4288       0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
  4289       0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
  4290       0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
  4291       0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
  4292       0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
  4293       0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
  4294       0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4295       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
  4296       0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
  4297       0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
  4298       0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
  4299       0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
  4300       0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
  4301       0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
  4302       0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
  4303       0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
  4304       0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
  4305       0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
  4306       0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
  4307       0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
  4308       0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
  4309       0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
  4310       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,
  4311       0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
  4312       0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
  4313       0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
  4314       0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
  4315       0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
  4316       0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
  4317       0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
  4318       0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
  4319       0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
  4320       0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
  4321       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
  4322       0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
  4323       0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
  4324       0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
  4325       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f,
  4326       0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
  4327       0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
  4328       0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
  4329       0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
  4330       0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
  4331       0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
  4332       0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
  4333       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
  4334       0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
  4335       0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
  4336       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
  4337       0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
  4338       0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
  4339       0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
  4340       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003,
  4341       0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
  4342       0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
  4343       0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
  4344       0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
  4345       0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
  4346       0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
  4347       0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
  4348       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
  4349       0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
  4350       0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
  4351       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
  4352       0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
  4353       0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
  4354       0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
  4355       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
  4356       0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
  4357       0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
  4358       0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
  4359       0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
  4360       0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4361       0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
  4362       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
  4363       0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
  4364       0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
  4365       0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
  4366       0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4367       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4368       0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0,
  4369       0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,
  4370       0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
  4371       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000,
  4372       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
  4373       0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4374       0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0,
  4375       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
  4376       0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000,
  4377       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,
  4378       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000,
  4379       0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4380       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4381       0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4382       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4383       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4384       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000,
  4385       0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4386       0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,
  4387       0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
  4388       0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4389       0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,
  4390       0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4391       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4392       0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4393       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4394       0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,
  4395       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
  4396       0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
  4397       0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,
  4398       0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
  4399       0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4400       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000,
  4401       0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4402       0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,
  4403       0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,
  4404       0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
  4405       0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4406       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,
  4407       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
  4408       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0,
  4409       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4410       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,
  4411       0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0,
  4412       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,
  4413       0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
  4414       0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4415       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,
  4416       0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4417       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4418       0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4419       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4420       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4421       0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
  4422       0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4423       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4424       0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,
  4425       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0,
  4426       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4427       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4428       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4429       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0,
  4430       0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
  4431       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4432       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,
  4433       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0,
  4434       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4435       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4436       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4437       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
  4438       0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0,
  4439       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4440       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4441       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4442       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4443       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4444       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4445       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4446       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4447       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4448       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4449       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4450       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4451       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4452       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4453       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,
  4454       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4455       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4456       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  4457       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  4459     // Definition of a 40x38 'danger' color logo.
  4460     const unsigned char logo40x38[4576] = {
  4461       177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
  4462       1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
  4463       0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
  4464       1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
  4465       2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
  4466       255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
  4467       189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
  4468       189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
  4469       22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
  4470       1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
  4471       0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
  4472       123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
  4473       189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
  4474       0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
  4475       189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255,
  4476       0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123,
  4477       123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189,
  4478       189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255,
  4479       0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189,
  4480       189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1,
  4481       0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255,
  4482       255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123,
  4483       123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86,
  4484       200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
  4486     //! Display a warning message.
  4487     /**
  4488         \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
  4489     **/
  4490     inline void warn(const char *format, ...) {
  4491       if (cimg::exception_mode()>=1) {
  4492         char message[8192];
  4493         cimg_std::va_list ap;
  4494         va_start(ap,format);
  4495         cimg_std::vsprintf(message,format,ap);
  4496         va_end(ap);
  4497 #ifdef cimg_strict_warnings
  4498         throw CImgWarningException(message);
  4499 #else
  4500         cimg_std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
  4501 #endif
  4505     // Execute an external system command.
  4506     /**
  4507        \note This function is similar to <tt>std::system()</tt>
  4508        and is here because using the <tt>std::</tt> version on
  4509        Windows may open undesired consoles.
  4510      **/
  4511     inline int system(const char *const command, const char *const module_name=0) {
  4512 #if cimg_OS==2
  4513       PROCESS_INFORMATION pi;
  4514       STARTUPINFO si;
  4515       cimg_std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
  4516       cimg_std::memset(&si,0,sizeof(STARTUPINFO));
  4517       GetStartupInfo(&si);
  4518       si.cb = sizeof(si);
  4519       si.wShowWindow = SW_HIDE;
  4520       si.dwFlags |= SW_HIDE;
  4521       const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
  4522       if (res) {
  4523         WaitForSingleObject(pi.hProcess, INFINITE);
  4524         CloseHandle(pi.hThread);
  4525         CloseHandle(pi.hProcess);
  4526         return 0;
  4527       } else
  4528 #endif
  4529         return cimg_std::system(command);
  4530       return module_name?0:1;
  4533     //! Return a reference to a temporary variable of type T.
  4534     template<typename T>
  4535     inline T& temporary(const T&) {
  4536       static T temp;
  4537       return temp;
  4540     //! Exchange values of variables \p a and \p b.
  4541     template<typename T>
  4542     inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
  4544     //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
  4545     template<typename T1, typename T2>
  4546     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
  4547       cimg::swap(a1,b1); cimg::swap(a2,b2);
  4550     //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
  4551     template<typename T1, typename T2, typename T3>
  4552     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
  4553       cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
  4556     //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
  4557     template<typename T1, typename T2, typename T3, typename T4>
  4558     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
  4559       cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
  4562     //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
  4563     template<typename T1, typename T2, typename T3, typename T4, typename T5>
  4564     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
  4565       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
  4568     //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
  4569     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
  4570     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {
  4571       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
  4574     //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
  4575     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
  4576     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
  4577                      T7& a7, T7& b7) {
  4578       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
  4581     //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
  4582     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
  4583     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
  4584                      T7& a7, T7& b7, T8& a8, T8& b8) {
  4585       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
  4588     //! Return the current endianness of the CPU.
  4589     /**
  4590        \return \c false for "Little Endian", \c true for "Big Endian".
  4591     **/
  4592     inline bool endianness() {
  4593       const int x = 1;
  4594       return ((unsigned char*)&x)[0]?false:true;
  4597     //! Invert endianness of a memory buffer.
  4598     template<typename T>
  4599     inline void invert_endianness(T* const buffer, const unsigned int size) {
  4600       if (size) switch (sizeof(T)) {
  4601       case 1 : break;
  4602       case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
  4603         const unsigned short val = *(--ptr);
  4604         *ptr = (unsigned short)((val>>8)|((val<<8)));
  4605       }} break;
  4606       case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
  4607         const unsigned int val = *(--ptr);
  4608         *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
  4609       }} break;
  4610       default : { for (T* ptr = buffer+size; ptr>buffer; ) {
  4611         unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
  4612         for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
  4613       }}
  4617     //! Invert endianness of a single variable.
  4618     template<typename T>
  4619     inline T& invert_endianness(T& a) {
  4620       invert_endianness(&a,1);
  4621       return a;
  4624     //! Get the value of a system timer with a millisecond precision.
  4625     inline unsigned long time() {
  4626 #if cimg_OS==1
  4627       struct timeval st_time;
  4628       gettimeofday(&st_time,0);
  4629       return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
  4630 #elif cimg_OS==2
  4631       static SYSTEMTIME st_time;
  4632       GetSystemTime(&st_time);
  4633       return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
  4634 #else
  4635       return 0;
  4636 #endif
  4639     //! Sleep for a certain numbers of milliseconds.
  4640     /**
  4641        This function frees the CPU ressources during the sleeping time.
  4642        It may be used to temporize your program properly, without wasting CPU time.
  4643     **/
  4644     inline void sleep(const unsigned int milliseconds) {
  4645 #if cimg_OS==1
  4646       struct timespec tv;
  4647       tv.tv_sec = milliseconds/1000;
  4648       tv.tv_nsec = (milliseconds%1000)*1000000;
  4649       nanosleep(&tv,0);
  4650 #elif cimg_OS==2
  4651       Sleep(milliseconds);
  4652 #endif
  4655     inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
  4656       if (!timer) timer = cimg::time();
  4657       const unsigned long current_time = cimg::time();
  4658       if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
  4659       const unsigned long time_diff = timer + milliseconds - current_time;
  4660       timer = current_time + time_diff;
  4661       cimg::sleep(time_diff);
  4662       return (unsigned int)time_diff;
  4665     //! Wait for a certain number of milliseconds since the last call.
  4666     /**
  4667        This function is equivalent to sleep() but the waiting time is computed with regard to the last call
  4668        of wait(). It may be used to temporize your program properly.
  4669     **/
  4670     inline unsigned int wait(const unsigned int milliseconds) {
  4671       static unsigned long timer = 0;
  4672       if (!timer) timer = cimg::time();
  4673       return _sleep(milliseconds,timer);
  4676     // Use a specific srand initialization to avoid multi-threads to have to the
  4677     // same series of random numbers (executed only once for a single program).
  4678     inline void srand() {
  4679       static bool first_time = true;
  4680       if (first_time) {
  4681         cimg_std::srand(cimg::time());
  4682         unsigned char *const rand_ptr = new unsigned char[1+cimg_std::rand()%2048];
  4683         cimg_std::srand((unsigned int)cimg_std::rand() + *(unsigned int*)(void*)rand_ptr);
  4684         delete[] rand_ptr;
  4685         first_time = false;
  4689     //! Return a left bitwise-rotated number.
  4690     template<typename T>
  4691     inline const T rol(const T a, const unsigned int n=1) {
  4692       return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
  4695     //! Return a right bitwise-rotated number.
  4696     template<typename T>
  4697     inline const T ror(const T a, const unsigned int n=1) {
  4698       return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
  4701     //! Return the absolute value of a number.
  4702     /**
  4703        \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
  4704        because it is able to consider a variable of any type, without cast needed.
  4705     **/
  4706     template<typename T>
  4707     inline T abs(const T a) {
  4708       return a>=0?a:-a;
  4710     inline bool abs(const bool a) {
  4711       return a;
  4713     inline unsigned char abs(const unsigned char a) {
  4714       return a;
  4716     inline unsigned short abs(const unsigned short a) {
  4717       return a;
  4719     inline unsigned int abs(const unsigned int a) {
  4720       return a;
  4722     inline unsigned long abs(const unsigned long a) {
  4723       return a;
  4725     inline double abs(const double a) {
  4726       return cimg_std::fabs(a);
  4728     inline float abs(const float a) {
  4729       return (float)cimg_std::fabs((double)a);
  4731     inline int abs(const int a) {
  4732       return cimg_std::abs(a);
  4735     //! Return the square of a number.
  4736     template<typename T>
  4737     inline T sqr(const T val) {
  4738       return val*val;
  4741     //! Return 1 + log_10(x).
  4742     inline int xln(const int x) {
  4743       return x>0?(int)(1+cimg_std::log10((double)x)):1;
  4746     //! Return the minimum value between two numbers.
  4747     template<typename t1, typename t2>
  4748     inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
  4749       typedef typename cimg::superset<t1,t2>::type t1t2;
  4750       return (t1t2)(a<=b?a:b);
  4753     //! Return the minimum value between three numbers.
  4754     template<typename t1, typename t2, typename t3>
  4755     inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
  4756       typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
  4757       return (t1t2t3)cimg::min(cimg::min(a,b),c);
  4760     //! Return the minimum value between four numbers.
  4761     template<typename t1, typename t2, typename t3, typename t4>
  4762     inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
  4763       typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
  4764       return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
  4767     //! Return the maximum value between two numbers.
  4768     template<typename t1, typename t2>
  4769     inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
  4770       typedef typename cimg::superset<t1,t2>::type t1t2;
  4771       return (t1t2)(a>=b?a:b);
  4774     //! Return the maximum value between three numbers.
  4775     template<typename t1, typename t2, typename t3>
  4776     inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
  4777       typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
  4778       return (t1t2t3)cimg::max(cimg::max(a,b),c);
  4781     //! Return the maximum value between four numbers.
  4782     template<typename t1, typename t2, typename t3, typename t4>
  4783     inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
  4784       typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
  4785       return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
  4788     //! Return the sign of a number.
  4789     template<typename T>
  4790     inline T sign(const T x) {
  4791       return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
  4794     //! Return the nearest power of 2 higher than a given number.
  4795     template<typename T>
  4796     inline unsigned long nearest_pow2(const T x) {
  4797       unsigned long i = 1;
  4798       while (x>i) i<<=1;
  4799       return i;
  4802     //! Return the modulo of a number.
  4803     /**
  4804        \note This modulo function accepts negative and floating-points modulo numbers, as well as
  4805        variable of any type.
  4806     **/
  4807     template<typename T>
  4808     inline T mod(const T& x, const T& m) {
  4809       const double dx = (double)x, dm = (double)m;
  4810       if (x<0) { return (T)(dm+dx+dm*cimg_std::floor(-dx/dm)); }
  4811       return (T)(dx-dm*cimg_std::floor(dx/dm));
  4813     inline int mod(const bool x, const bool m) {
  4814       return m?(x?1:0):0;
  4816     inline int mod(const char x, const char m) {
  4817       return x>=0?x%m:(x%m?m+x%m:0);
  4819     inline int mod(const short x, const short m) {
  4820       return x>=0?x%m:(x%m?m+x%m:0);
  4822     inline int mod(const int x, const int m) {
  4823       return x>=0?x%m:(x%m?m+x%m:0);
  4825     inline int mod(const long x, const long m) {
  4826       return x>=0?x%m:(x%m?m+x%m:0);
  4828     inline int mod(const unsigned char x, const unsigned char m) {
  4829       return x%m;
  4831     inline int mod(const unsigned short x, const unsigned short m) {
  4832       return x%m;
  4834     inline int mod(const unsigned int x, const unsigned int m) {
  4835       return x%m;
  4837     inline int mod(const unsigned long x, const unsigned long m) {
  4838       return x%m;
  4841     //! Return the minmod of two numbers.
  4842     /**
  4843        <i>minmod(\p a,\p b)</i> is defined to be :
  4844        - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
  4845        - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
  4846     **/
  4847     template<typename T>
  4848     inline T minmod(const T a, const T b) {
  4849       return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
  4852     //! Return a random variable between [0,1] with respect to an uniform distribution.
  4853     inline double rand() {
  4854       static bool first_time = true;
  4855       if (first_time) { cimg::srand(); first_time = false; }
  4856       return (double)cimg_std::rand()/RAND_MAX;
  4859     //! Return a random variable between [-1,1] with respect to an uniform distribution.
  4860     inline double crand() {
  4861       return 1-2*cimg::rand();
  4864     //! Return a random variable following a gaussian distribution and a standard deviation of 1.
  4865     inline double grand() {
  4866       double x1, w;
  4867       do {
  4868         const double x2 = 2*cimg::rand() - 1.0;
  4869         x1 = 2*cimg::rand()-1.0;
  4870         w = x1*x1 + x2*x2;
  4871       } while (w<=0 || w>=1.0);
  4872       return x1*cimg_std::sqrt((-2*cimg_std::log(w))/w);
  4875     //! Return a random variable following a Poisson distribution of parameter z.
  4876     inline unsigned int prand(const double z) {
  4877       if (z<=1.0e-10) return 0;
  4878       if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
  4879       unsigned int k = 0;
  4880       const double y = std::exp(-z);
  4881       for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
  4882       return k-1;
  4885     //! Return a rounded number.
  4886     /**
  4887        \param x is the number to be rounded.
  4888        \param y is the rounding precision.
  4889        \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward).
  4890     **/
  4891     inline double round(const double x, const double y, const int rounding_type=0) {
  4892       if (y<=0) return x;
  4893       const double delta = cimg::mod(x,y);
  4894       if (delta==0.0) return x;
  4895       const double
  4896         backward = x - delta,
  4897         forward = backward + y;
  4898       return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
  4901     inline double _pythagore(double a, double b) {
  4902       const double absa = cimg::abs(a), absb = cimg::abs(b);
  4903       if (absa>absb) { const double tmp = absb/absa; return absa*cimg_std::sqrt(1.0+tmp*tmp); }
  4904       else { const double tmp = absa/absb; return (absb==0?0:absb*cimg_std::sqrt(1.0+tmp*tmp)); }
  4907     //! Remove the 'case' of an ASCII character.
  4908     inline char uncase(const char x) {
  4909       return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
  4912     //! Remove the 'case' of a C string.
  4913     /**
  4914        Acts in-place.
  4915     **/
  4916     inline void uncase(char *const string) {
  4917       if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
  4920     //! Read a float number from a C-string.
  4921     /**
  4922        \note This function is quite similar to <tt>std::atof()</tt>,
  4923        but that it allows the retrieval of fractions as in "1/2".
  4924     **/
  4925     inline float atof(const char *const str) {
  4926       float x = 0,y = 1;
  4927       if (!str) return 0; else { cimg_std::sscanf(str,"%g/%g",&x,&y); return x/y; }
  4930     //! Compute the length of a C-string.
  4931     /**
  4932        \note This function is similar to <tt>std::strlen()</tt>
  4933        and is here because some old compilers do not
  4934        define the <tt>std::</tt> version.
  4935     **/
  4936     inline int strlen(const char *const s) {
  4937       if (!s) return -1;
  4938       int k = 0;
  4939       for (const char *ns = s; *ns; ++ns) ++k;
  4940       return k;
  4943     //! Compare the first \p n characters of two C-strings.
  4944     /**
  4945        \note This function is similar to <tt>std::strncmp()</tt>
  4946        and is here because some old compilers do not
  4947        define the <tt>std::</tt> version.
  4948     **/
  4949     inline int strncmp(const char *const s1, const char *const s2, const int l) {
  4950       if (!s1) return s2?-1:0;
  4951       const char *ns1 = s1, *ns2 = s2;
  4952       int k, diff = 0; for (k = 0; k<l && !(diff = *ns1-*ns2); ++k) { ++ns1; ++ns2; }
  4953       return k!=l?diff:0;
  4956     //! Compare the first \p n characters of two C-strings, ignoring the case.
  4957     /**
  4958        \note This function is similar to <tt>std::strncasecmp()</tt>
  4959        and is here because some old compilers do not
  4960        define the <tt>std::</tt> version.
  4961     **/
  4962     inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
  4963       if (!s1) return s2?-1:0;
  4964       const char *ns1 = s1, *ns2 = s2;
  4965       int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
  4966       return k!=l?diff:0;
  4969     //! Compare two C-strings.
  4970     /**
  4971        \note This function is similar to <tt>std::strcmp()</tt>
  4972        and is here because some old compilers do not
  4973        define the <tt>std::</tt> version.
  4974     **/
  4975     inline int strcmp(const char *const s1, const char *const s2) {
  4976       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
  4977       return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
  4980     //! Compare two C-strings, ignoring the case.
  4981     /**
  4982        \note This function is similar to <tt>std::strcasecmp()</tt>
  4983        and is here because some old compilers do not
  4984        define the <tt>std::</tt> version.
  4985     **/
  4986     inline int strcasecmp(const char *const s1, const char *const s2) {
  4987       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
  4988       return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
  4991     //! Find a character in a C-string.
  4992     inline int strfind(const char *const s, const char c) {
  4993       if (!s) return -1;
  4994       int l; for (l = cimg::strlen(s); l>=0 && s[l]!=c; --l) {}
  4995       return l;
  4998     //! Remove useless delimiters on the borders of a C-string
  4999     inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
  5000       if (!s) return false;
  5001       const int l = cimg::strlen(s);
  5002       int p, q;
  5003       if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
  5004       else {
  5005         for (p = 0; p<l && s[p]==delimiter; ) ++p;
  5006         for (q = l-1; q>p && s[q]==delimiter; ) --q;
  5008       const int n = q - p + 1;
  5009       if (n!=l) { cimg_std::memmove(s,s+p,n); s[n] = '\0'; return true; }
  5010       return false;
  5013     //! Remove useless spaces and symmetric delimiters ', " and ` from a C-string.
  5014     inline void strclean(char *const s) {
  5015       if (!s) return;
  5016       strpare(s,' ',false);
  5017       for (bool need_iter = true; need_iter; ) {
  5018         need_iter = false;
  5019         need_iter |= strpare(s,'\'',true);
  5020         need_iter |= strpare(s,'\"',true);
  5021         need_iter |= strpare(s,'`',true);
  5025     //! Replace explicit escape sequences '\x' in C-strings (where x in [ntvbrfa?'"0]).
  5026     inline void strescape(char *const s) {
  5027 #define cimg_strescape(ci,co) case ci: *nd = co; break;
  5028       char *ns, *nd;
  5029       for (ns = nd = s; *ns; ++ns, ++nd)
  5030         if (*ns=='\\') switch (*(++ns)) {
  5031             cimg_strescape('n','\n');
  5032             cimg_strescape('t','\t');
  5033             cimg_strescape('v','\v');
  5034             cimg_strescape('b','\b');
  5035             cimg_strescape('r','\r');
  5036             cimg_strescape('f','\f');
  5037             cimg_strescape('a','\a');
  5038             cimg_strescape('\\','\\');
  5039             cimg_strescape('\?','\?');
  5040             cimg_strescape('\'','\'');
  5041             cimg_strescape('\"','\"');
  5042             cimg_strescape('\0','\0');
  5044         else *nd = *ns;
  5045       *nd = 0;
  5048     //! Compute the basename of a filename.
  5049     inline const char* basename(const char *const s)  {
  5050       return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
  5053     // Generate a random filename.
  5054     inline const char* filenamerand() {
  5055       static char id[9] = { 0,0,0,0,0,0,0,0,0 };
  5056       cimg::srand();
  5057       for (unsigned int k=0; k<8; ++k) {
  5058         const int v = (int)cimg_std::rand()%3;
  5059         id[k] = (char)(v==0?('0'+(cimg_std::rand()%10)):(v==1?('a'+(cimg_std::rand()%26)):('A'+(cimg_std::rand()%26))));
  5061       return id;
  5064     // Convert filename into a Windows-style filename.
  5065     inline void winformat_string(char *const s) {
  5066       if (s && s[0]) {
  5067 #if cimg_OS==2
  5068         char *const ns = new char[MAX_PATH];
  5069         if (GetShortPathNameA(s,ns,MAX_PATH)) cimg_std::strcpy(s,ns);
  5070 #endif
  5074     //! Return or set path to store temporary files.
  5075     inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
  5076 #define _cimg_test_temporary_path(p) \
  5077       if (!path_found) { \
  5078         cimg_std::sprintf(st_path,"%s",p); \
  5079         cimg_std::sprintf(tmp,"%s%s%s",st_path,cimg_OS==2?"\\":"/",filetmp); \
  5080         if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; } \
  5082       static char *st_path = 0;
  5083       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5084       if (user_path) {
  5085         if (!st_path) st_path = new char[1024];
  5086         cimg_std::memset(st_path,0,1024);
  5087         cimg_std::strncpy(st_path,user_path,1023);
  5088       } else if (!st_path) {
  5089         st_path = new char[1024];
  5090         cimg_std::memset(st_path,0,1024);
  5091         bool path_found = false;
  5092         char tmp[1024], filetmp[512];
  5093         cimg_std::FILE *file = 0;
  5094         cimg_std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
  5095         char *tmpPath = getenv("TMP");
  5096         if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
  5097         if (tmpPath) _cimg_test_temporary_path(tmpPath);
  5098 #if cimg_OS==2
  5099         _cimg_test_temporary_path("C:\\WINNT\\Temp");
  5100         _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
  5101         _cimg_test_temporary_path("C:\\Temp");
  5102         _cimg_test_temporary_path("C:");
  5103         _cimg_test_temporary_path("D:\\WINNT\\Temp");
  5104         _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
  5105         _cimg_test_temporary_path("D:\\Temp");
  5106         _cimg_test_temporary_path("D:");
  5107 #else
  5108         _cimg_test_temporary_path("/tmp");
  5109         _cimg_test_temporary_path("/var/tmp");
  5110 #endif
  5111         if (!path_found) {
  5112           st_path[0]='\0';
  5113           cimg_std::strcpy(tmp,filetmp);
  5114           if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; }
  5116         if (!path_found)
  5117           throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
  5118                                 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
  5119                                 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
  5121       return st_path;
  5124     // Return or set path to the "Program files/" directory (windows only).
  5125 #if cimg_OS==2
  5126     inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
  5127       static char *st_path = 0;
  5128       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5129       if (user_path) {
  5130         if (!st_path) st_path = new char[1024];
  5131         cimg_std::memset(st_path,0,1024);
  5132         cimg_std::strncpy(st_path,user_path,1023);
  5133       } else if (!st_path) {
  5134         st_path = new char[MAX_PATH];
  5135         cimg_std::memset(st_path,0,MAX_PATH);
  5136         // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
  5137 #if !defined(__INTEL_COMPILER)
  5138         if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
  5139           const char *pfPath = getenv("PROGRAMFILES");
  5140           if (pfPath) cimg_std::strncpy(st_path,pfPath,MAX_PATH-1);
  5141           else cimg_std::strcpy(st_path,"C:\\PROGRA~1");
  5143 #else
  5144         cimg_std::strcpy(st_path,"C:\\PROGRA~1");
  5145 #endif
  5147       return st_path;
  5149 #endif
  5151     //! Return or set path to the ImageMagick's \c convert tool.
  5152     inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
  5153       static char *st_path = 0;
  5154       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5155       if (user_path) {
  5156         if (!st_path) st_path = new char[1024];
  5157         cimg_std::memset(st_path,0,1024);
  5158         cimg_std::strncpy(st_path,user_path,1023);
  5159       } else if (!st_path) {
  5160         st_path = new char[1024];
  5161         cimg_std::memset(st_path,0,1024);
  5162         bool path_found = false;
  5163         cimg_std::FILE *file = 0;
  5164 #if cimg_OS==2
  5165         const char *pf_path = programfiles_path();
  5166         if (!path_found) {
  5167           cimg_std::sprintf(st_path,".\\convert.exe");
  5168           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5170         { for (int k=32; k>=10 && !path_found; --k) {
  5171           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
  5172           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5173         }}
  5174         { for (int k=9; k>=0 && !path_found; --k) {
  5175           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
  5176           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5177         }}
  5178         { for (int k=32; k>=0 && !path_found; --k) {
  5179           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
  5180           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5181         }}
  5182         { for (int k=32; k>=10 && !path_found; --k) {
  5183           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  5184           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5185         }}
  5186         { for (int k=9; k>=0 && !path_found; --k) {
  5187           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  5188           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5189         }}
  5190         { for (int k=32; k>=0 && !path_found; --k) {
  5191           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  5192           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5193         }}
  5194         { for (int k=32; k>=10 && !path_found; --k) {
  5195           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
  5196           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5197         }}
  5198         { for (int k=9; k>=0 && !path_found; --k) {
  5199           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
  5200           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5201         }}
  5202         { for (int k=32; k>=0 && !path_found; --k) {
  5203           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
  5204           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5205         }}
  5206         { for (int k=32; k>=10 && !path_found; --k) {
  5207           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
  5208           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5209         }}
  5210         { for (int k=9; k>=0 && !path_found; --k) {
  5211           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
  5212           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5213         }}
  5214         { for (int k=32; k>=0 && !path_found; --k) {
  5215           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
  5216           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5217         }}
  5218         { for (int k=32; k>=10 && !path_found; --k) {
  5219           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
  5220           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5221         }}
  5222         { for (int k=9; k>=0 && !path_found; --k) {
  5223           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
  5224           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5225         }}
  5226         { for (int k=32; k>=0 && !path_found; --k) {
  5227           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
  5228           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5229         }}
  5230         { for (int k=32; k>=10 && !path_found; --k) {
  5231           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
  5232           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5233         }}
  5234         { for (int k=9; k>=0 && !path_found; --k) {
  5235           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
  5236           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5237         }}
  5238         { for (int k=32; k>=0 && !path_found; --k) {
  5239           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
  5240           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5241         }}
  5242         if (!path_found) cimg_std::strcpy(st_path,"convert.exe");
  5243 #else
  5244         if (!path_found) {
  5245           cimg_std::sprintf(st_path,"./convert");
  5246           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5248         if (!path_found) cimg_std::strcpy(st_path,"convert");
  5249 #endif
  5250         winformat_string(st_path);
  5252       return st_path;
  5255     //! Return path of the GraphicsMagick's \c gm tool.
  5256     inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
  5257       static char *st_path = 0;
  5258       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5259       if (user_path) {
  5260         if (!st_path) st_path = new char[1024];
  5261         cimg_std::memset(st_path,0,1024);
  5262         cimg_std::strncpy(st_path,user_path,1023);
  5263       } else if (!st_path) {
  5264         st_path = new char[1024];
  5265         cimg_std::memset(st_path,0,1024);
  5266         bool path_found = false;
  5267         cimg_std::FILE *file = 0;
  5268 #if cimg_OS==2
  5269         const char* pf_path = programfiles_path();
  5270         if (!path_found) {
  5271           cimg_std::sprintf(st_path,".\\gm.exe");
  5272           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5274         { for (int k=32; k>=10 && !path_found; --k) {
  5275           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
  5276           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5277         }}
  5278         { for (int k=9; k>=0 && !path_found; --k) {
  5279           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
  5280           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5281         }}
  5282         { for (int k=32; k>=0 && !path_found; --k) {
  5283           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
  5284           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5285         }}
  5286         { for (int k=32; k>=10 && !path_found; --k) {
  5287           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  5288           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5289         }}
  5290         { for (int k=9; k>=0 && !path_found; --k) {
  5291           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  5292           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5293         }}
  5294         { for (int k=32; k>=0 && !path_found; --k) {
  5295           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  5296           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5297         }}
  5298         { for (int k=32; k>=10 && !path_found; --k) {
  5299           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
  5300           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5301         }}
  5302         { for (int k=9; k>=0 && !path_found; --k) {
  5303           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
  5304           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5305         }}
  5306         { for (int k=32; k>=0 && !path_found; --k) {
  5307           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
  5308           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5309         }}
  5310         { for (int k=32; k>=10 && !path_found; --k) {
  5311           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
  5312           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5313         }}
  5314         { for (int k=9; k>=0 && !path_found; --k) {
  5315           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
  5316           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5317         }}
  5318         { for (int k=32; k>=0 && !path_found; --k) {
  5319           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
  5320           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5321         }}
  5322         { for (int k=32; k>=10 && !path_found; --k) {
  5323           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
  5324           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5325         }}
  5326         { for (int k=9; k>=0 && !path_found; --k) {
  5327           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
  5328           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5329         }}
  5330         { for (int k=32; k>=0 && !path_found; --k) {
  5331           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
  5332           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5333         }}
  5334         { for (int k=32; k>=10 && !path_found; --k) {
  5335           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
  5336           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5337         }}
  5338         { for (int k=9; k>=0 && !path_found; --k) {
  5339           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
  5340           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5341         }}
  5342         { for (int k=32; k>=0 && !path_found; --k) {
  5343           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
  5344           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5345         }}
  5346         if (!path_found) cimg_std::strcpy(st_path,"gm.exe");
  5347 #else
  5348         if (!path_found) {
  5349           cimg_std::sprintf(st_path,"./gm");
  5350           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5352         if (!path_found) cimg_std::strcpy(st_path,"gm");
  5353 #endif
  5354         winformat_string(st_path);
  5356       return st_path;
  5359     //! Return or set path of the \c XMedcon tool.
  5360     inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
  5361       static char *st_path = 0;
  5362       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5363       if (user_path) {
  5364         if (!st_path) st_path = new char[1024];
  5365         cimg_std::memset(st_path,0,1024);
  5366         cimg_std::strncpy(st_path,user_path,1023);
  5367       } else if (!st_path) {
  5368         st_path = new char[1024];
  5369         cimg_std::memset(st_path,0,1024);
  5370         bool path_found = false;
  5371         cimg_std::FILE *file = 0;
  5372 #if cimg_OS==2
  5373         const char* pf_path = programfiles_path();
  5374         if (!path_found) {
  5375           cimg_std::sprintf(st_path,".\\medcon.bat");
  5376           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5378         if (!path_found) {
  5379           cimg_std::sprintf(st_path,".\\medcon.exe");
  5380           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5382         if (!path_found) {
  5383           cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
  5384           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5386         if (!path_found) {
  5387           cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
  5388           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5390         if (!path_found) cimg_std::strcpy(st_path,"medcon.bat");
  5391 #else
  5392         if (!path_found) {
  5393           cimg_std::sprintf(st_path,"./medcon");
  5394           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5396         if (!path_found) cimg_std::strcpy(st_path,"medcon");
  5397 #endif
  5398         winformat_string(st_path);
  5400       return st_path;
  5403     //! Return or set path to the 'ffmpeg' command.
  5404     inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
  5405       static char *st_path = 0;
  5406       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5407       if (user_path) {
  5408         if (!st_path) st_path = new char[1024];
  5409         cimg_std::memset(st_path,0,1024);
  5410         cimg_std::strncpy(st_path,user_path,1023);
  5411       } else if (!st_path) {
  5412         st_path = new char[1024];
  5413         cimg_std::memset(st_path,0,1024);
  5414         bool path_found = false;
  5415         cimg_std::FILE *file = 0;
  5416 #if cimg_OS==2
  5417         if (!path_found) {
  5418           cimg_std::sprintf(st_path,".\\ffmpeg.exe");
  5419           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5421         if (!path_found) cimg_std::strcpy(st_path,"ffmpeg.exe");
  5422 #else
  5423         if (!path_found) {
  5424           cimg_std::sprintf(st_path,"./ffmpeg");
  5425           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5427         if (!path_found) cimg_std::strcpy(st_path,"ffmpeg");
  5428 #endif
  5429         winformat_string(st_path);
  5431       return st_path;
  5434     //! Return or set path to the 'gzip' command.
  5435     inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
  5436       static char *st_path = 0;
  5437       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5438       if (user_path) {
  5439         if (!st_path) st_path = new char[1024];
  5440         cimg_std::memset(st_path,0,1024);
  5441         cimg_std::strncpy(st_path,user_path,1023);
  5442       } else if (!st_path) {
  5443         st_path = new char[1024];
  5444         cimg_std::memset(st_path,0,1024);
  5445         bool path_found = false;
  5446         cimg_std::FILE *file = 0;
  5447 #if cimg_OS==2
  5448         if (!path_found) {
  5449           cimg_std::sprintf(st_path,".\\gzip.exe");
  5450           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5452         if (!path_found) cimg_std::strcpy(st_path,"gzip.exe");
  5453 #else
  5454         if (!path_found) {
  5455           cimg_std::sprintf(st_path,"./gzip");
  5456           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5458         if (!path_found) cimg_std::strcpy(st_path,"gzip");
  5459 #endif
  5460         winformat_string(st_path);
  5462       return st_path;
  5465     //! Return or set path to the 'gunzip' command.
  5466     inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
  5467       static char *st_path = 0;
  5468       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5469       if (user_path) {
  5470         if (!st_path) st_path = new char[1024];
  5471         cimg_std::memset(st_path,0,1024);
  5472         cimg_std::strncpy(st_path,user_path,1023);
  5473       } else if (!st_path) {
  5474         st_path = new char[1024];
  5475         cimg_std::memset(st_path,0,1024);
  5476         bool path_found = false;
  5477         cimg_std::FILE *file = 0;
  5478 #if cimg_OS==2
  5479         if (!path_found) {
  5480           cimg_std::sprintf(st_path,".\\gunzip.exe");
  5481           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5483         if (!path_found) cimg_std::strcpy(st_path,"gunzip.exe");
  5484 #else
  5485         if (!path_found) {
  5486           cimg_std::sprintf(st_path,"./gunzip");
  5487           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5489         if (!path_found) cimg_std::strcpy(st_path,"gunzip");
  5490 #endif
  5491         winformat_string(st_path);
  5493       return st_path;
  5496     //! Return or set path to the 'dcraw' command.
  5497     inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
  5498       static char *st_path = 0;
  5499       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  5500       if (user_path) {
  5501         if (!st_path) st_path = new char[1024];
  5502         cimg_std::memset(st_path,0,1024);
  5503         cimg_std::strncpy(st_path,user_path,1023);
  5504       } else if (!st_path) {
  5505         st_path = new char[1024];
  5506         cimg_std::memset(st_path,0,1024);
  5507         bool path_found = false;
  5508         cimg_std::FILE *file = 0;
  5509 #if cimg_OS==2
  5510         if (!path_found) {
  5511           cimg_std::sprintf(st_path,".\\dcraw.exe");
  5512           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5514         if (!path_found) cimg_std::strcpy(st_path,"dcraw.exe");
  5515 #else
  5516         if (!path_found) {
  5517           cimg_std::sprintf(st_path,"./dcraw");
  5518           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  5520         if (!path_found) cimg_std::strcpy(st_path,"dcraw");
  5521 #endif
  5522         winformat_string(st_path);
  5524       return st_path;
  5527     //! Split a filename into two strings 'body' and 'extension'.
  5528     inline const char *split_filename(const char *const filename, char *const body=0) {
  5529       if (!filename) { if (body) body[0]='\0'; return 0; }
  5530       int l = cimg::strfind(filename,'.');
  5531       if (l>=0) { if (body) { cimg_std::strncpy(body,filename,l); body[l]='\0'; }}
  5532       else { if (body) cimg_std::strcpy(body,filename); l = (int)cimg::strlen(filename)-1; }
  5533       return filename+l+1;
  5536     //! Create a numbered version of a filename.
  5537     inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
  5538       if (!filename) { if (string) string[0]='\0'; return 0; }
  5539       char format[1024],body[1024];
  5540       const char *ext = cimg::split_filename(filename,body);
  5541       if (n>0) cimg_std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
  5542       else cimg_std::sprintf(format,"%s_%%d.%s",body,ext);
  5543       cimg_std::sprintf(string,format,number);
  5544       return string;
  5547     //! Open a file, and check for possible errors.
  5548     inline cimg_std::FILE *fopen(const char *const path, const char *const mode) {
  5549       if(!path || !mode)
  5550         throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
  5551                                     path?path:"(null)",mode?mode:"(null)");
  5552       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
  5553       cimg_std::FILE *dest = cimg_std::fopen(path,mode);
  5554       if (!dest)
  5555         throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
  5556                               path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
  5557       return dest;
  5560     //! Close a file, and check for possible errors.
  5561     inline int fclose(cimg_std::FILE *file) {
  5562       if (!file) warn("cimg::fclose() : Can't close (null) file");
  5563       if (!file || file==stdin || file==stdout) return 0;
  5564       const int errn = cimg_std::fclose(file);
  5565       if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
  5566       return errn;
  5569     //! Try to guess the image format of a filename, using its magick numbers.
  5570     inline const char *file_type(cimg_std::FILE *const file, const char *const filename) {
  5571       static const char
  5572         *const _pnm = "pnm",
  5573         *const _bmp = "bmp",
  5574         *const _gif = "gif",
  5575         *const _jpeg = "jpeg",
  5576         *const _off = "off",
  5577         *const _pan = "pan",
  5578         *const _png = "png",
  5579         *const _tiff = "tiff";
  5580       if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
  5581       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
  5582       const char *ftype = 0, *head;
  5583       char header[2048], item[1024];
  5584       const unsigned char *const uheader = (unsigned char*)header;
  5585       int err;
  5586       const unsigned int siz = (unsigned int)cimg_std::fread(header,2048,1,nfile);   // Read first 2048 bytes.
  5587       if (!file) cimg::fclose(nfile);
  5588       if (!ftype) { // Check for BMP format.
  5589         if (header[0]=='B' && header[1]=='M') ftype = _bmp;
  5591       if (!ftype) { // Check for GIF format.
  5592         if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
  5593             (header[4]=='7' || header[4]=='9')) ftype = _gif;
  5595       if (!ftype) { // Check for JPEG format.
  5596         if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
  5598       if (!ftype) { // Check for OFF format.
  5599         if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
  5601       if (!ftype) { // Check for PAN format.
  5602         if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
  5603             header[5]=='R' && header[6]=='E') ftype = _pan;
  5605       if (!ftype) { // Check for PNG format.
  5606         if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
  5607             uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
  5609       if (!ftype) { // Check for PNM format.
  5610         head = header;
  5611         while (head<header+siz && (err=cimg_std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
  5612           head+=1+(err?cimg::strlen(item):0);
  5613         if (cimg_std::sscanf(item," P%d",&err)==1) ftype = _pnm;
  5615       if (!ftype) { // Check for TIFF format.
  5616         if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
  5618       return ftype;
  5621     //! Read file data, and check for possible errors.
  5622     template<typename T>
  5623     inline int fread(T *const ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
  5624       if (!ptr || nmemb<=0 || !stream)
  5625         throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
  5626                                     nmemb,sizeof(T),stream,ptr);
  5627       const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
  5628       unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
  5629       do {
  5630         ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
  5631         lalread = (unsigned int)cimg_std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
  5632         alread+=lalread;
  5633         toread-=lalread;
  5634       } while (ltoread==lalread && toread>0);
  5635       if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
  5636       return alread;
  5639     //! Write data to a file, and check for possible errors.
  5640     template<typename T>
  5641     inline int fwrite(const T *ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
  5642       if (!ptr || !stream)
  5643         throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
  5644                                     nmemb,sizeof(T),stream,ptr);
  5645       if (nmemb<=0) return 0;
  5646       const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
  5647       unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
  5648       do {
  5649         ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
  5650         lalwrite = (unsigned int)cimg_std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
  5651         alwrite+=lalwrite;
  5652         towrite-=lalwrite;
  5653       } while (ltowrite==lalwrite && towrite>0);
  5654       if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
  5655       return alwrite;
  5658     inline const char* option(const char *const name, const int argc, const char *const *const argv,
  5659                               const char *defaut, const char *const usage=0) {
  5660       static bool first = true, visu = false;
  5661       const char *res = 0;
  5662       if (first) {
  5663         first=false;
  5664         visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
  5665         visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
  5666         visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
  5668       if (!name && visu) {
  5669         if (usage) {
  5670           cimg_std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
  5671           cimg_std::fprintf(cimg_stdout," : %s",usage);
  5672           cimg_std::fprintf(cimg_stdout," (%s, %s)\n\n",__DATE__,__TIME__);
  5674         if (defaut) cimg_std::fprintf(cimg_stdout,"%s\n",defaut);
  5676       if (name) {
  5677         if (argc>0) {
  5678           int k = 0;
  5679           while (k<argc && cimg::strcmp(argv[k],name)) ++k;
  5680           res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
  5681         } else res = defaut;
  5682         if (visu && usage) cimg_std::fprintf(cimg_stdout,"    %s%-16s%s %-24s %s%s%s\n",
  5683                                         cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
  5685       return res;
  5688     inline bool option(const char *const name, const int argc, const char *const *const argv,
  5689                        const bool defaut, const char *const usage=0) {
  5690       const char *s = cimg::option(name,argc,argv,(char*)0);
  5691       const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
  5692       cimg::option(name,0,0,res?"true":"false",usage);
  5693       return res;
  5696     inline int option(const char *const name, const int argc, const char *const *const argv,
  5697                       const int defaut, const char *const usage=0) {
  5698       const char *s = cimg::option(name,argc,argv,(char*)0);
  5699       const int res = s?cimg_std::atoi(s):defaut;
  5700       char tmp[256];
  5701       cimg_std::sprintf(tmp,"%d",res);
  5702       cimg::option(name,0,0,tmp,usage);
  5703       return res;
  5706     inline char option(const char *const name, const int argc, const char *const *const argv,
  5707                        const char defaut, const char *const usage=0) {
  5708       const char *s = cimg::option(name,argc,argv,(char*)0);
  5709       const char res = s?s[0]:defaut;
  5710       char tmp[8];
  5711       tmp[0] = res; tmp[1] ='\0';
  5712       cimg::option(name,0,0,tmp,usage);
  5713       return res;
  5716     inline float option(const char *const name, const int argc, const char *const *const argv,
  5717                         const float defaut, const char *const usage=0) {
  5718       const char *s = cimg::option(name,argc,argv,(char*)0);
  5719       const float res = s?cimg::atof(s):defaut;
  5720       char tmp[256];
  5721       cimg_std::sprintf(tmp,"%g",res);
  5722       cimg::option(name,0,0,tmp,usage);
  5723       return res;
  5726     inline double option(const char *const name, const int argc, const char *const *const argv,
  5727                          const double defaut, const char *const usage=0) {
  5728       const char *s = cimg::option(name,argc,argv,(char*)0);
  5729       const double res = s?cimg::atof(s):defaut;
  5730       char tmp[256];
  5731       cimg_std::sprintf(tmp,"%g",res);
  5732       cimg::option(name,0,0,tmp,usage);
  5733       return res;
  5736     inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
  5737       for (int k = 1, pos = 0; k<argc;) {
  5738         const char *const item = argv[k];
  5739         bool option = (*item=='-'), single_option = false;
  5740         if (option) {
  5741           va_list ap;
  5742           va_start(ap,nb_singles);
  5743           for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
  5744           va_end(ap);
  5746         if (option) { ++k; if (!single_option) ++k; }
  5747         else { if (pos++==(int)nb) return item; else ++k; }
  5749       return 0;
  5752     //! Print informations about %CImg environement variables.
  5753     /**
  5754        Printing is done on the standard error output.
  5755     **/
  5756     inline void info() {
  5757       char tmp[1024] = { 0 };
  5758       cimg_std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
  5759                    cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
  5760                    cimg::t_normal,__DATE__,__TIME__);
  5762       cimg_std::fprintf(cimg_stdout,"  > Operating System :       %s%-13s%s %s('cimg_OS'=%d)%s\n",
  5763                    cimg::t_bold,
  5764                    cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
  5765                    cimg::t_normal,cimg::t_green,
  5766                    cimg_OS,
  5767                    cimg::t_normal);
  5769       cimg_std::fprintf(cimg_stdout,"  > CPU endianness :         %s%s Endian%s\n",
  5770                    cimg::t_bold,
  5771                    cimg::endianness()?"Big":"Little",
  5772                    cimg::t_normal);
  5774 #ifdef cimg_use_visualcpp6
  5775       cimg_std::fprintf(cimg_stdout,"  > Using Visual C++ 6.0 :       %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
  5776                    cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
  5777 #endif
  5779       cimg_std::fprintf(cimg_stdout,"  > Debug messages :         %s%-13s%s %s('cimg_debug'=%d)%s\n",
  5780                    cimg::t_bold,
  5781                    cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
  5782                    cimg::t_normal,cimg::t_green,
  5783                    cimg_debug,
  5784                    cimg::t_normal);
  5786       cimg_std::fprintf(cimg_stdout,"  > Stricts warnings :       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
  5787                    cimg::t_bold,
  5788 #ifdef cimg_strict_warnings
  5789                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5790 #else
  5791                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5792 #endif
  5793                    cimg::t_normal);
  5795       cimg_std::fprintf(cimg_stdout,"  > Using VT100 messages :   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
  5796                    cimg::t_bold,
  5797 #ifdef cimg_use_vt100
  5798                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5799 #else
  5800                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5801 #endif
  5802                    cimg::t_normal);
  5804       cimg_std::fprintf(cimg_stdout,"  > Display type :           %s%-13s%s %s('cimg_display'=%d)%s\n",
  5805                    cimg::t_bold,
  5806                    cimg_display==0?"No display":
  5807                    (cimg_display==1?"X11":
  5808                     (cimg_display==2?"Windows GDI":
  5809                      (cimg_display==3?"Carbon":"Unknow"))),
  5810                    cimg::t_normal,cimg::t_green,
  5811                    cimg_display,
  5812                    cimg::t_normal);
  5814 #if cimg_display==1
  5815       cimg_std::fprintf(cimg_stdout,"  > Using XShm for X11 :     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
  5816                    cimg::t_bold,
  5817 #ifdef cimg_use_xshm
  5818                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5819 #else
  5820                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5821 #endif
  5822                    cimg::t_normal);
  5824       cimg_std::fprintf(cimg_stdout,"  > Using XRand for X11 :    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
  5825                    cimg::t_bold,
  5826 #ifdef cimg_use_xrandr
  5827                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5828 #else
  5829                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5830 #endif
  5831                    cimg::t_normal);
  5832 #endif
  5833       cimg_std::fprintf(cimg_stdout,"  > Using OpenMP :           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
  5834                    cimg::t_bold,
  5835 #ifdef cimg_use_openmp
  5836                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5837 #else
  5838                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5839 #endif
  5840                    cimg::t_normal);
  5841       cimg_std::fprintf(cimg_stdout,"  > Using PNG library :      %s%-13s%s %s('cimg_use_png' %s)%s\n",
  5842                    cimg::t_bold,
  5843 #ifdef cimg_use_png
  5844                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5845 #else
  5846                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5847 #endif
  5848                    cimg::t_normal);
  5849       cimg_std::fprintf(cimg_stdout,"  > Using JPEG library :     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
  5850                    cimg::t_bold,
  5851 #ifdef cimg_use_jpeg
  5852                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5853 #else
  5854                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5855 #endif
  5856                    cimg::t_normal);
  5858       cimg_std::fprintf(cimg_stdout,"  > Using TIFF library :     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
  5859                    cimg::t_bold,
  5860 #ifdef cimg_use_tiff
  5861                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5862 #else
  5863                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5864 #endif
  5865                    cimg::t_normal);
  5867       cimg_std::fprintf(cimg_stdout,"  > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
  5868                    cimg::t_bold,
  5869 #ifdef cimg_use_magick
  5870                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5871 #else
  5872                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5873 #endif
  5874                    cimg::t_normal);
  5876       cimg_std::fprintf(cimg_stdout,"  > Using FFTW3 library :    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
  5877                    cimg::t_bold,
  5878 #ifdef cimg_use_fftw3
  5879                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5880 #else
  5881                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5882 #endif
  5883                    cimg::t_normal);
  5885       cimg_std::fprintf(cimg_stdout,"  > Using LAPACK library :   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
  5886                    cimg::t_bold,
  5887 #ifdef cimg_use_lapack
  5888                    "Yes",cimg::t_normal,cimg::t_green,"defined",
  5889 #else
  5890                    "No",cimg::t_normal,cimg::t_green,"undefined",
  5891 #endif
  5892                    cimg::t_normal);
  5894       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
  5895       cimg_std::fprintf(cimg_stdout,"  > Path of ImageMagick :    %s%-13s%s\n",
  5896                    cimg::t_bold,
  5897                    tmp,
  5898                    cimg::t_normal);
  5900       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
  5901       cimg_std::fprintf(cimg_stdout,"  > Path of GraphicsMagick : %s%-13s%s\n",
  5902                    cimg::t_bold,
  5903                    tmp,
  5904                    cimg::t_normal);
  5906       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
  5907       cimg_std::fprintf(cimg_stdout,"  > Path of 'medcon' :       %s%-13s%s\n",
  5908                    cimg::t_bold,
  5909                    tmp,
  5910                    cimg::t_normal);
  5912       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
  5913       cimg_std::fprintf(cimg_stdout,"  > Temporary path :         %s%-13s%s\n",
  5914                    cimg::t_bold,
  5915                    tmp,
  5916                    cimg::t_normal);
  5918       cimg_std::fprintf(cimg_stdout,"\n");
  5921     // Declare LAPACK function signatures if necessary.
  5922     //
  5923 #ifdef cimg_use_lapack
  5924     template<typename T>
  5925     inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
  5926       dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
  5929     inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
  5930       sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
  5933     template<typename T>
  5934     inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
  5935       dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
  5938     inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
  5939       sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
  5942     template<typename T>
  5943     inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
  5944                       T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
  5945       dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
  5948     inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
  5949                       float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
  5950       sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
  5953     template<typename T>
  5954     inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
  5955       int one = 1;
  5956       dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
  5959     inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
  5960       int one = 1;
  5961       sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
  5964     template<typename T>
  5965     inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
  5966       dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
  5969     inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
  5970       ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
  5972 #endif
  5974     // End of the 'cimg' namespace
  5977   /*------------------------------------------------
  5980    #   Definition of mathematical operators and
  5981    #   external functions.
  5984    -------------------------------------------------*/
  5985   //
  5986   // These functions are extern to any classes and can be used for a "functional-style" programming,
  5987   // such as writting :
  5988   //                     cos(img);
  5989   // instead of          img.get_cos();
  5990   //
  5991   // Note that only the arithmetic operators and functions are implemented here.
  5992   //
  5994 #ifdef cimg_use_visualcpp6
  5995   template<typename t>
  5996   inline CImg<t> operator+(const CImg<t>& img, const t val) {
  5997     return CImg<t>(img,false)+=val;
  5999 #else
  6000   template<typename t1, typename t2>
  6001   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
  6002     typedef typename cimg::superset<t1,t2>::type t1t2;
  6003     return CImg<t1t2>(img,false)+=val;
  6005 #endif
  6007 #ifdef cimg_use_visualcpp6
  6008   template<typename t>
  6009   inline CImg<t> operator+(const t val, const CImg<t>& img) {
  6010     return img + val;
  6012 #else
  6013   template<typename t1, typename t2>
  6014   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
  6015     return img + val;
  6017 #endif
  6019 #ifdef cimg_use_visualcpp6
  6020   template<typename t>
  6021   inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
  6022     return CImgList<t>(list)+=val;
  6024 #else
  6025   template<typename t1, typename t2>
  6026   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
  6027     typedef typename cimg::superset<t1,t2>::type t1t2;
  6028     return CImgList<t1t2>(list)+=val;
  6030 #endif
  6032 #ifdef cimg_use_visualcpp6
  6033   template<typename t>
  6034   inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
  6035     return list + val;
  6037 #else
  6038   template<typename t1, typename t2>
  6039   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
  6040     return list + val;
  6042 #endif
  6044   template<typename t1, typename t2>
  6045   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
  6046     typedef typename cimg::superset<t1,t2>::type t1t2;
  6047     return CImg<t1t2>(img1,false)+=img2;
  6050   template<typename t1, typename t2>
  6051   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
  6052     typedef typename cimg::superset<t1,t2>::type t1t2;
  6053     return CImgList<t1t2>(list)+=img;
  6056   template<typename t1, typename t2>
  6057   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
  6058     return img + list;
  6061   template<typename t1, typename t2>
  6062   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  6063     typedef typename cimg::superset<t1,t2>::type t1t2;
  6064     return CImgList<t1t2>(list1)+=list2;
  6067 #ifdef cimg_use_visualcpp6
  6068   template<typename t>
  6069   inline CImg<t> operator-(const CImg<t>& img, const t val) {
  6070     return CImg<t>(img,false)-=val;
  6072 #else
  6073   template<typename t1, typename t2>
  6074   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
  6075     typedef typename cimg::superset<t1,t2>::type t1t2;
  6076     return CImg<t1t2>(img,false)-=val;
  6078 #endif
  6080 #ifdef cimg_use_visualcpp6
  6081   template<typename t>
  6082   inline CImg<t> operator-(const t val, const CImg<t>& img) {
  6083     return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
  6085 #else
  6086   template<typename t1, typename t2>
  6087   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
  6088     typedef typename cimg::superset<t1,t2>::type t1t2;
  6089     return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
  6091 #endif
  6093 #ifdef cimg_use_visualcpp6
  6094   template<typename t>
  6095   inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
  6096     return CImgList<t>(list)-=val;
  6098 #else
  6099   template<typename t1, typename t2>
  6100   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
  6101     typedef typename cimg::superset<t1,t2>::type t1t2;
  6102     return CImgList<t1t2>(list)-=val;
  6104 #endif
  6106 #ifdef cimg_use_visualcpp6
  6107   template<typename t>
  6108   inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
  6109     CImgList<t> res(list.size);
  6110     cimglist_for(res,l) res[l] = val - list[l];
  6111     return res;
  6113 #else
  6114   template<typename t1, typename t2>
  6115   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
  6116     typedef typename cimg::superset<t1,t2>::type t1t2;
  6117     CImgList<t1t2> res(list.size);
  6118     cimglist_for(res,l) res[l] = val - list[l];
  6119     return res;
  6121 #endif
  6123   template<typename t1, typename t2>
  6124   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
  6125     typedef typename cimg::superset<t1,t2>::type t1t2;
  6126     return CImg<t1t2>(img1,false)-=img2;
  6129   template<typename t1, typename t2>
  6130   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
  6131     typedef typename cimg::superset<t1,t2>::type t1t2;
  6132     CImgList<t1t2> res(list.size);
  6133     cimglist_for(res,l) res[l] = img - list[l];
  6134     return res;
  6137   template<typename t1, typename t2>
  6138   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
  6139     typedef typename cimg::superset<t1,t2>::type t1t2;
  6140     return CImgList<t1t2>(list)-=img;
  6143   template<typename t1, typename t2>
  6144   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  6145     typedef typename cimg::superset<t1,t2>::type t1t2;
  6146     return CImgList<t1t2>(list1)-=list2;
  6149 #ifdef cimg_use_visualcpp6
  6150   template<typename t>
  6151   inline CImg<t> operator*(const CImg<t>& img, const double val) {
  6152     return CImg<t>(img,false)*=val;
  6154 #else
  6155   template<typename t1, typename t2>
  6156   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
  6157     typedef typename cimg::superset<t1,t2>::type t1t2;
  6158     return CImg<t1t2>(img,false)*=val;
  6160 #endif
  6162 #ifdef cimg_use_visualcpp6
  6163   template<typename t>
  6164   inline CImg<t> operator*(const double val, const CImg<t>& img) {
  6165     return img*val;
  6167 #else
  6168   template<typename t1, typename t2>
  6169   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
  6170     return img*val;
  6172 #endif
  6174 #ifdef cimg_use_visualcpp6
  6175   template<typename t>
  6176   inline CImgList<t> operator*(const CImgList<t>& list, const double val) {
  6177     return CImgList<t>(list)*=val;
  6179 #else
  6180   template<typename t1, typename t2>
  6181   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
  6182     typedef typename cimg::superset<t1,t2>::type t1t2;
  6183     return CImgList<t1t2>(list)*=val;
  6185 #endif
  6187 #ifdef cimg_use_visualcpp6
  6188   template<typename t>
  6189   inline CImgList<t> operator*(const double val, const CImgList<t>& list) {
  6190     return list*val;
  6192 #else
  6193   template<typename t1, typename t2>
  6194   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
  6195     return list*val;
  6197 #endif
  6199   template<typename t1, typename t2>
  6200   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
  6201     typedef typename cimg::superset<t1,t2>::type t1t2;
  6202     if (img1.width!=img2.height)
  6203       throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
  6204                                   img1.width,img1.height,img2.width,img2.height);
  6205     CImg<t1t2> res(img2.width,img1.height);
  6206     t1t2 val;
  6207 #ifdef cimg_use_openmp
  6208 #pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
  6209 #endif
  6210     cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
  6211     return res;
  6214   template<typename t1, typename t2>
  6215   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
  6216     typedef typename cimg::superset<t1,t2>::type t1t2;
  6217     CImgList<t1t2> res(list.size);
  6218     cimglist_for(res,l) res[l] = img*list[l];
  6219     return res;
  6222   template<typename t1, typename t2>
  6223   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
  6224     typedef typename cimg::superset<t1,t2>::type t1t2;
  6225     CImgList<t1t2> res(list.size);
  6226     cimglist_for(res,l) res[l] = list[l]*img;
  6227     return res;
  6230   template<typename t1, typename t2>
  6231   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  6232     typedef typename cimg::superset<t1,t2>::type t1t2;
  6233     CImgList<t1t2> res(cimg::min(list1.size,list2.size));
  6234     cimglist_for(res,l) res[l] = list1[l]*list2[l];
  6235     return res;
  6238 #ifdef cimg_use_visualcpp6
  6239   template<typename t>
  6240   inline CImg<t> operator/(const CImg<t>& img, const double val) {
  6241     return CImg<t>(img,false)/=val;
  6243 #else
  6244   template<typename t1, typename t2>
  6245   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
  6246     typedef typename cimg::superset<t1,t2>::type t1t2;
  6247     return CImg<t1t2>(img,false)/=val;
  6249 #endif
  6251 #ifdef cimg_use_visualcpp6
  6252   template<typename t>
  6253   inline CImg<t> operator/(const double val, CImg<t>& img) {
  6254     return val*img.get_invert();
  6256 #else
  6257   template<typename t1, typename t2>
  6258   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
  6259     return val*img.get_invert();
  6261 #endif
  6263 #ifdef cimg_use_visualcpp6
  6264   template<typename t>
  6265   inline CImgList<t> operator/(const CImgList<t>& list, const double val) {
  6266     return CImgList<t>(list)/=val;
  6268 #else
  6269   template<typename t1, typename t2>
  6270   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
  6271     typedef typename cimg::superset<t1,t2>::type t1t2;
  6272     return CImgList<t1t2>(list)/=val;
  6274 #endif
  6276 #ifdef cimg_use_visualcpp6
  6277   template<typename t>
  6278   inline CImgList<t> operator/(const double val, const CImgList<t>& list) {
  6279     CImgList<t> res(list.size);
  6280     cimglist_for(res,l) res[l] = val/list[l];
  6281     return res;
  6283 #else
  6284   template<typename t1, typename t2>
  6285   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
  6286     typedef typename cimg::superset<t1,t2>::type t1t2;
  6287     CImgList<t1t2> res(list.size);
  6288     cimglist_for(res,l) res[l] = val/list[l];
  6289     return res;
  6291 #endif
  6293   template<typename t1, typename t2>
  6294   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
  6295     typedef typename cimg::superset<t1,t2>::type t1t2;
  6296     return CImg<t1t2>(img1,false)*=img2.get_invert();
  6299   template<typename t1, typename t2>
  6300   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
  6301     typedef typename cimg::superset<t1,t2>::type t1t2;
  6302     CImgList<t1t2> res(list.size);
  6303     cimglist_for(res,l) res[l] = img/list[l];
  6304     return res;
  6307   template<typename t1, typename t2>
  6308   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
  6309     typedef typename cimg::superset<t1,t2>::type t1t2;
  6310     return CImgList<t1t2>(list)/=img;
  6313   template<typename t1, typename t2>
  6314   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  6315     typedef typename cimg::superset<t1,t2>::type t1t2;
  6316     return CImgList<t1t2>(list1)/=list2;
  6319   template<typename T>
  6320   inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
  6321     return instance.get_sqr();
  6324   template<typename T>
  6325   inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
  6326     return instance.get_sqrt();
  6329   template<typename T>
  6330   inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
  6331     return instance.get_exp();
  6334   template<typename T>
  6335   inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
  6336     return instance.get_log();
  6339   template<typename T>
  6340   inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
  6341     return instance.get_log10();
  6344   template<typename T>
  6345   inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
  6346     return instance.get_abs();
  6349   template<typename T>
  6350   inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
  6351     return instance.get_cos();
  6354   template<typename T>
  6355   inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
  6356     return instance.get_sin();
  6359   template<typename T>
  6360   inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
  6361     return instance.get_tan();
  6364   template<typename T>
  6365   inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
  6366     return instance.get_acos();
  6369   template<typename T>
  6370   inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
  6371     return instance.get_asin();
  6374   template<typename T>
  6375   inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
  6376     return instance.get_atan();
  6379   template<typename T>
  6380   inline CImg<T> transpose(const CImg<T>& instance) {
  6381     return instance.get_transpose();
  6384   template<typename T>
  6385   inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
  6386     return instance.get_invert();
  6389   template<typename T>
  6390   inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
  6391     return instance.get_pseudoinvert();
  6394   /*-------------------------------------------
  6398    # Definition of the CImgDisplay structure
  6402    --------------------------------------------*/
  6404   //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
  6405   /**
  6406      Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
  6407      of a \c CImgList<T> image list inside. When a display is created, associated window events
  6408      (such as mouse motion, keyboard and window size changes) are handled and can be easily
  6409      detected by testing specific \c CImgDisplay data fields.
  6410      See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
  6411   **/
  6413   struct CImgDisplay {
  6415     //! Width of the display
  6416     unsigned int width;
  6418     //! Height of the display
  6419     unsigned int height;
  6421     //! Normalization type used for the display
  6422     unsigned int normalization;
  6424     //! Display title
  6425     char* title;
  6427     //! X-pos of the display on the screen
  6428     volatile int window_x;
  6430     //! Y-pos of the display on the screen
  6431     volatile int window_y;
  6433     //! Width of the underlying window
  6434     volatile unsigned int window_width;
  6436     //! Height of the underlying window
  6437     volatile unsigned int window_height;
  6439     //! X-coordinate of the mouse pointer on the display
  6440     volatile int mouse_x;
  6442     //! Y-coordinate of the mouse pointer on the display
  6443     volatile int mouse_y;
  6445     //! Button state of the mouse
  6446     volatile unsigned int buttons[512];
  6447     volatile unsigned int& button;
  6449     //! Wheel state of the mouse
  6450     volatile int wheel;
  6452     //! Key value if pressed
  6453     volatile unsigned int& key;
  6454     volatile unsigned int keys[512];
  6456     //! Key value if released
  6457     volatile unsigned int& released_key;
  6458     volatile unsigned int released_keys[512];
  6460     //! Closed state of the window
  6461     volatile bool is_closed;
  6463     //! Resized state of the window
  6464     volatile bool is_resized;
  6466     //! Moved state of the window
  6467     volatile bool is_moved;
  6469     //! Event state of the window
  6470     volatile bool is_event;
  6472     //! Current state of the corresponding key (exists for all referenced keys).
  6473     volatile bool is_keyESC;
  6474     volatile bool is_keyF1;
  6475     volatile bool is_keyF2;
  6476     volatile bool is_keyF3;
  6477     volatile bool is_keyF4;
  6478     volatile bool is_keyF5;
  6479     volatile bool is_keyF6;
  6480     volatile bool is_keyF7;
  6481     volatile bool is_keyF8;
  6482     volatile bool is_keyF9;
  6483     volatile bool is_keyF10;
  6484     volatile bool is_keyF11;
  6485     volatile bool is_keyF12;
  6486     volatile bool is_keyPAUSE;
  6487     volatile bool is_key1;
  6488     volatile bool is_key2;
  6489     volatile bool is_key3;
  6490     volatile bool is_key4;
  6491     volatile bool is_key5;
  6492     volatile bool is_key6;
  6493     volatile bool is_key7;
  6494     volatile bool is_key8;
  6495     volatile bool is_key9;
  6496     volatile bool is_key0;
  6497     volatile bool is_keyBACKSPACE;
  6498     volatile bool is_keyINSERT;
  6499     volatile bool is_keyHOME;
  6500     volatile bool is_keyPAGEUP;
  6501     volatile bool is_keyTAB;
  6502     volatile bool is_keyQ;
  6503     volatile bool is_keyW;
  6504     volatile bool is_keyE;
  6505     volatile bool is_keyR;
  6506     volatile bool is_keyT;
  6507     volatile bool is_keyY;
  6508     volatile bool is_keyU;
  6509     volatile bool is_keyI;
  6510     volatile bool is_keyO;
  6511     volatile bool is_keyP;
  6512     volatile bool is_keyDELETE;
  6513     volatile bool is_keyEND;
  6514     volatile bool is_keyPAGEDOWN;
  6515     volatile bool is_keyCAPSLOCK;
  6516     volatile bool is_keyA;
  6517     volatile bool is_keyS;
  6518     volatile bool is_keyD;
  6519     volatile bool is_keyF;
  6520     volatile bool is_keyG;
  6521     volatile bool is_keyH;
  6522     volatile bool is_keyJ;
  6523     volatile bool is_keyK;
  6524     volatile bool is_keyL;
  6525     volatile bool is_keyENTER;
  6526     volatile bool is_keySHIFTLEFT;
  6527     volatile bool is_keyZ;
  6528     volatile bool is_keyX;
  6529     volatile bool is_keyC;
  6530     volatile bool is_keyV;
  6531     volatile bool is_keyB;
  6532     volatile bool is_keyN;
  6533     volatile bool is_keyM;
  6534     volatile bool is_keySHIFTRIGHT;
  6535     volatile bool is_keyARROWUP;
  6536     volatile bool is_keyCTRLLEFT;
  6537     volatile bool is_keyAPPLEFT;
  6538     volatile bool is_keyALT;
  6539     volatile bool is_keySPACE;
  6540     volatile bool is_keyALTGR;
  6541     volatile bool is_keyAPPRIGHT;
  6542     volatile bool is_keyMENU;
  6543     volatile bool is_keyCTRLRIGHT;
  6544     volatile bool is_keyARROWLEFT;
  6545     volatile bool is_keyARROWDOWN;
  6546     volatile bool is_keyARROWRIGHT;
  6547     volatile bool is_keyPAD0;
  6548     volatile bool is_keyPAD1;
  6549     volatile bool is_keyPAD2;
  6550     volatile bool is_keyPAD3;
  6551     volatile bool is_keyPAD4;
  6552     volatile bool is_keyPAD5;
  6553     volatile bool is_keyPAD6;
  6554     volatile bool is_keyPAD7;
  6555     volatile bool is_keyPAD8;
  6556     volatile bool is_keyPAD9;
  6557     volatile bool is_keyPADADD;
  6558     volatile bool is_keyPADSUB;
  6559     volatile bool is_keyPADMUL;
  6560     volatile bool is_keyPADDIV;
  6562     //! Fullscreen state of the display
  6563     bool is_fullscreen;
  6565     float fps_fps, min, max;
  6566     unsigned long timer, fps_frames, fps_timer;
  6568 #ifdef cimgdisplay_plugin
  6569 #include cimgdisplay_plugin
  6570 #endif
  6571 #ifdef cimgdisplay_plugin1
  6572 #include cimgdisplay_plugin1
  6573 #endif
  6574 #ifdef cimgdisplay_plugin2
  6575 #include cimgdisplay_plugin2
  6576 #endif
  6577 #ifdef cimgdisplay_plugin3
  6578 #include cimgdisplay_plugin3
  6579 #endif
  6580 #ifdef cimgdisplay_plugin4
  6581 #include cimgdisplay_plugin4
  6582 #endif
  6583 #ifdef cimgdisplay_plugin5
  6584 #include cimgdisplay_plugin5
  6585 #endif
  6586 #ifdef cimgdisplay_plugin6
  6587 #include cimgdisplay_plugin6
  6588 #endif
  6589 #ifdef cimgdisplay_plugin7
  6590 #include cimgdisplay_plugin7
  6591 #endif
  6592 #ifdef cimgdisplay_plugin8
  6593 #include cimgdisplay_plugin8
  6594 #endif
  6596     //! Create an empty display window.
  6597     CImgDisplay():
  6598       width(0),height(0),normalization(0),title(0),
  6599       window_x(0),window_y(0),window_width(0),window_height(0),
  6600       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  6601       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
  6602       min(0),max(0) {}
  6604     //! Create a display window with a specified size \p pwidth x \p height.
  6605     /** \param dimw Width of the display window.
  6606         \param dimh Height of the display window.
  6607         \param title Title of the display window.
  6608         \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
  6609         \param fullscreen_flag : Fullscreen mode.
  6610         \param closed_flag : Initially visible mode.
  6611         A black image will be initially displayed in the display window.
  6612     **/
  6613     CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  6614                 const unsigned int normalization_type=3,
  6615                 const bool fullscreen_flag=false, const bool closed_flag=false):
  6616       width(0),height(0),normalization(0),title(0),
  6617       window_x(0),window_y(0),window_width(0),window_height(0),
  6618       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  6619       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
  6620       min(0),max(0) {
  6621       assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  6624     //! Create a display window from an image.
  6625     /** \param img : Image that will be used to create the display window.
  6626         \param title : Title of the display window
  6627         \param normalization_type : Normalization type of the display window.
  6628         \param fullscreen_flag : Fullscreen mode.
  6629         \param closed_flag : Initially visible mode.
  6630     **/
  6631     template<typename T>
  6632     CImgDisplay(const CImg<T>& img, const char *title=0,
  6633                 const unsigned int normalization_type=3,
  6634                 const bool fullscreen_flag=false, const bool closed_flag=false):
  6635       width(0),height(0),normalization(0),title(0),
  6636       window_x(0),window_y(0),window_width(0),window_height(0),
  6637       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  6638       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  6639       assign(img,title,normalization_type,fullscreen_flag,closed_flag);
  6642     //! Create a display window from an image list.
  6643     /** \param list : The list of images to display.
  6644         \param title : Title of the display window
  6645         \param normalization_type : Normalization type of the display window.
  6646         \param fullscreen_flag : Fullscreen mode.
  6647         \param closed_flag : Initially visible mode.
  6648     **/
  6649     template<typename T>
  6650     CImgDisplay(const CImgList<T>& list, const char *title=0,
  6651                 const unsigned int normalization_type=3,
  6652                 const bool fullscreen_flag=false, const bool closed_flag=false):
  6653       width(0),height(0),normalization(0),title(0),
  6654       window_x(0),window_y(0),window_width(0),window_height(0),
  6655       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  6656       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  6657       assign(list,title,normalization_type,fullscreen_flag,closed_flag);
  6660     //! Create a display window by copying another one.
  6661     /**
  6662         \param disp  : Display window to copy.
  6663     **/
  6664     CImgDisplay(const CImgDisplay& disp):
  6665       width(0),height(0),normalization(0),title(0),
  6666       window_x(0),window_y(0),window_width(0),window_height(0),
  6667       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  6668       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  6669       assign(disp);
  6672     //! Destructor.
  6673     ~CImgDisplay() {
  6674       assign();
  6677     //! Assignment operator.
  6678     CImgDisplay& operator=(const CImgDisplay& disp) {
  6679       return assign(disp);
  6682     //! Return true is display is empty.
  6683     bool is_empty() const {
  6684       return (!width || !height);
  6687     //! Return true if display is not empty.
  6688     operator bool() const {
  6689       return !is_empty();
  6692     //! Return display width.
  6693     int dimx() const {
  6694       return (int)width;
  6697     //! Return display height.
  6698     int dimy() const {
  6699       return (int)height;
  6702     //! Return display window width.
  6703     int window_dimx() const {
  6704       return (int)window_width;
  6707     //! Return display window height.
  6708     int window_dimy() const {
  6709       return (int)window_height;
  6712     //! Return X-coordinate of the window.
  6713     int window_posx() const {
  6714       return window_x;
  6717     //! Return Y-coordinate of the window.
  6718     int window_posy() const {
  6719       return window_y;
  6722     //! Synchronized waiting function. Same as cimg::wait().
  6723     CImgDisplay& wait(const unsigned int milliseconds) {
  6724       cimg::_sleep(milliseconds,timer);
  6725       return *this;
  6728     //! Wait for an event occuring on the current display.
  6729     CImgDisplay& wait() {
  6730       if (!is_empty()) wait(*this);
  6731       return *this;
  6734     //! Wait for any event occuring on the display \c disp1.
  6735     static void wait(CImgDisplay& disp1) {
  6736       disp1.is_event = 0;
  6737       while (!disp1.is_event) wait_all();
  6740     //! Wait for any event occuring either on the display \c disp1 or \c disp2.
  6741     static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
  6742       disp1.is_event = disp2.is_event = 0;
  6743       while (!disp1.is_event && !disp2.is_event) wait_all();
  6746     //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
  6747     static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
  6748       disp1.is_event = disp2.is_event = disp3.is_event = 0;
  6749       while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
  6752     //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
  6753     static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
  6754       disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
  6755       while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
  6758     //! Return the frame per second rate.
  6759     float frames_per_second() {
  6760       if (!fps_timer) fps_timer = cimg::time();
  6761       const float delta = (cimg::time()-fps_timer)/1000.0f;
  6762       ++fps_frames;
  6763       if (delta>=1) {
  6764         fps_fps = fps_frames/delta;
  6765         fps_frames = 0;
  6766         fps_timer = cimg::time();
  6768       return fps_fps;
  6771     //! Display an image list CImgList<T> into a display window.
  6772     /** First, all images of the list are appended into a single image used for visualization,
  6773         then this image is displayed in the current display window.
  6774         \param list     : The list of images to display.
  6775         \param axis     : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
  6776         \param align : Defines the relative alignment of images when displaying images of different sizes.
  6777         Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
  6778     **/
  6779     template<typename T>
  6780     CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
  6781       return display(list.get_append(axis,align));
  6784     //! Display an image CImg<T> into a display window.
  6785     template<typename T>
  6786     CImgDisplay& operator<<(const CImg<T>& img) {
  6787       return display(img);
  6790     //! Display an image CImg<T> into a display window.
  6791     template<typename T>
  6792     CImgDisplay& operator<<(const CImgList<T>& list) {
  6793       return display(list);
  6796     //! Resize a display window with the size of an image.
  6797     /** \param img    : Input image. \p image.width and \p image.height give the new dimensions of the display window.
  6798         \param redraw : If \p true (default), the current displayed image in the display window will
  6799         be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
  6800     **/
  6801     template<typename T>
  6802     CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
  6803       return resize(img.width,img.height,redraw);
  6806     //! Resize a display window using the size of the given display \p disp.
  6807     CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
  6808       return resize(disp.width,disp.height,redraw);
  6811     //! Resize a display window in its current size.
  6812     CImgDisplay& resize(const bool redraw=true) {
  6813       resize(window_width,window_height,redraw);
  6814       return *this;
  6817     //! Set fullscreen mode.
  6818     CImgDisplay& fullscreen(const bool redraw=true) {
  6819       if (is_empty() || is_fullscreen) return *this;
  6820       return toggle_fullscreen(redraw);
  6823     //! Set normal screen mode.
  6824     CImgDisplay& normalscreen(const bool redraw=true) {
  6825       if (is_empty() || !is_fullscreen) return *this;
  6826       return toggle_fullscreen(redraw);
  6829     // Inner routine used for fast resizing of buffer to display size.
  6830     template<typename t, typename T>
  6831     static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
  6832                                t *ptrd, const unsigned int wd, const unsigned int hd) {
  6833       unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
  6834       float s, curr, old;
  6835       s = (float)ws/wd;
  6836       poffx = offx; curr = 0; for (unsigned int x=0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
  6837       s = (float)hs/hd;
  6838       poffy = offy; curr = 0; for (unsigned int y=0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
  6839       *poffy = 0;
  6840       poffy = offy;
  6841       {for (unsigned int y=0; y<hd; ) {
  6842         const T *ptr = ptrs;
  6843         poffx = offx;
  6844         for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
  6845         ++y;
  6846         unsigned int dy=*(poffy++);
  6847         for (;!dy && y<hd; cimg_std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
  6848         ptrs+=dy;
  6849       }}
  6850       delete[] offx; delete[] offy;
  6853     //! Clear all events of the current display.
  6854     CImgDisplay& flush() {
  6855       cimg_std::memset((void*)buttons,0,512*sizeof(unsigned int));
  6856       cimg_std::memset((void*)keys,0,512*sizeof(unsigned int));
  6857       cimg_std::memset((void*)released_keys,0,512*sizeof(unsigned int));
  6858       is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
  6859         is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
  6860         is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
  6861         is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
  6862         is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
  6863         is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
  6864         is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keyALT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
  6865         is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
  6866         is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
  6867         is_keyPADMUL = is_keyPADDIV = false;
  6868       is_resized = is_moved = is_event = false;
  6869       fps_timer = fps_frames = timer = wheel = 0;
  6870       mouse_x = mouse_y = -1;
  6871       fps_fps = 0;
  6872       return *this;
  6875     // Update 'is_key' fields.
  6876     void update_iskey(const unsigned int key, const bool pressed=true) {
  6877 #define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
  6878       _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
  6879       _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
  6880       _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
  6881       _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
  6882       _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
  6883       _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
  6884       _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
  6885       _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
  6886       _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
  6887       _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
  6888       _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
  6889       _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
  6890       _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
  6891       _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
  6892       _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
  6893       _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
  6894       _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
  6895       _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
  6896       _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
  6897       _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
  6898       _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
  6899       _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
  6900       _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
  6901       _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
  6902       _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
  6905     //! Test if any key has been pressed.
  6906     bool is_key(const bool remove=false) {
  6907       for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
  6908       return false;
  6911     //! Test if a key has been pressed.
  6912     bool is_key(const unsigned int key1, const bool remove) {
  6913       for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
  6914       return false;
  6917     //! Test if a key sequence has been typed.
  6918     bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
  6919       const unsigned int seq[] = { key1, key2 };
  6920       return is_key(seq,2,remove);
  6923     //! Test if a key sequence has been typed.
  6924     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
  6925       const unsigned int seq[] = { key1, key2, key3 };
  6926       return is_key(seq,3,remove);
  6929     //! Test if a key sequence has been typed.
  6930     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6931                  const unsigned int key4, const bool remove) {
  6932       const unsigned int seq[] = { key1, key2, key3, key4 };
  6933       return is_key(seq,4,remove);
  6936     //! Test if a key sequence has been typed.
  6937     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6938                 const unsigned int key4, const unsigned int key5, const bool remove) {
  6939       const unsigned int seq[] = { key1, key2, key3, key4, key5 };
  6940       return is_key(seq,5,remove);
  6943     //! Test if a key sequence has been typed.
  6944     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6945                 const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
  6946       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
  6947       return is_key(seq,6,remove);
  6950     //! Test if a key sequence has been typed.
  6951     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6952                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
  6953                 const unsigned int key7, const bool remove) {
  6954       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
  6955       return is_key(seq,7,remove);
  6958     //! Test if a key sequence has been typed.
  6959     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6960                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
  6961                 const unsigned int key7, const unsigned int key8, const bool remove) {
  6962       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
  6963       return is_key(seq,8,remove);
  6966     //! Test if a key sequence has been typed.
  6967     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  6968                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
  6969                 const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
  6970       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
  6971       return is_key(seq,9,remove);
  6974     //! Test if a key sequence has been typed.
  6975     bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
  6976       if (keyseq && N) {
  6977         const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
  6978         for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
  6979           if (*(pk++)==k) {
  6980             bool res = true;
  6981             const unsigned int *ps = ps_end, *pk2 = pk;
  6982             for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
  6983             if (res) {
  6984               if (remove) cimg_std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
  6985               return true;
  6990       return false;
  6993     // Find the good width and height of a window to display an image (internal routine).
  6994 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
  6995     static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
  6996                                    const int dmin=128, const int dmax=-85,const bool return_last=false) {
  6997       unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
  6998       const unsigned int
  6999         sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
  7000         mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
  7001         mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
  7002         Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
  7003         Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
  7004       if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
  7005       if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
  7006       if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
  7007       if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
  7008       if (nw<mw) nw = mw;
  7009       if (nh<mh) nh = mh;
  7010       if (return_last) return nh;
  7011       return nw;
  7014     // When no display available
  7015     //---------------------------
  7016 #if cimg_display==0
  7018     //! Return the width of the screen resolution.
  7019     static int screen_dimx() {
  7020       return 0;
  7023     //! Return the height of the screen resolution.
  7024     static int screen_dimy() {
  7025       return 0;
  7028     //! Wait for a window event in any CImg window.
  7029     static void wait_all() {}
  7031     //! In-place version of the destructor.
  7032     CImgDisplay& assign() {
  7033       return *this;
  7036     //! In-place version of the previous constructor.
  7037     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  7038                         const unsigned int normalization_type=3,
  7039                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7040       throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
  7041       const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  7042       avoid_warning = 0;
  7043       return *this;
  7046     //! In-place version of the previous constructor.
  7047     template<typename T>
  7048     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  7049                         const unsigned int normalization_type=3,
  7050                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7051       throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
  7052       const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  7053       avoid_warning = 0;
  7054       return assign(0,0);
  7057     //! In-place version of the previous constructor.
  7058     template<typename T>
  7059     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  7060                         const unsigned int normalization_type=3,
  7061                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7062       throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
  7063       const char* avoid_warning = title + list.size + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  7064       avoid_warning = 0;
  7065       return assign(0,0);
  7068     //! In-place version of the previous constructor.
  7069     CImgDisplay& assign(const CImgDisplay &disp) {
  7070       return assign(disp.width,disp.height);
  7073     //! Resize window.
  7074     CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
  7075       int avoid_warning = width | height | (int)redraw;
  7076       avoid_warning = 0;
  7077       return *this;
  7080     //! Toggle fullscreen mode.
  7081     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  7082       bool avoid_warning = redraw;
  7083       avoid_warning = false;
  7084       return *this;
  7087     //! Show a closed display.
  7088     CImgDisplay& show() {
  7089       return *this;
  7092     //! Close a visible display.
  7093     CImgDisplay& close() {
  7094       return *this;
  7097     //! Move window.
  7098     CImgDisplay& move(const int posx, const int posy) {
  7099       int avoid_warning = posx | posy;
  7100       avoid_warning = 0;
  7101       return *this;
  7104     //! Show mouse pointer.
  7105     CImgDisplay& show_mouse() {
  7106       return *this;
  7109     //! Hide mouse pointer.
  7110     CImgDisplay& hide_mouse() {
  7111       return *this;
  7114     //! Move mouse pointer to a specific location.
  7115     CImgDisplay& set_mouse(const int posx, const int posy) {
  7116       int avoid_warning = posx | posy;
  7117       avoid_warning = 0;
  7118       return *this;
  7121     //! Set the window title.
  7122     CImgDisplay& set_title(const char *format, ...) {
  7123       const char *avoid_warning = format;
  7124       avoid_warning = 0;
  7125       return *this;
  7128     //! Display an image in a window.
  7129     template<typename T>
  7130     CImgDisplay& display(const CImg<T>& img) {
  7131       unsigned int avoid_warning = img.width;
  7132       avoid_warning = 0;
  7133       return *this;
  7136     //! Re-paint image content in window.
  7137     CImgDisplay& paint() {
  7138       return *this;
  7141     //! Render image buffer into GDI native image format.
  7142     template<typename T>
  7143     CImgDisplay& render(const CImg<T>& img) {
  7144       unsigned int avoid_warning = img.width;
  7145       avoid_warning = 0;
  7146       return *this;
  7149     //! Take a snapshot of the display in the specified image.
  7150     template<typename T>
  7151     const CImgDisplay& snapshot(CImg<T>& img) const {
  7152       img.assign(width,height,1,3,0);
  7153       return *this;
  7156     // X11-based display
  7157     //-------------------
  7158 #elif cimg_display==1
  7159     Atom wm_delete_window, wm_delete_protocol;
  7160     Window window, background_window;
  7161     Colormap colormap;
  7162     XImage *image;
  7163     void *data;
  7164 #ifdef cimg_use_xshm
  7165     XShmSegmentInfo *shminfo;
  7166 #endif
  7168     static int screen_dimx() {
  7169       int res = 0;
  7170       if (!cimg::X11attr().display) {
  7171         Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
  7172         if (!disp)
  7173           throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
  7174         res = DisplayWidth(disp,DefaultScreen(disp));
  7175         XCloseDisplay(disp);
  7176       } else {
  7177 #ifdef cimg_use_xrandr
  7178         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
  7179           res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
  7180         else
  7181 #endif
  7182           res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  7184       return res;
  7187     static int screen_dimy() {
  7188       int res = 0;
  7189       if (!cimg::X11attr().display) {
  7190         Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY") ? cimg_std::getenv("DISPLAY") : ":0.0"));
  7191         if (!disp)
  7192           throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
  7193         res = DisplayHeight(disp,DefaultScreen(disp));
  7194         XCloseDisplay(disp);
  7195       } else {
  7196 #ifdef cimg_use_xrandr
  7197         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
  7198           res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
  7199         else
  7200 #endif
  7201           res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  7203       return res;
  7206     static void wait_all() {
  7207       if (cimg::X11attr().display) {
  7208         XLockDisplay(cimg::X11attr().display);
  7209         bool flag = true;
  7210         XEvent event;
  7211         while (flag) {
  7212           XNextEvent(cimg::X11attr().display, &event);
  7213           for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
  7214             if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
  7215               cimg::X11attr().wins[i]->_handle_events(&event);
  7216               if (cimg::X11attr().wins[i]->is_event) flag = false;
  7219         XUnlockDisplay(cimg::X11attr().display);
  7223     void _handle_events(const XEvent *const pevent) {
  7224       XEvent event = *pevent;
  7225       switch (event.type) {
  7226       case ClientMessage : {
  7227         if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
  7228             (int)event.xclient.data.l[0]==(int)wm_delete_window) {
  7229           XUnmapWindow(cimg::X11attr().display,window);
  7230           mouse_x = mouse_y = -1;
  7231           if (button) { cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
  7232           if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
  7233           if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
  7234           is_closed = is_event = true;
  7236       } break;
  7237       case ConfigureNotify : {
  7238         while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
  7239         const unsigned int
  7240           nw = event.xconfigure.width,
  7241           nh = event.xconfigure.height;
  7242         const int
  7243           nx = event.xconfigure.x,
  7244           ny = event.xconfigure.y;
  7245         if (nw && nh && (nw!=window_width || nh!=window_height)) {
  7246           window_width = nw;
  7247           window_height = nh;
  7248           mouse_x = mouse_y = -1;
  7249           XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
  7250           is_resized = is_event = true;
  7252         if (nx!=window_x || ny!=window_y) {
  7253           window_x = nx;
  7254           window_y = ny;
  7255           is_moved = is_event = true;
  7257       } break;
  7258       case Expose : {
  7259         while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
  7260         _paint(false);
  7261         if (is_fullscreen) {
  7262           XWindowAttributes attr;
  7263           XGetWindowAttributes(cimg::X11attr().display, window, &attr);
  7264           while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
  7265           XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
  7267       } break;
  7268       case ButtonPress : {
  7269         do {
  7270         mouse_x = event.xmotion.x;
  7271         mouse_y = event.xmotion.y;
  7272         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  7273           switch (event.xbutton.button) {
  7274           case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
  7275           case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
  7276           case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
  7278         } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
  7279       } break;
  7280       case ButtonRelease : {
  7281         do {
  7282         mouse_x = event.xmotion.x;
  7283         mouse_y = event.xmotion.y;
  7284         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  7285           switch (event.xbutton.button) {
  7286           case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
  7287           case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
  7288           case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
  7289           case 4 : ++wheel; is_event = true; break;
  7290           case 5 : --wheel; is_event = true; break;
  7292         } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
  7293       } break;
  7294       case KeyPress : {
  7295         char tmp;
  7296         KeySym ksym;
  7297         XLookupString(&event.xkey,&tmp,1,&ksym,0);
  7298         update_iskey((unsigned int)ksym,true);
  7299         if (key) cimg_std::memmove((void*)(keys+1),(void*)keys,512-1);
  7300         key = (unsigned int)ksym;
  7301         if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
  7302         is_event = true;
  7303       } break;
  7304       case KeyRelease : {
  7305         char tmp;
  7306         KeySym ksym;
  7307         XLookupString(&event.xkey,&tmp,1,&ksym,0);
  7308         update_iskey((unsigned int)ksym,false);
  7309         if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
  7310         if (released_key) cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
  7311         released_key = (unsigned int)ksym;
  7312         is_event = true;
  7313       } break;
  7314       case EnterNotify: {
  7315         while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
  7316         mouse_x = event.xmotion.x;
  7317         mouse_y = event.xmotion.y;
  7318         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  7319       } break;
  7320       case LeaveNotify : {
  7321         while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
  7322         mouse_x = mouse_y =-1;
  7323         is_event = true;
  7324       } break;
  7325       case MotionNotify : {
  7326         while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
  7327         mouse_x = event.xmotion.x;
  7328         mouse_y = event.xmotion.y;
  7329         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  7330         is_event = true;
  7331       } break;
  7335     static void* _events_thread(void *arg) {
  7336       arg = 0;
  7337       XEvent event;
  7338       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
  7339       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
  7340       for (;;) {
  7341         XLockDisplay(cimg::X11attr().display);
  7342         bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
  7343         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
  7344                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
  7345                                                       KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
  7346                                                       ButtonReleaseMask|KeyReleaseMask,&event);
  7347         if (event_flag) {
  7348           for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
  7349             if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
  7350               cimg::X11attr().wins[i]->_handle_events(&event);
  7352         XUnlockDisplay(cimg::X11attr().display);
  7353         pthread_testcancel();
  7354         cimg::sleep(7);
  7356       return 0;
  7359     void _set_colormap(Colormap& colormap, const unsigned int dim) {
  7360       XColor palette[256];
  7361       switch (dim) {
  7362       case 1 : { // palette for greyscale images
  7363         for (unsigned int index=0; index<256; ++index) {
  7364           palette[index].pixel = index;
  7365           palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
  7366           palette[index].flags = DoRed | DoGreen | DoBlue;
  7368       } break;
  7369       case 2 : { // palette for RG images
  7370         for (unsigned int index=0, r=8; r<256; r+=16)
  7371           for (unsigned int g=8; g<256; g+=16) {
  7372             palette[index].pixel = index;
  7373             palette[index].red = palette[index].blue = (unsigned short)(r<<8);
  7374             palette[index].green = (unsigned short)(g<<8);
  7375             palette[index++].flags = DoRed | DoGreen | DoBlue;
  7377       } break;
  7378       default : { // palette for RGB images
  7379         for (unsigned int index=0, r=16; r<256; r+=32)
  7380           for (unsigned int g=16; g<256; g+=32)
  7381             for (unsigned int b=32; b<256; b+=64) {
  7382               palette[index].pixel = index;
  7383               palette[index].red = (unsigned short)(r<<8);
  7384               palette[index].green = (unsigned short)(g<<8);
  7385               palette[index].blue = (unsigned short)(b<<8);
  7386               palette[index++].flags = DoRed | DoGreen | DoBlue;
  7390       XStoreColors(cimg::X11attr().display,colormap,palette,256);
  7393     void _map_window() {
  7394       XWindowAttributes attr;
  7395       XEvent event;
  7396       bool exposed = false, mapped = false;
  7397       XMapRaised(cimg::X11attr().display,window);
  7398       XSync(cimg::X11attr().display,False);
  7399       do {
  7400         XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
  7401         switch (event.type) {
  7402         case MapNotify : mapped = true; break;
  7403         case Expose : exposed = true; break;
  7404         default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
  7406       } while (!(exposed && mapped));
  7407       do {
  7408         XGetWindowAttributes(cimg::X11attr().display, window, &attr);
  7409         if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
  7410       } while (attr.map_state != IsViewable);
  7411       window_x = attr.x;
  7412       window_y = attr.y;
  7415     void _paint(const bool wait_expose=true) {
  7416       if (!is_closed) {
  7417         if (wait_expose) {
  7418           static XEvent event;
  7419           event.xexpose.type = Expose;
  7420           event.xexpose.serial = 0;
  7421           event.xexpose.send_event = True;
  7422           event.xexpose.display = cimg::X11attr().display;
  7423           event.xexpose.window = window;
  7424           event.xexpose.x = 0;
  7425           event.xexpose.y = 0;
  7426           event.xexpose.width = dimx();
  7427           event.xexpose.height = dimy();
  7428           event.xexpose.count = 0;
  7429           XSendEvent(cimg::X11attr().display, window, False, 0, &event);
  7430         } else {
  7431 #ifdef cimg_use_xshm
  7432           if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
  7433           else
  7434 #endif
  7435             XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
  7436           XSync(cimg::X11attr().display, False);
  7441     template<typename T>
  7442     void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
  7443       foo = 0;
  7444 #ifdef cimg_use_xshm
  7445       if (shminfo) {
  7446         XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
  7447         XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7448                                          cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
  7449         if (!nimage) {
  7450           delete nshminfo;
  7451           return;
  7452         } else {
  7453           nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
  7454           if (nshminfo->shmid==-1) {
  7455             XDestroyImage(nimage);
  7456             delete nshminfo;
  7457             return;
  7458           } else {
  7459             nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
  7460             if (nshminfo->shmaddr==(char*)-1) {
  7461               shmctl(nshminfo->shmid,IPC_RMID,0);
  7462               XDestroyImage(nimage);
  7463               delete nshminfo;
  7464               return;
  7465             } else {
  7466               nshminfo->readOnly = False;
  7467               cimg::X11attr().shm_enabled = true;
  7468               XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
  7469               XShmAttach(cimg::X11attr().display, nshminfo);
  7470               XSync(cimg::X11attr().display, False);
  7471               XSetErrorHandler(oldXErrorHandler);
  7472               if (!cimg::X11attr().shm_enabled) {
  7473                 shmdt(nshminfo->shmaddr);
  7474                 shmctl(nshminfo->shmid,IPC_RMID,0);
  7475                 XDestroyImage(nimage);
  7476                 delete nshminfo;
  7477                 return;
  7478               } else {
  7479                 T *const ndata = (T*)nimage->data;
  7480                 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
  7481                 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
  7482                 XShmDetach(cimg::X11attr().display, shminfo);
  7483                 XDestroyImage(image);
  7484                 shmdt(shminfo->shmaddr);
  7485                 shmctl(shminfo->shmid,IPC_RMID,0);
  7486                 delete shminfo;
  7487                 shminfo = nshminfo;
  7488                 image = nimage;
  7489                 data = (void*)ndata;
  7494       } else
  7495 #endif
  7497           T *ndata = (T*)cimg_std::malloc(ndimx*ndimy*sizeof(T));
  7498           if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
  7499           else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
  7500           data = (void*)ndata;
  7501           XDestroyImage(image);
  7502           image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7503                                cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
  7507     void _init_fullscreen() {
  7508       background_window = 0;
  7509       if (is_fullscreen && !is_closed) {
  7510 #ifdef cimg_use_xrandr
  7511         int foo;
  7512         if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
  7513           XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
  7514           if (!cimg::X11attr().resolutions) {
  7515             cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
  7516             cimg::X11attr().nb_resolutions = (unsigned int)foo;
  7518           if (cimg::X11attr().resolutions) {
  7519             cimg::X11attr().curr_resolution = 0;
  7520             for (unsigned int i=0; i<cimg::X11attr().nb_resolutions; ++i) {
  7521               const unsigned int
  7522                 nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
  7523                 nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
  7524               if (nw>=width && nh>=height &&
  7525                   nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
  7526                   nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
  7527                 cimg::X11attr().curr_resolution = i;
  7529             if (cimg::X11attr().curr_resolution>0) {
  7530               XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
  7531               XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
  7532                                  cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
  7533               XRRFreeScreenConfigInfo(config);
  7534               XSync(cimg::X11attr().display, False);
  7538         if (!cimg::X11attr().resolutions)
  7539           cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
  7540 #endif
  7541         const unsigned int sx = screen_dimx(), sy = screen_dimy();
  7542         XSetWindowAttributes winattr;
  7543         winattr.override_redirect = True;
  7544         if (sx!=width || sy!=height) {
  7545           background_window = XCreateWindow(cimg::X11attr().display,
  7546                                             RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
  7547                                             sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
  7548           const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  7549           void *background_data = cimg_std::malloc(bufsize);
  7550           cimg_std::memset(background_data,0,bufsize);
  7551           XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7552                                                   cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
  7553           XEvent event;
  7554           XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
  7555           XMapRaised(cimg::X11attr().display,background_window);
  7556           do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
  7557           while (event.type!=MapNotify);
  7558 #ifdef cimg_use_xshm
  7559           if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
  7560           else
  7561 #endif
  7562             XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
  7563           XWindowAttributes attr;
  7564           XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
  7565           while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
  7566           XDestroyImage(background_image);
  7571     void _desinit_fullscreen() {
  7572       if (is_fullscreen) {
  7573         XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
  7574 #ifdef cimg_use_xrandr
  7575         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
  7576           XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
  7577           XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
  7578                              0, cimg::X11attr().curr_rotation, CurrentTime);
  7579           XRRFreeScreenConfigInfo(config);
  7580           XSync(cimg::X11attr().display, False);
  7581           cimg::X11attr().curr_resolution = 0;
  7583 #endif
  7584         if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
  7585         background_window = 0;
  7586         is_fullscreen = false;
  7590     static int _assign_xshm(Display *dpy, XErrorEvent *error) {
  7591       dpy = 0; error = 0;
  7592       cimg::X11attr().shm_enabled = false;
  7593       return 0;
  7596     void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  7597                  const unsigned int normalization_type=3,
  7598                  const bool fullscreen_flag=false, const bool closed_flag=false) {
  7600       // Allocate space for window title
  7601       const int s = cimg::strlen(ptitle)+1;
  7602       char *tmp_title = s?new char[s]:0;
  7603       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  7605       // Destroy previous display window if existing
  7606       if (!is_empty()) assign();
  7608       // Open X11 display if necessary.
  7609       if (!cimg::X11attr().display) {
  7610         static bool xinit_threads = false;
  7611         if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
  7612         cimg::X11attr().nb_wins = 0;
  7613         cimg::X11attr().display = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
  7614         if (!cimg::X11attr().display)
  7615           throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
  7616         cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
  7617         if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
  7618           throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
  7619                                      "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
  7620         cimg::X11attr().gc = new GC;
  7621         *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  7622         Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  7623         XVisualInfo vtemplate;
  7624         vtemplate.visualid = XVisualIDFromVisual(visual);
  7625         int nb_visuals;
  7626         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
  7627         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
  7628         cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
  7629         XFree(vinfo);
  7630         XLockDisplay(cimg::X11attr().display);
  7631         cimg::X11attr().event_thread = new pthread_t;
  7632         pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
  7633       } else XLockDisplay(cimg::X11attr().display);
  7635       // Set display variables
  7636       width = cimg::min(dimw,(unsigned int)screen_dimx());
  7637       height = cimg::min(dimh,(unsigned int)screen_dimy());
  7638       normalization = normalization_type<4?normalization_type:3;
  7639       is_fullscreen = fullscreen_flag;
  7640       window_x = window_y = 0;
  7641       is_closed = closed_flag;
  7642       title = tmp_title;
  7643       flush();
  7645       // Create X11 window and palette (if 8bits display)
  7646       if (is_fullscreen) {
  7647         if (!is_closed) _init_fullscreen();
  7648         const unsigned int sx = screen_dimx(), sy = screen_dimy();
  7649         XSetWindowAttributes winattr;
  7650         winattr.override_redirect = True;
  7651         window = XCreateWindow(cimg::X11attr().display,
  7652                                RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7653                                (sx-width)/2,(sy-height)/2,
  7654                                width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
  7655       } else
  7656         window = XCreateSimpleWindow(cimg::X11attr().display,
  7657                                      RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7658                                      0,0,width,height,2,0,0x0L);
  7659       XStoreName(cimg::X11attr().display,window,title?title:" ");
  7660       if (cimg::X11attr().nb_bits==8) {
  7661         colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
  7662                                                                                 DefaultScreen(cimg::X11attr().display)),AllocAll);
  7663         _set_colormap(colormap,3);
  7664         XSetWindowColormap(cimg::X11attr().display,window,colormap);
  7666       window_width = width;
  7667       window_height = height;
  7669       // Create XImage
  7670       const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  7671 #ifdef cimg_use_xshm
  7672       shminfo = 0;
  7673       if (XShmQueryExtension(cimg::X11attr().display)) {
  7674         shminfo = new XShmSegmentInfo;
  7675         image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7676                                 cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
  7677         if (!image) {
  7678           delete shminfo;
  7679           shminfo = 0;
  7680         } else {
  7681           shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
  7682           if (shminfo->shmid==-1) {
  7683             XDestroyImage(image);
  7684             delete shminfo;
  7685             shminfo = 0;
  7686           } else {
  7687             shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
  7688             if (shminfo->shmaddr==(char*)-1) {
  7689               shmctl(shminfo->shmid,IPC_RMID,0);
  7690               XDestroyImage(image);
  7691               delete shminfo;
  7692               shminfo = 0;
  7693             } else {
  7694               shminfo->readOnly = False;
  7695               cimg::X11attr().shm_enabled = true;
  7696               XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
  7697               XShmAttach(cimg::X11attr().display, shminfo);
  7698               XSync(cimg::X11attr().display, False);
  7699               XSetErrorHandler(oldXErrorHandler);
  7700               if (!cimg::X11attr().shm_enabled) {
  7701                 shmdt(shminfo->shmaddr);
  7702                 shmctl(shminfo->shmid,IPC_RMID,0);
  7703                 XDestroyImage(image);
  7704                 delete shminfo;
  7705                 shminfo = 0;
  7711       if (!shminfo)
  7712 #endif
  7714           data = cimg_std::malloc(bufsize);
  7715           image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  7716                                cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
  7719       wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
  7720       wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
  7721       XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
  7722       XSelectInput(cimg::X11attr().display,window,
  7723                    ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
  7724                    EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
  7725       if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
  7726       cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
  7727       if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
  7728       XUnlockDisplay(cimg::X11attr().display);
  7731     CImgDisplay& assign() {
  7732       if (is_empty()) return *this;
  7733       XLockDisplay(cimg::X11attr().display);
  7735       // Remove display window from event thread list.
  7736       unsigned int i;
  7737       for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
  7738       for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
  7739       --cimg::X11attr().nb_wins;
  7741       // Destroy window, image, colormap and title.
  7742       if (is_fullscreen && !is_closed) _desinit_fullscreen();
  7743       XDestroyWindow(cimg::X11attr().display,window);
  7744       window = 0;
  7745 #ifdef cimg_use_xshm
  7746       if (shminfo) {
  7747         XShmDetach(cimg::X11attr().display, shminfo);
  7748         XDestroyImage(image);
  7749         shmdt(shminfo->shmaddr);
  7750         shmctl(shminfo->shmid,IPC_RMID,0);
  7751         delete shminfo;
  7752         shminfo = 0;
  7753       } else
  7754 #endif
  7755         XDestroyImage(image);
  7756       data = 0; image = 0;
  7757       if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
  7758       colormap = 0;
  7759       XSync(cimg::X11attr().display, False);
  7761       // Reset display variables
  7762       if (title) delete[] title;
  7763       width = height = normalization = window_width = window_height = 0;
  7764       window_x = window_y = 0;
  7765       is_fullscreen = false;
  7766       is_closed = true;
  7767       min = max = 0;
  7768       title = 0;
  7769       flush();
  7771       // End event thread and close display if necessary
  7772       XUnlockDisplay(cimg::X11attr().display);
  7774       /* The code below was used to close the X11 display when not used anymore,
  7775          unfortunately, since the latest Xorg versions, it randomely hangs, so
  7776          I prefer to remove it. A fix would be needed anyway.
  7778          if (!cimg::X11attr().nb_wins) {
  7779          // Kill event thread
  7780          pthread_cancel(*cimg::X11attr().event_thread);
  7781          XUnlockDisplay(cimg::X11attr().display);
  7782          pthread_join(*cimg::X11attr().event_thread,0);
  7783          delete cimg::X11attr().event_thread;
  7784          cimg::X11attr().event_thread = 0;
  7785          XCloseDisplay(cimg::X11attr().display);
  7786          cimg::X11attr().display = 0;
  7787          delete cimg::X11attr().gc;
  7788          cimg::X11attr().gc = 0;
  7789          } else XUnlockDisplay(cimg::X11attr().display);
  7790       */
  7791       return *this;
  7794     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  7795                         const unsigned int normalization_type=3,
  7796                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7797       if (!dimw || !dimh) return assign();
  7798       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  7799       min = max = 0;
  7800       cimg_std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
  7801                           (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
  7802       return paint();
  7805     template<typename T>
  7806     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  7807                         const unsigned int normalization_type=3,
  7808                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7809       if (!img) return assign();
  7810       CImg<T> tmp;
  7811       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  7812       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  7813       if (normalization==2) min = (float)nimg.minmax(max);
  7814       return render(nimg).paint();
  7817     template<typename T>
  7818     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  7819                         const unsigned int normalization_type=3,
  7820                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  7821       if (!list) return assign();
  7822       CImg<T> tmp;
  7823       const CImg<T> img = list.get_append('x','p'),
  7824         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  7825       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  7826       if (normalization==2) min = (float)nimg.minmax(max);
  7827       return render(nimg).paint();
  7830     CImgDisplay& assign(const CImgDisplay& win) {
  7831       if (!win) return assign();
  7832       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  7833       cimg_std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
  7834                                  cimg::X11attr().nb_bits==16?sizeof(unsigned short):
  7835                                  sizeof(unsigned int))*width*height);
  7836       return paint();
  7839     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  7840       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  7841       if (is_empty()) return assign(nwidth,nheight);
  7842       const unsigned int
  7843         tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
  7844         tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
  7845         dimx = tmpdimx?tmpdimx:1,
  7846         dimy = tmpdimy?tmpdimy:1;
  7847       XLockDisplay(cimg::X11attr().display);
  7848       if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
  7849       if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
  7850       case 8 :  { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
  7851       case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
  7852       default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
  7854       window_width = width = dimx; window_height = height = dimy;
  7855       is_resized = false;
  7856       XUnlockDisplay(cimg::X11attr().display);
  7857       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  7858       if (redraw) return paint();
  7859       return *this;
  7862     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  7863       if (is_empty()) return *this;
  7864       if (redraw) {
  7865         const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  7866         void *odata = cimg_std::malloc(bufsize);
  7867         cimg_std::memcpy(odata,data,bufsize);
  7868         assign(width,height,title,normalization,!is_fullscreen,false);
  7869         cimg_std::memcpy(data,odata,bufsize);
  7870         cimg_std::free(odata);
  7871         return paint(false);
  7873       return assign(width,height,title,normalization,!is_fullscreen,false);
  7876     CImgDisplay& show() {
  7877       if (!is_empty() && is_closed) {
  7878         XLockDisplay(cimg::X11attr().display);
  7879         if (is_fullscreen) _init_fullscreen();
  7880         _map_window();
  7881         is_closed = false;
  7882         XUnlockDisplay(cimg::X11attr().display);
  7883         return paint();
  7885       return *this;
  7888     CImgDisplay& close() {
  7889       if (!is_empty() && !is_closed) {
  7890         XLockDisplay(cimg::X11attr().display);
  7891         if (is_fullscreen) _desinit_fullscreen();
  7892         XUnmapWindow(cimg::X11attr().display,window);
  7893         window_x = window_y = -1;
  7894         is_closed = true;
  7895         XUnlockDisplay(cimg::X11attr().display);
  7897       return *this;
  7900     CImgDisplay& move(const int posx, const int posy) {
  7901       if (is_empty()) return *this;
  7902       show();
  7903       XLockDisplay(cimg::X11attr().display);
  7904       XMoveWindow(cimg::X11attr().display,window,posx,posy);
  7905       window_x = posx; window_y = posy;
  7906       is_moved = false;
  7907       XUnlockDisplay(cimg::X11attr().display);
  7908       return paint();
  7911     CImgDisplay& show_mouse() {
  7912       if (is_empty()) return *this;
  7913       XLockDisplay(cimg::X11attr().display);
  7914       XDefineCursor(cimg::X11attr().display,window,None);
  7915       XUnlockDisplay(cimg::X11attr().display);
  7916       return *this;
  7919     CImgDisplay& hide_mouse() {
  7920       if (is_empty()) return *this;
  7921       XLockDisplay(cimg::X11attr().display);
  7922       const char pix_data[8] = { 0 };
  7923       XColor col;
  7924       col.red = col.green = col.blue = 0;
  7925       Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
  7926       Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
  7927       XFreePixmap(cimg::X11attr().display,pix);
  7928       XDefineCursor(cimg::X11attr().display,window,cur);
  7929       XUnlockDisplay(cimg::X11attr().display);
  7930       return *this;
  7933     CImgDisplay& set_mouse(const int posx, const int posy) {
  7934       if (is_empty() || is_closed) return *this;
  7935       XLockDisplay(cimg::X11attr().display);
  7936       XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
  7937       mouse_x = posx; mouse_y = posy;
  7938       is_moved = false;
  7939       XSync(cimg::X11attr().display, False);
  7940       XUnlockDisplay(cimg::X11attr().display);
  7941       return *this;
  7944     CImgDisplay& set_title(const char *format, ...) {
  7945       if (is_empty()) return *this;
  7946       char tmp[1024] = {0};
  7947       va_list ap;
  7948       va_start(ap, format);
  7949       cimg_std::vsprintf(tmp,format,ap);
  7950       va_end(ap);
  7951       if (title) delete[] title;
  7952       const int s = cimg::strlen(tmp)+1;
  7953       title = new char[s];
  7954       cimg_std::memcpy(title,tmp,s*sizeof(char));
  7955       XLockDisplay(cimg::X11attr().display);
  7956       XStoreName(cimg::X11attr().display,window,tmp);
  7957       XUnlockDisplay(cimg::X11attr().display);
  7958       return *this;
  7961     template<typename T>
  7962     CImgDisplay& display(const CImg<T>& img) {
  7963       if (img.is_empty())
  7964         throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
  7965       if (is_empty()) assign(img.width,img.height);
  7966       return render(img).paint(false);
  7969     CImgDisplay& paint(const bool wait_expose=true) {
  7970       if (is_empty()) return *this;
  7971       XLockDisplay(cimg::X11attr().display);
  7972       _paint(wait_expose);
  7973       XUnlockDisplay(cimg::X11attr().display);
  7974       return *this;
  7977     template<typename T>
  7978     CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
  7979       if (is_empty()) return *this;
  7980       if (!img)
  7981         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  7982                                     img.width,img.height,img.depth,img.dim,img.data);
  7983       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  7984       if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
  7985       if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
  7987       const T
  7988         *data1 = img.data,
  7989         *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
  7990         *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
  7992       if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
  7993       XLockDisplay(cimg::X11attr().display);
  7995       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  7996         min = max = 0;
  7997         switch (cimg::X11attr().nb_bits) {
  7998         case 8 : { // 256 color palette, no normalization
  7999           _set_colormap(colormap,img.dim);
  8000           unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
  8001           unsigned char *ptrd = (unsigned char*)ndata;
  8002           switch (img.dim) {
  8003           case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
  8004             break;
  8005           case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8006               const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
  8007               (*ptrd++) = (R&0xf0) | (G>>4);
  8008             } break;
  8009           default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8010               const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
  8011               (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
  8014           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
  8015         } break;
  8016         case 16 : { // 16 bits colors, no normalization
  8017           unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
  8018           unsigned char *ptrd = (unsigned char*)ndata;
  8019           const unsigned int M = 248;
  8020           switch (img.dim) {
  8021           case 1 :
  8022             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8023               const unsigned char val = (unsigned char)*(data1++), G = val>>2;
  8024               *(ptrd++) = (val&M) | (G>>3);
  8025               *(ptrd++) = (G<<5) | (G>>1);
  8026             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8027               const unsigned char val = (unsigned char)*(data1++), G = val>>2;
  8028               *(ptrd++) = (G<<5) | (G>>1);
  8029               *(ptrd++) = (val&M) | (G>>3);
  8031             break;
  8032           case 2 :
  8033             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8034               const unsigned char G = (unsigned char)*(data2++)>>2;
  8035               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  8036               *(ptrd++) = (G<<5);
  8037             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8038               const unsigned char G = (unsigned char)*(data2++)>>2;
  8039               *(ptrd++) = (G<<5);
  8040               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  8042             break;
  8043           default :
  8044             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8045               const unsigned char G = (unsigned char)*(data2++)>>2;
  8046               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  8047               *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
  8048             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8049               const unsigned char G = (unsigned char)*(data2++)>>2;
  8050               *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
  8051               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  8054           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
  8055         } break;
  8056         default : { // 24 bits colors, no normalization
  8057           unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
  8058           if (sizeof(int)==4) { // 32 bits int uses optimized version
  8059             unsigned int *ptrd = ndata;
  8060             switch (img.dim) {
  8061             case 1 :
  8062               if (cimg::X11attr().byte_order==cimg::endianness())
  8063                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8064                   const unsigned char val = (unsigned char)*(data1++);
  8065                   *(ptrd++) = (val<<16) | (val<<8) | val;
  8067               else
  8068                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8069                   const unsigned char val = (unsigned char)*(data1++)<<8;
  8070                   *(ptrd++) = (val<<16) | (val<<8) | val;
  8072               break;
  8073             case 2 :
  8074               if (cimg::X11attr().byte_order==cimg::endianness())
  8075                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8076                   *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
  8077               else
  8078                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8079                   *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
  8080               break;
  8081             default :
  8082               if (cimg::X11attr().byte_order==cimg::endianness())
  8083                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8084                   *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  8085               else
  8086                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8087                   *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
  8089           } else {
  8090             unsigned char *ptrd = (unsigned char*)ndata;
  8091             switch (img.dim) {
  8092             case 1 :
  8093               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8094                 *(ptrd++) = 0;
  8095                 *(ptrd++) = (unsigned char)*(data1++);
  8096                 *(ptrd++) = 0;
  8097                 *(ptrd++) = 0;
  8098               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8099                 *(ptrd++) = 0;
  8100                 *(ptrd++) = 0;
  8101                 *(ptrd++) = (unsigned char)*(data1++);
  8102                 *(ptrd++) = 0;
  8104               break;
  8105             case 2 :
  8106               if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
  8107               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8108                 *(ptrd++) = 0;
  8109                 *(ptrd++) = (unsigned char)*(data2++);
  8110                 *(ptrd++) = (unsigned char)*(data1++);
  8111                 *(ptrd++) = 0;
  8113               break;
  8114             default :
  8115               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8116                 *(ptrd++) = 0;
  8117                 *(ptrd++) = (unsigned char)*(data1++);
  8118                 *(ptrd++) = (unsigned char)*(data2++);
  8119                 *(ptrd++) = (unsigned char)*(data3++);
  8120               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8121                 *(ptrd++) = (unsigned char)*(data3++);
  8122                 *(ptrd++) = (unsigned char)*(data2++);
  8123                 *(ptrd++) = (unsigned char)*(data1++);
  8124                 *(ptrd++) = 0;
  8128           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
  8130         };
  8131       } else {
  8132         if (normalization==3) {
  8133           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  8134           else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
  8135         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  8136         const float delta = max-min, mm = delta?delta:1.0f;
  8137         switch (cimg::X11attr().nb_bits) {
  8138         case 8 : { // 256 color palette, with normalization
  8139           _set_colormap(colormap,img.dim);
  8140           unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
  8141           unsigned char *ptrd = (unsigned char*)ndata;
  8142           switch (img.dim) {
  8143           case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8144             const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
  8145             *(ptrd++) = R;
  8146           } break;
  8147           case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8148             const unsigned char
  8149               R = (unsigned char)(255*(*(data1++)-min)/mm),
  8150               G = (unsigned char)(255*(*(data2++)-min)/mm);
  8151             (*ptrd++) = (R&0xf0) | (G>>4);
  8152           } break;
  8153           default :
  8154             for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8155               const unsigned char
  8156                 R = (unsigned char)(255*(*(data1++)-min)/mm),
  8157                 G = (unsigned char)(255*(*(data2++)-min)/mm),
  8158                 B = (unsigned char)(255*(*(data3++)-min)/mm);
  8159               *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
  8162           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
  8163         } break;
  8164         case 16 : { // 16 bits colors, with normalization
  8165           unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
  8166           unsigned char *ptrd = (unsigned char*)ndata;
  8167           const unsigned int M = 248;
  8168           switch (img.dim) {
  8169           case 1 :
  8170             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8171               const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
  8172               *(ptrd++) = (val&M) | (G>>3);
  8173               *(ptrd++) = (G<<5) | (val>>3);
  8174             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8175               const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
  8176               *(ptrd++) = (G<<5) | (val>>3);
  8177               *(ptrd++) = (val&M) | (G>>3);
  8179             break;
  8180           case 2 :
  8181             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8182               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  8183               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  8184               *(ptrd++) = (G<<5);
  8185             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8186               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  8187               *(ptrd++) = (G<<5);
  8188               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  8190             break;
  8191           default :
  8192             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8193               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  8194               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  8195               *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
  8196             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8197               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  8198               *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
  8199               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  8202           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
  8203         } break;
  8204         default : { // 24 bits colors, with normalization
  8205           unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
  8206           if (sizeof(int)==4) { // 32 bits int uses optimized version
  8207             unsigned int *ptrd = ndata;
  8208             switch (img.dim) {
  8209             case 1 :
  8210               if (cimg::X11attr().byte_order==cimg::endianness())
  8211                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8212                   const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  8213                   *(ptrd++) = (val<<16) | (val<<8) | val;
  8215               else
  8216                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8217                   const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  8218                   *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
  8220               break;
  8221             case 2 :
  8222               if (cimg::X11attr().byte_order==cimg::endianness())
  8223                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8224                   *(ptrd++) =
  8225                     ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
  8226                     ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
  8227               else
  8228                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8229                   *(ptrd++) =
  8230                     ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
  8231                     ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
  8232               break;
  8233             default :
  8234               if (cimg::X11attr().byte_order==cimg::endianness())
  8235                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8236                   *(ptrd++) =
  8237                     ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
  8238                     ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
  8239                     (unsigned char)(255*(*(data3++)-min)/mm);
  8240               else
  8241                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8242                   *(ptrd++) =
  8243                     ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
  8244                     ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
  8245                     ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
  8247           } else {
  8248             unsigned char *ptrd = (unsigned char*)ndata;
  8249             switch (img.dim) {
  8250             case 1 :
  8251               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8252                 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  8253                 (*ptrd++) = 0;
  8254                 (*ptrd++) = val;
  8255                 (*ptrd++) = val;
  8256                 (*ptrd++) = val;
  8257               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8258                 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  8259                 (*ptrd++) = val;
  8260                 (*ptrd++) = val;
  8261                 (*ptrd++) = val;
  8262                 (*ptrd++) = 0;
  8264               break;
  8265             case 2 :
  8266               if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
  8267               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8268                 (*ptrd++) = 0;
  8269                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  8270                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  8271                 (*ptrd++) = 0;
  8273               break;
  8274             default :
  8275               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8276                 (*ptrd++) = 0;
  8277                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  8278                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  8279                 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
  8280               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8281                 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
  8282                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  8283                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  8284                 (*ptrd++) = 0;
  8288           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
  8292       XUnlockDisplay(cimg::X11attr().display);
  8293       return *this;
  8296     template<typename T>
  8297     const CImgDisplay& snapshot(CImg<T>& img) const {
  8298       if (is_empty()) img.assign();
  8299       else {
  8300         img.assign(width,height,1,3);
  8302           *data1 = img.ptr(0,0,0,0),
  8303           *data2 = img.ptr(0,0,0,1),
  8304           *data3 = img.ptr(0,0,0,2);
  8305         if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
  8306         switch (cimg::X11attr().nb_bits) {
  8307         case 8 : {
  8308           unsigned char *ptrs = (unsigned char*)data;
  8309           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8310             const unsigned char val = *(ptrs++);
  8311             *(data1++) = val&0xe0;
  8312             *(data2++) = (val&0x1c)<<3;
  8313             *(data3++) = val<<6;
  8315         } break;
  8316         case 16 : {
  8317           unsigned char *ptrs = (unsigned char*)data;
  8318           if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8319             const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
  8320             *(data1++) = val0&0xf8;
  8321             *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
  8322             *(data3++) = val1<<3;
  8323           } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8324             const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
  8325             *(data1++) = val1&0xf8;
  8326             *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
  8327             *(data3++) = val0<<3;
  8329         } break;
  8330         default : {
  8331           unsigned char *ptrs = (unsigned char*)data;
  8332           if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8333             ++ptrs;
  8334             *(data1++) = *(ptrs++);
  8335             *(data2++) = *(ptrs++);
  8336             *(data3++) = *(ptrs++);
  8337           } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8338             *(data3++) = *(ptrs++);
  8339             *(data2++) = *(ptrs++);
  8340             *(data1++) = *(ptrs++);
  8341             ++ptrs;
  8346       return *this;
  8349     // Windows-based display
  8350     //-----------------------
  8351 #elif cimg_display==2
  8352     CLIENTCREATESTRUCT ccs;
  8353     BITMAPINFO bmi;
  8354     unsigned int *data;
  8355     DEVMODE curr_mode;
  8356     HWND window;
  8357     HWND background_window;
  8358     HDC hdc;
  8359     HANDLE thread;
  8360     HANDLE created;
  8361     HANDLE mutex;
  8362     bool mouse_tracking;
  8363     bool visible_cursor;
  8365     static int screen_dimx() {
  8366       DEVMODE mode;
  8367       mode.dmSize = sizeof(DEVMODE);
  8368       mode.dmDriverExtra = 0;
  8369       EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
  8370       return mode.dmPelsWidth;
  8373     static int screen_dimy() {
  8374       DEVMODE mode;
  8375       mode.dmSize = sizeof(DEVMODE);
  8376       mode.dmDriverExtra = 0;
  8377       EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
  8378       return mode.dmPelsHeight;
  8381     static void wait_all() {
  8382       WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
  8385     static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
  8386 #ifdef _WIN64
  8387       CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
  8388 #else
  8389       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
  8390 #endif
  8391       MSG st_msg;
  8393       switch (msg) {
  8394       case WM_CLOSE :
  8395         disp->mouse_x = disp->mouse_y = -1;
  8396         disp->window_x = disp->window_y = 0;
  8397         if (disp->button) {
  8398           cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8399           disp->button = 0;
  8401         if (disp->key) {
  8402           cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  8403           disp->key = 0;
  8405         if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  8406         disp->is_closed = true;
  8407         ReleaseMutex(disp->mutex);
  8408         ShowWindow(disp->window,SW_HIDE);
  8409         disp->is_event = true;
  8410         SetEvent(cimg::Win32attr().wait_event);
  8411         return 0;
  8412       case WM_SIZE : {
  8413         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
  8414         WaitForSingleObject(disp->mutex,INFINITE);
  8415         const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
  8416         if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
  8417           disp->window_width = nw;
  8418           disp->window_height = nh;
  8419           disp->mouse_x = disp->mouse_y = -1;
  8420           disp->is_resized = disp->is_event = true;
  8421           SetEvent(cimg::Win32attr().wait_event);
  8423         ReleaseMutex(disp->mutex);
  8424       } break;
  8425       case WM_MOVE : {
  8426         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
  8427         WaitForSingleObject(disp->mutex,INFINITE);
  8428         const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
  8429         if (nx!=disp->window_x || ny!=disp->window_y) {
  8430           disp->window_x = nx;
  8431           disp->window_y = ny;
  8432           disp->is_moved = disp->is_event = true;
  8433           SetEvent(cimg::Win32attr().wait_event);
  8435         ReleaseMutex(disp->mutex);
  8436       } break;
  8437       case WM_PAINT :
  8438         disp->paint();
  8439         break;
  8440       case WM_KEYDOWN :
  8441         disp->update_iskey((unsigned int)wParam,true);
  8442         if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  8443         disp->key = (unsigned int)wParam;
  8444         if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  8445         disp->is_event = true;
  8446         SetEvent(cimg::Win32attr().wait_event);
  8447         break;
  8448       case WM_MOUSEMOVE : {
  8449         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
  8450         disp->mouse_x = LOWORD(lParam);
  8451         disp->mouse_y = HIWORD(lParam);
  8452 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
  8453         if (!disp->mouse_tracking) {
  8454           TRACKMOUSEEVENT tme;
  8455           tme.cbSize = sizeof(TRACKMOUSEEVENT);
  8456           tme.dwFlags = TME_LEAVE;
  8457           tme.hwndTrack = disp->window;
  8458           if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
  8460 #endif
  8461         if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
  8462           disp->mouse_x = disp->mouse_y = -1;
  8463         disp->is_event = true;
  8464         SetEvent(cimg::Win32attr().wait_event);
  8465       } break;
  8466       case WM_MOUSELEAVE : {
  8467         disp->mouse_x = disp->mouse_y = -1;
  8468         disp->mouse_tracking = false;
  8469       } break;
  8470       case WM_LBUTTONDOWN :
  8471         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8472         disp->button|=1U;
  8473         disp->is_event = true;
  8474         SetEvent(cimg::Win32attr().wait_event);
  8475         break;
  8476       case WM_RBUTTONDOWN :
  8477         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8478         disp->button|=2U;
  8479         disp->is_event = true;
  8480         SetEvent(cimg::Win32attr().wait_event);
  8481         break;
  8482       case WM_MBUTTONDOWN :
  8483         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8484         disp->button|=4U;
  8485         disp->is_event = true;
  8486         SetEvent(cimg::Win32attr().wait_event);
  8487         break;
  8488       case 0x020A : // WM_MOUSEWHEEL:
  8489         disp->wheel+=(int)((short)HIWORD(wParam))/120;
  8490         disp->is_event = true;
  8491         SetEvent(cimg::Win32attr().wait_event);
  8492       case WM_KEYUP :
  8493         disp->update_iskey((unsigned int)wParam,false);
  8494         if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
  8495         if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
  8496         disp->released_key = (unsigned int)wParam;
  8497         disp->is_event = true;
  8498         SetEvent(cimg::Win32attr().wait_event);
  8499         break;
  8500       case WM_LBUTTONUP :
  8501         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8502         disp->button&=~1U;
  8503         disp->is_event = true;
  8504         SetEvent(cimg::Win32attr().wait_event);
  8505         break;
  8506       case WM_RBUTTONUP :
  8507         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8508         disp->button&=~2U;
  8509         disp->is_event = true;
  8510         SetEvent(cimg::Win32attr().wait_event);
  8511         break;
  8512       case WM_MBUTTONUP :
  8513         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  8514         disp->button&=~4U;
  8515         disp->is_event = true;
  8516         SetEvent(cimg::Win32attr().wait_event);
  8517         break;
  8518       case WM_SETCURSOR :
  8519         if (disp->visible_cursor) ShowCursor(TRUE);
  8520         else ShowCursor(FALSE);
  8521         break;
  8523       return DefWindowProc(window,msg,wParam,lParam);
  8526     static DWORD WINAPI _events_thread(void* arg) {
  8527       CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
  8528       const char *title = (const char*)(((void**)arg)[1]);
  8529       MSG msg;
  8530       delete[] (void**)arg;
  8531       disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  8532       disp->bmi.bmiHeader.biWidth = disp->width;
  8533       disp->bmi.bmiHeader.biHeight = -(int)disp->height;
  8534       disp->bmi.bmiHeader.biPlanes = 1;
  8535       disp->bmi.bmiHeader.biBitCount = 32;
  8536       disp->bmi.bmiHeader.biCompression = BI_RGB;
  8537       disp->bmi.bmiHeader.biSizeImage = 0;
  8538       disp->bmi.bmiHeader.biXPelsPerMeter = 1;
  8539       disp->bmi.bmiHeader.biYPelsPerMeter = 1;
  8540       disp->bmi.bmiHeader.biClrUsed = 0;
  8541       disp->bmi.bmiHeader.biClrImportant = 0;
  8542       disp->data = new unsigned int[disp->width*disp->height];
  8543       if (!disp->is_fullscreen) { // Normal window
  8544         RECT rect;
  8545         rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
  8546         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8547         const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
  8548         disp->window = CreateWindowA("MDICLIENT",title?title:" ",
  8549                                      WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
  8550                                      disp->width + 2*border1, disp->height + border1 + border2,
  8551                                      0,0,0,&(disp->ccs));
  8552         if (!disp->is_closed) {
  8553           GetWindowRect(disp->window,&rect);
  8554           disp->window_x = rect.left + border1;
  8555           disp->window_y = rect.top + border2;
  8556         } else disp->window_x = disp->window_y = 0;
  8557       } else { // Fullscreen window
  8558         const unsigned int sx = screen_dimx(), sy = screen_dimy();
  8559         disp->window = CreateWindowA("MDICLIENT",title?title:" ",
  8560                                      WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
  8561                                      disp->width,disp->height,0,0,0,&(disp->ccs));
  8562         disp->window_x = disp->window_y = 0;
  8564       SetForegroundWindow(disp->window);
  8565       disp->hdc = GetDC(disp->window);
  8566       disp->window_width = disp->width;
  8567       disp->window_height = disp->height;
  8568       disp->flush();
  8569 #ifdef _WIN64
  8570       SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
  8571       SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
  8572 #else
  8573       SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
  8574       SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
  8575 #endif
  8576       SetEvent(disp->created);
  8577       while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
  8578       return 0;
  8581     CImgDisplay& _update_window_pos() {
  8582       if (!is_closed) {
  8583         RECT rect;
  8584         rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
  8585         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8586         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
  8587         GetWindowRect(window,&rect);
  8588         window_x = rect.left + border1;
  8589         window_y = rect.top + border2;
  8590       } else window_x = window_y = -1;
  8591       return *this;
  8594     void _init_fullscreen() {
  8595       background_window = 0;
  8596       if (is_fullscreen && !is_closed) {
  8597         DEVMODE mode;
  8598         unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
  8599         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
  8600           const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
  8601           if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
  8602             bestbpp = mode.dmBitsPerPel;
  8603             ibest = imode;
  8604             bw = nw; bh = nh;
  8607         if (bestbpp) {
  8608           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
  8609           EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
  8610           EnumDisplaySettings(0,ibest,&mode);
  8611           ChangeDisplaySettings(&mode,0);
  8612         } else curr_mode.dmSize = 0;
  8614         const unsigned int sx = screen_dimx(), sy = screen_dimy();
  8615         if (sx!=width || sy!=height) {
  8616           CLIENTCREATESTRUCT background_ccs;
  8617           background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
  8618           SetForegroundWindow(background_window);
  8620       } else curr_mode.dmSize = 0;
  8623     void _desinit_fullscreen() {
  8624       if (is_fullscreen) {
  8625         if (background_window) DestroyWindow(background_window);
  8626         background_window = 0;
  8627         if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
  8628         is_fullscreen = false;
  8632     CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  8633                          const unsigned int normalization_type=3,
  8634                          const bool fullscreen_flag=false, const bool closed_flag=false) {
  8636       // Allocate space for window title
  8637       const int s = cimg::strlen(ptitle)+1;
  8638       char *tmp_title = s?new char[s]:0;
  8639       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  8641       // Destroy previous window if existing
  8642       if (!is_empty()) assign();
  8644       // Set display variables
  8645       width = cimg::min(dimw,(unsigned int)screen_dimx());
  8646       height = cimg::min(dimh,(unsigned int)screen_dimy());
  8647       normalization = normalization_type<4?normalization_type:3;
  8648       is_fullscreen = fullscreen_flag;
  8649       window_x = window_y = 0;
  8650       is_closed = closed_flag;
  8651       visible_cursor = true;
  8652       mouse_tracking = false;
  8653       title = tmp_title;
  8654       flush();
  8655       if (is_fullscreen) _init_fullscreen();
  8657       // Create event thread
  8658       void *arg = (void*)(new void*[2]);
  8659       ((void**)arg)[0]=(void*)this;
  8660       ((void**)arg)[1]=(void*)title;
  8661       unsigned long ThreadID = 0;
  8662       mutex = CreateMutex(0,FALSE,0);
  8663       created = CreateEvent(0,FALSE,FALSE,0);
  8664       thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
  8665       WaitForSingleObject(created,INFINITE);
  8666       return *this;
  8669     CImgDisplay& assign() {
  8670       if (is_empty()) return *this;
  8671       DestroyWindow(window);
  8672       TerminateThread(thread,0);
  8673       if (data) delete[] data;
  8674       if (title) delete[] title;
  8675       if (is_fullscreen) _desinit_fullscreen();
  8676       width = height = normalization = window_width = window_height = 0;
  8677       window_x = window_y = 0;
  8678       is_fullscreen = false;
  8679       is_closed = true;
  8680       min = max = 0;
  8681       title = 0;
  8682       flush();
  8683       return *this;
  8686     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  8687                         const unsigned int normalization_type=3,
  8688                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  8689       if (!dimw || !dimh) return assign();
  8690       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  8691       min = max = 0;
  8692       cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
  8693       return paint();
  8696     template<typename T>
  8697     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  8698                         const unsigned int normalization_type=3,
  8699                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  8700       if (!img) return assign();
  8701       CImg<T> tmp;
  8702       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  8703       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  8704       if (normalization==2) min = (float)nimg.minmax(max);
  8705       return display(nimg);
  8708     template<typename T>
  8709     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  8710                         const unsigned int normalization_type=3,
  8711                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  8712       if (!list) return assign();
  8713       CImg<T> tmp;
  8714       const CImg<T> img = list.get_append('x','p'),
  8715         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  8716       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  8717       if (normalization==2) min = (float)nimg.minmax(max);
  8718       return display(nimg);
  8721     CImgDisplay& assign(const CImgDisplay& win) {
  8722       if (!win) return assign();
  8723       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  8724       cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
  8725       return paint();
  8728     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  8729       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  8730       if (is_empty()) return assign(nwidth,nheight);
  8731       const unsigned int
  8732         tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
  8733         tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
  8734         dimx = tmpdimx?tmpdimx:1,
  8735         dimy = tmpdimy?tmpdimy:1;
  8736       if (window_width!=dimx || window_height!=dimy) {
  8737         RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
  8738         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8739         const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
  8740         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
  8742       if (width!=dimx || height!=dimy) {
  8743         unsigned int *ndata = new unsigned int[dimx*dimy];
  8744         if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
  8745         else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
  8746         delete[] data;
  8747         data = ndata;
  8748         bmi.bmiHeader.biWidth = dimx;
  8749         bmi.bmiHeader.biHeight = -(int)dimy;
  8750         width = dimx;
  8751         height = dimy;
  8753       window_width = dimx; window_height = dimy;
  8754       is_resized = false;
  8755       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  8756       if (redraw) return paint();
  8757       return *this;
  8760     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  8761       if (is_empty()) return *this;
  8762       if (redraw) {
  8763         const unsigned int bufsize = width*height*4;
  8764         void *odata = cimg_std::malloc(bufsize);
  8765         cimg_std::memcpy(odata,data,bufsize);
  8766         assign(width,height,title,normalization,!is_fullscreen,false);
  8767         cimg_std::memcpy(data,odata,bufsize);
  8768         cimg_std::free(odata);
  8769         return paint();
  8771       return assign(width,height,title,normalization,!is_fullscreen,false);
  8774     CImgDisplay& show() {
  8775       if (is_empty()) return *this;
  8776       if (is_closed) {
  8777         is_closed = false;
  8778         if (is_fullscreen) _init_fullscreen();
  8779         ShowWindow(window,SW_SHOW);
  8780         _update_window_pos();
  8782       return paint();
  8785     CImgDisplay& close() {
  8786       if (is_empty()) return *this;
  8787       if (!is_closed && !is_fullscreen) {
  8788         if (is_fullscreen) _desinit_fullscreen();
  8789         ShowWindow(window,SW_HIDE);
  8790         is_closed = true;
  8791         window_x = window_y = 0;
  8793       return *this;
  8796     CImgDisplay& move(const int posx, const int posy) {
  8797       if (is_empty()) return *this;
  8798       if (!is_fullscreen) {
  8799         RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
  8800         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8801         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
  8802         SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
  8803       } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
  8804       window_x = posx;
  8805       window_y = posy;
  8806       is_moved = false;
  8807       return show();
  8810     CImgDisplay& show_mouse() {
  8811       if (is_empty()) return *this;
  8812       visible_cursor = true;
  8813       ShowCursor(TRUE);
  8814       SendMessage(window,WM_SETCURSOR,0,0);
  8815       return *this;
  8818     CImgDisplay& hide_mouse() {
  8819       if (is_empty()) return *this;
  8820       visible_cursor = false;
  8821       ShowCursor(FALSE);
  8822       SendMessage(window,WM_SETCURSOR,0,0);
  8823       return *this;
  8826     CImgDisplay& set_mouse(const int posx, const int posy) {
  8827       if (!is_closed && posx>=0 && posy>=0) {
  8828         _update_window_pos();
  8829         const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
  8830         if (res) { mouse_x = posx; mouse_y = posy; }
  8832       return *this;
  8835     CImgDisplay& set_title(const char *format, ...) {
  8836       if (is_empty()) return *this;
  8837       char tmp[1024] = {0};
  8838       va_list ap;
  8839       va_start(ap, format);
  8840       cimg_std::vsprintf(tmp,format,ap);
  8841       va_end(ap);
  8842       if (title) delete[] title;
  8843       const int s = cimg::strlen(tmp)+1;
  8844       title = new char[s];
  8845       cimg_std::memcpy(title,tmp,s*sizeof(char));
  8846       SetWindowTextA(window, tmp);
  8847       return *this;
  8850     template<typename T>
  8851     CImgDisplay& display(const CImg<T>& img) {
  8852       if (img.is_empty())
  8853         throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
  8854       if (is_empty()) assign(img.width,img.height);
  8855       return render(img).paint();
  8858     CImgDisplay& paint() {
  8859       if (!is_closed) {
  8860         WaitForSingleObject(mutex,INFINITE);
  8861         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
  8862         ReleaseMutex(mutex);
  8864       return *this;
  8867     template<typename T>
  8868     CImgDisplay& render(const CImg<T>& img) {
  8869       if (is_empty()) return *this;
  8870       if (!img)
  8871         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  8872                                     img.width,img.height,img.depth,img.dim,img.data);
  8873       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  8875       const T
  8876         *data1 = img.data,
  8877         *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
  8878         *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
  8880       WaitForSingleObject(mutex,INFINITE);
  8881       unsigned int
  8882         *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
  8883         *ptrd = ndata;
  8885       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  8886         min = max = 0;
  8887         switch (img.dim) {
  8888         case 1 : {
  8889           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8890             const unsigned char val = (unsigned char)*(data1++);
  8891             *(ptrd++) = (val<<16) | (val<<8) | val;
  8892           }} break;
  8893         case 2 : {
  8894           for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8895             *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
  8896         } break;
  8897         default : {
  8898           for (unsigned int xy = img.width*img.height; xy>0; --xy)
  8899             *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  8902       } else {
  8903         if (normalization==3) {
  8904           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  8905           else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
  8906         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  8907         const float delta = max-min, mm = delta?delta:1.0f;
  8908         switch (img.dim) {
  8909         case 1 : {
  8910           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8911             const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  8912             *(ptrd++) = (val<<16) | (val<<8) | val;
  8913           }} break;
  8914         case 2 : {
  8915           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8916             const unsigned char
  8917               R = (unsigned char)(255*(*(data1++)-min)/mm),
  8918               G = (unsigned char)(255*(*(data2++)-min)/mm);
  8919             *(ptrd++) = (R<<16) | (G<<8);
  8920           }} break;
  8921         default : {
  8922           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8923             const unsigned char
  8924               R = (unsigned char)(255*(*(data1++)-min)/mm),
  8925               G = (unsigned char)(255*(*(data2++)-min)/mm),
  8926               B = (unsigned char)(255*(*(data3++)-min)/mm);
  8927             *(ptrd++) = (R<<16) | (G<<8) | B;
  8928           }}
  8931       if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
  8932       ReleaseMutex(mutex);
  8933       return *this;
  8936     template<typename T>
  8937     const CImgDisplay& snapshot(CImg<T>& img) const {
  8938       if (is_empty()) img.assign();
  8939       else {
  8940         img.assign(width,height,1,3);
  8942           *data1 = img.ptr(0,0,0,0),
  8943           *data2 = img.ptr(0,0,0,1),
  8944           *data3 = img.ptr(0,0,0,2);
  8945         unsigned int *ptrs = data;
  8946          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  8947           const unsigned int val = *(ptrs++);
  8948           *(data1++) = (unsigned char)(val>>16);
  8949           *(data2++) = (unsigned char)((val>>8)&0xFF);
  8950           *(data3++) = (unsigned char)(val&0xFF);
  8953       return *this;
  8956     // MacOSX - Carbon-based display
  8957     //-------------------------------
  8958     // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
  8959     //
  8960 #elif cimg_display==3
  8961     unsigned int *data;                     // The bits of the picture
  8962     WindowRef carbonWindow;                 // The opaque carbon window struct associated with the display
  8963     MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
  8964     CGColorSpaceRef csr;                    // Needed for painting
  8965     CGDataProviderRef dataProvider;         // Needed for painting
  8966     CGImageRef imageRef;                    // The image
  8967     UInt32 lastKeyModifiers;                // Buffer storing modifiers state
  8969     // Define the kind of the queries which can be serialized using the event thread.
  8970     typedef enum {
  8971       COM_CREATEWINDOW = 0, // Create window query
  8972       COM_RELEASEWINDOW,    // Release window query
  8973       COM_SHOWWINDOW,       // Show window query
  8974       COM_HIDEWINDOW,       // Hide window query
  8975       COM_SHOWMOUSE,        // Show mouse query
  8976       COM_HIDEMOUSE,        // Hide mouse query
  8977       COM_RESIZEWINDOW,     // Resize window query
  8978       COM_MOVEWINDOW,       // Move window query
  8979       COM_SETTITLE,         // Set window title query
  8980       COM_SETMOUSEPOS       // Set cursor position query
  8981     } CImgCarbonQueryKind;
  8983     // The query destructor send to the event thread.
  8984     struct CbSerializedQuery {
  8985       CImgDisplay* sender;         // Query's sender
  8986       CImgCarbonQueryKind kind;    // The kind of the query sent to the background thread
  8987       short x, y;                  // X:Y values for move/resize operations
  8988       char *c;                     // Char values for window title
  8989       bool createFullScreenWindow; // Boolean value used for full-screen window creation
  8990       bool createClosedWindow;     // Boolean value used for closed-window creation
  8991       bool update;                 // Boolean value used for resize
  8992       bool success;                // Succes or failure of the message, used as return value
  8993       CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
  8995       inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
  8996         return CbSerializedQuery(sender, COM_RELEASEWINDOW);
  8998       inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
  8999         CbSerializedQuery q(sender, COM_CREATEWINDOW);
  9000         q.createFullScreenWindow = fullscreen;
  9001         q.createClosedWindow = closed;
  9002         return q;
  9004       inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
  9005         return CbSerializedQuery(sender, COM_SHOWWINDOW);
  9007       inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
  9008         return CbSerializedQuery(sender, COM_HIDEWINDOW);
  9010       inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
  9011         return CbSerializedQuery(sender, COM_SHOWMOUSE);
  9013       inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
  9014         return CbSerializedQuery(sender, COM_HIDEMOUSE);
  9016       inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
  9017         CbSerializedQuery q(sender, COM_RESIZEWINDOW);
  9018         q.x = x, q.y = y;
  9019         q.update = update;
  9020         return q;
  9022       inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
  9023         CbSerializedQuery q(sender, COM_MOVEWINDOW);
  9024         q.x = x, q.y = y;
  9025         return q;
  9027       inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
  9028         CbSerializedQuery q(sender, COM_SETTITLE);
  9029         q.c = c;
  9030         return q;
  9032       inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
  9033         CbSerializedQuery q(sender, COM_SETMOUSEPOS);
  9034         q.x = x, q.y = y;
  9035         return q;
  9037     };
  9039     // Send a serialized query in a synchroneous way.
  9040     // @param c Application Carbon global settings.
  9041     // @param m The query to send.
  9042     // @result Success/failure of the operation returned by the event thread.
  9043     bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
  9044       MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
  9045       MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
  9046       return m.success;
  9049     // Free the window attached to the current display.
  9050     // @param c Application Carbon global settings.
  9051     // @result Success/failure of the operation.
  9052     bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
  9053       if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
  9054         throw CImgDisplayException("Cannot release window associated with the current display.");
  9055       // If a window existed, ask to release it
  9056       MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
  9057       --c.windowCount; //Decrement the window count
  9058       MPExitCriticalRegion(c.windowListCR); // Unlock the list
  9059       return c.windowCount == 0;
  9062     // Create the window attached to the current display.
  9063     // @param c Application Carbon global settings.
  9064     // @param title The window title, if any.
  9065     // @param fullscreen Shoud we start in fullscreen mode ?
  9066     // @param create_closed If true, the window is created but not displayed.
  9067     // @result Success/failure of the operation.
  9068     void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
  9069       if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
  9070         throw CImgDisplayException("Cannot create the window associated with the current display.");
  9071       if (title) set_title(title); // Set the title, if any
  9072       // Now we can register the window
  9073       MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
  9074       ++c.windowCount; //Increment the window count
  9075       MPExitCriticalRegion(c.windowListCR); // Unlock the list
  9078     // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
  9079     void _CbFinalizeGraphics() {
  9080       CGImageRelease (imageRef); // Release the picture
  9081       CGDataProviderRelease(dataProvider); // Release the DP
  9082       CGColorSpaceRelease(csr); // Free the cs
  9085     // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
  9086     void _CbInitializeGraphics() {
  9087       csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
  9088       if (!csr)
  9089         throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
  9090       // Create the DP
  9091       dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
  9092       if (!dataProvider)
  9093         throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
  9094       // ... and finally the image.
  9095       if (cimg::endianness())
  9096         imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
  9097                                  kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
  9098       else
  9099         imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
  9100                                  kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
  9101       if (!imageRef)
  9102         throw CImgDisplayException("CGImageCreate() failed.");
  9105     // Reinit graphic objects. Free them, then reallocate all.
  9106     // This is used when image bounds are changed or when data source get invalid.
  9107     void _CbReinitGraphics() {
  9108       MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
  9109       _CbFinalizeGraphics();
  9110       _CbInitializeGraphics();
  9111       MPExitCriticalRegion(paintCriticalRegion);
  9114     // Convert a point having global coordonates into the window coordonates.
  9115     // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
  9116     // @param mouseEvent The mouse event which triggered the event handler.
  9117     // @param window The window where the event occured.
  9118     // @param point The modified point struct.
  9119     // @result True if the point struct has been converted successfully.
  9120     static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
  9121       Rect bounds;
  9122       if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
  9123         point->x -= bounds.left;
  9124         point->y -= bounds.top;
  9125         HIViewRef view = NULL;
  9126         if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
  9127           return HIViewConvertPoint(point, NULL, view) == noErr;
  9129       return false;
  9132     static int screen_dimx() {
  9133       return CGDisplayPixelsWide(kCGDirectMainDisplay);
  9136     static int screen_dimy() {
  9137       return CGDisplayPixelsHigh(kCGDirectMainDisplay);
  9140     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  9141                         const unsigned int normalization_type=3,
  9142                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  9143       if (!dimw || !dimh) return assign();
  9144       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  9145       min = max = 0;
  9146       cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
  9147       return paint();
  9150     template<typename T>
  9151     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  9152                         const unsigned int normalization_type=3,
  9153                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  9154       if (!img) return assign();
  9155       CImg<T> tmp;
  9156       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  9157       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  9158       if (normalization==2) min = (float)nimg.minmax(max);
  9159       return display(nimg);
  9162     template<typename T>
  9163     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  9164                         const unsigned int normalization_type=3,
  9165                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  9166       if (!list) return assign();
  9167       CImg<T> tmp;
  9168       const CImg<T> img = list.get_append('x','p'),
  9169         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  9170       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  9171       if (normalization==2) min = (float)nimg.minmax(max);
  9172       return display(nimg);
  9175     CImgDisplay& assign(const CImgDisplay &win) {
  9176       if (!win) return assign();
  9177       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  9178       cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
  9179       return paint();
  9182     template<typename T>
  9183     CImgDisplay& display(const CImg<T>& img) {
  9184       if (is_empty()) assign(img.width,img.height);
  9185       return render(img).paint();
  9188     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  9189       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  9190       if (is_empty()) return assign(nwidth,nheight);
  9191       const unsigned int
  9192         tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
  9193         tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
  9194         dimx = tmpdimx?tmpdimx:1,
  9195         dimy = tmpdimy?tmpdimy:1;
  9196       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9198       if ((window_width!=dimx || window_height!=dimy) &&
  9199           !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
  9200         throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
  9202       if (width!=dimx || height!=dimy) {
  9203         unsigned int *ndata = new unsigned int[dimx*dimy];
  9204         if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
  9205         else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
  9206         unsigned int const* old_data = data;
  9207         data = ndata;
  9208         delete[] old_data;
  9209         _CbReinitGraphics();
  9211       window_width = width = dimx; window_height = height = dimy;
  9212       is_resized = false;
  9213       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  9214       if (redraw) return paint();
  9215       return *this;
  9218     CImgDisplay& move(const int posx, const int posy) {
  9219       if (is_empty()) return *this;
  9220       if (!is_fullscreen) {
  9221         // If the operation succeeds, window_x and window_y are updated by the event thread
  9222         cimg::CarbonInfo& c = cimg::CarbonAttr();
  9223         // Send the query
  9224         if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
  9225           throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
  9227       return show();
  9230     CImgDisplay& set_mouse(const int posx, const int posy) {
  9231       if (!is_closed && posx>=0 && posy>=0) {
  9232         // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
  9233         cimg::CarbonInfo& c = cimg::CarbonAttr();
  9234         // Send the query
  9235         if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
  9236           throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
  9238       return *this;
  9241     CImgDisplay& hide_mouse() {
  9242       if (is_empty()) return *this;
  9243       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9244       // Send the query
  9245       if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
  9246         throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
  9247       return *this;
  9250     CImgDisplay& show_mouse() {
  9251       if (is_empty()) return *this;
  9252       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9253       // Send the query
  9254       if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
  9255         throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
  9256       return *this;
  9259     static void wait_all() {
  9260       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9261       MPWaitOnSemaphore(c.wait_event,kDurationForever);
  9264     CImgDisplay& show() {
  9265       if (is_empty()) return *this;
  9266       if (is_closed) {
  9267         cimg::CarbonInfo& c = cimg::CarbonAttr();
  9268         if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
  9269           throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
  9271       return paint();
  9274     CImgDisplay& close() {
  9275       if (is_empty()) return *this;
  9276       if (!is_closed && !is_fullscreen) {
  9277         cimg::CarbonInfo& c = cimg::CarbonAttr();
  9278         // If the operation succeeds, window_x and window_y are updated on the event thread
  9279         if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
  9280           throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
  9282       return *this;
  9285     CImgDisplay& set_title(const char *format, ...) {
  9286       if (is_empty()) return *this;
  9287       char tmp[1024] = {0};
  9288       va_list ap;
  9289       va_start(ap, format);
  9290       cimg_std::vsprintf(tmp,format,ap);
  9291       va_end(ap);
  9292       if (title) delete[] title;
  9293       const int s = cimg::strlen(tmp)+1;
  9294       title = new char[s];
  9295       cimg_std::memcpy(title,tmp,s*sizeof(char));
  9296       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9297       if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
  9298         throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
  9299       return *this;
  9302     CImgDisplay& paint() {
  9303       if (!is_closed) {
  9304         MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
  9305         CGrafPtr portPtr = GetWindowPort(carbonWindow);
  9306         CGContextRef currentContext = 0;
  9307         QDBeginCGContext(portPtr,&currentContext);
  9308         CGContextSetRGBFillColor(currentContext,255,255,255,255);
  9309         CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
  9310         CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
  9311         CGContextFlush(currentContext);
  9312         QDEndCGContext(portPtr, &currentContext);
  9313         MPExitCriticalRegion(paintCriticalRegion);
  9315       return *this;
  9318     template<typename T>
  9319     CImgDisplay& render(const CImg<T>& img) {
  9320       if (is_empty()) return *this;
  9321       if (!img)
  9322         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  9323                                     img.width,img.height,img.depth,img.dim,img.data);
  9324       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  9325       const T
  9326         *data1 = img.data,
  9327         *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
  9328         *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
  9329       MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
  9330       unsigned int
  9331         *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
  9332         *ptrd = ndata;
  9333       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  9334         min = max = 0;
  9335         for (unsigned int xy = img.width*img.height; xy>0; --xy)
  9336           *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  9337       } else {
  9338         if (normalization==3) {
  9339           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  9340           else {
  9341             min = (float)cimg::type<T>::min();
  9342             max = (float)cimg::type<T>::max();
  9344         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  9345         const float delta = max-min, mm = delta?delta:1.0f;
  9346         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  9347           const unsigned char
  9348             R = (unsigned char)(255*(*(data1++)-min)/mm),
  9349             G = (unsigned char)(255*(*(data2++)-min)/mm),
  9350             B = (unsigned char)(255*(*(data3++)-min)/mm);
  9351           *(ptrd++) = (R<<16) | (G<<8) | (B);
  9354       if (ndata!=data) {
  9355         _render_resize(ndata,img.width,img.height,data,width,height);
  9356         delete[] ndata;
  9358       MPExitCriticalRegion(paintCriticalRegion);
  9359       return *this;
  9362     template<typename T>
  9363     const CImgDisplay& snapshot(CImg<T>& img) const {
  9364       if (is_empty()) img.assign();
  9365       else {
  9366         img.assign(width,height,1,3);
  9368           *data1 = img.ptr(0,0,0,0),
  9369           *data2 = img.ptr(0,0,0,1),
  9370           *data3 = img.ptr(0,0,0,2);
  9371         unsigned int *ptrs = data;
  9372         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  9373           const unsigned int val = *(ptrs++);
  9374           *(data1++) = (unsigned char)(val>>16);
  9375           *(data2++) = (unsigned char)((val>>8)&0xFF);
  9376           *(data3++) = (unsigned char)(val&0xFF);
  9379       return *this;
  9382     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  9383       if (is_empty()) return *this;
  9384       if (redraw) {
  9385         const unsigned int bufsize = width*height*4;
  9386         void *odata = cimg_std::malloc(bufsize);
  9387         cimg_std::memcpy(odata,data,bufsize);
  9388         assign(width,height,title,normalization,!is_fullscreen,false);
  9389         cimg_std::memcpy(data,odata,bufsize);
  9390         cimg_std::free(odata);
  9391         return paint();
  9393       return assign(width,height,title,normalization,!is_fullscreen,false);
  9396     static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
  9397       OSStatus result = eventNotHandledErr;
  9398       CImgDisplay* disp = (CImgDisplay*) userData;
  9399       (void)myHandler; // Avoid "unused parameter"
  9400       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9401       // Gets the associated display
  9402       if (disp) {
  9403         // Window events are always handled
  9404         if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
  9405         case kEventWindowClose :
  9406           disp->mouse_x = disp->mouse_y = -1;
  9407           disp->window_x = disp->window_y = 0;
  9408           if (disp->button) {
  9409             cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  9410             disp->button = 0;
  9412           if (disp->key) {
  9413             cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  9414             disp->key = 0;
  9416           if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  9417           disp->is_closed = true;
  9418           HideWindow(disp->carbonWindow);
  9419           disp->is_event = true;
  9420           MPSignalSemaphore(c.wait_event);
  9421           result = noErr;
  9422           break;
  9423           // There is a lot of case where we have to redraw our window
  9424         case kEventWindowBoundsChanging :
  9425         case kEventWindowResizeStarted :
  9426         case kEventWindowCollapsed : //Not sure it's really needed :-)
  9427           break;
  9428         case kEventWindowZoomed :
  9429         case kEventWindowExpanded :
  9430         case kEventWindowResizeCompleted : {
  9431           MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
  9432           // Now we retrieve the new size of the window
  9433           Rect newContentRect;
  9434           GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
  9435           const unsigned int
  9436             nw = (unsigned int)(newContentRect.right - newContentRect.left),
  9437             nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
  9439           // Then we update CImg internal settings
  9440           if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
  9441             disp->window_width = nw;
  9442             disp->window_height = nh;
  9443             disp->mouse_x = disp->mouse_y = -1;
  9444             disp->is_resized = true;
  9446           disp->is_event = true;
  9447           MPExitCriticalRegion(disp->paintCriticalRegion);
  9448           disp->paint(); // Coords changed, must update the screen
  9449           MPSignalSemaphore(c.wait_event);
  9450           result = noErr;
  9451         } break;
  9452         case kEventWindowDragStarted :
  9453         case kEventWindowDragCompleted : {
  9454           MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
  9455           // Now we retrieve the new size of the window
  9456           Rect newContentRect ;
  9457           GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
  9458           const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
  9459           // Then we update CImg internal settings
  9460           if (nx!=disp->window_x || ny!=disp->window_y) {
  9461             disp->window_x = nx;
  9462             disp->window_y = ny;
  9463             disp->is_moved = true;
  9465           disp->is_event = true;
  9466           MPExitCriticalRegion(disp->paintCriticalRegion);
  9467           disp->paint(); // Coords changed, must update the screen
  9468           MPSignalSemaphore(c.wait_event);
  9469           result = noErr;
  9470         } break;
  9471           case kEventWindowPaint :
  9472           disp->paint();
  9473           break;
  9476         switch (GetEventClass(theEvent)) {
  9477         case kEventClassKeyboard : {
  9478           if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
  9479             // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
  9480             UInt32 newModifiers;
  9481             if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
  9482               int newKeyCode = -1;
  9483               UInt32 changed = disp->lastKeyModifiers^newModifiers;
  9484               // Find what changed here
  9485               if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
  9486               if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
  9488               // On the Mac, the "option" key = the ALT key
  9489               if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
  9490               if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
  9491               if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
  9492               if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
  9493               if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
  9494               if (newKeyCode != -1) { // Simulate keystroke
  9495                 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  9496                 disp->key = (int)newKeyCode;
  9498               disp->lastKeyModifiers = newModifiers; // Save current state
  9500             disp->is_event = true;
  9501             MPSignalSemaphore(c.wait_event);
  9503           if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
  9504             char keyCode;
  9505             if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
  9506               disp->update_iskey((unsigned int)keyCode,true);
  9507               if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  9508               disp->key = (unsigned int)keyCode;
  9509               if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  9511             disp->is_event = true;
  9512             MPSignalSemaphore(c.wait_event);
  9514         } break;
  9516         case kEventClassMouse :
  9517           switch (GetEventKind(theEvent)) {
  9518           case kEventMouseDragged :
  9519             //  When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
  9520             //  but a kEventMouseDragged one. So we merge them here.
  9521           case kEventMouseMoved :
  9522             HIPoint point;
  9523             if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
  9524               if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
  9525                 disp->mouse_x = (int)point.x;
  9526                 disp->mouse_y = (int)point.y;
  9527                 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
  9528                   disp->mouse_x = disp->mouse_y = -1;
  9529               } else disp->mouse_x = disp->mouse_y = -1;
  9531             disp->is_event = true;
  9532             MPSignalSemaphore(c.wait_event);
  9533             break;
  9534           case kEventMouseDown :
  9535             UInt16 btn;
  9536             if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
  9537               cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  9538               if (btn==kEventMouseButtonPrimary) disp->button|=1U;
  9539               // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
  9540               // to emulate a right click by using the Control key
  9541               if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
  9542                 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
  9543               if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
  9544               if (btn==kEventMouseButtonTertiary) disp->button|=4U;
  9546             disp->is_event = true;
  9547             MPSignalSemaphore(c.wait_event);
  9548             break;
  9549           case kEventMouseWheelMoved :
  9550             EventMouseWheelAxis wheelax;
  9551             SInt32 delta;
  9552             if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
  9553               if (wheelax==kEventMouseWheelAxisY) {
  9554                 if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
  9555                   if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
  9556                 disp->is_event = true;
  9557                 MPSignalSemaphore(c.wait_event);
  9559             break;
  9563         switch (GetEventClass(theEvent)) {
  9564         case kEventClassKeyboard :
  9565           if (GetEventKind(theEvent)==kEventRawKeyUp) {
  9566             UInt32 keyCode;
  9567             if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
  9568               disp->update_iskey((unsigned int)keyCode,false);
  9569               if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
  9570               if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
  9571               disp->released_key = (int)keyCode;
  9573             disp->is_event = true;
  9574             MPSignalSemaphore(c.wait_event);
  9576           break;
  9578         case kEventClassMouse :
  9579           switch (GetEventKind(theEvent)) {
  9580           case kEventMouseUp :
  9581             UInt16 btn;
  9582             if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
  9583               cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  9584               if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
  9585               // See note in kEventMouseDown handler.
  9586               if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
  9587                 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
  9588               if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
  9589               if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
  9591             disp->is_event = true;
  9592             MPSignalSemaphore(c.wait_event);
  9593             break;
  9597       return (result);
  9600     static void* _events_thread(void* args) {
  9601       (void)args;      // Make the compiler happy
  9602       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9603       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
  9604       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
  9605       MPSignalSemaphore(c.sync_event);  // Notify the caller that all goes fine
  9606       EventRef theEvent;
  9607       EventTargetRef theTarget;
  9608       OSStatus err;
  9609       CbSerializedQuery* query;
  9610       theTarget = GetEventDispatcherTarget();
  9612       // Enter in the main loop
  9613       while (true) {
  9614         pthread_testcancel(); /* Check if cancelation happens */
  9615         err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
  9616         if (err==noErr) { // Received a carbon event, so process it !
  9617           SendEventToEventTarget (theEvent, theTarget);
  9618           ReleaseEvent(theEvent);
  9619         } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
  9620           OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
  9621           if (r!=noErr) continue; //nothing in the queue or an error.., bye
  9622           // If we're here, we've something to do now.
  9623           if (query) {
  9624             switch (query->kind) {
  9625             case COM_SETMOUSEPOS : { // change the cursor position
  9626               query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
  9627                 == kCGErrorSuccess;
  9628               if (query->success) {
  9629                 query->sender->mouse_x = query->x;
  9630                 query->sender->mouse_y = query->y;
  9631               } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
  9632             } break;
  9633             case COM_SETTITLE : { // change the title bar caption
  9634               CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
  9635               query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
  9636               if (!query->success)
  9637                 cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
  9638               CFRelease(windowTitle);
  9639             } break;
  9640             case COM_RESIZEWINDOW : { // Resize a window
  9641               SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
  9642               // If the window has been resized successfully, update display informations
  9643               query->sender->window_width = query->x;
  9644               query->sender->window_height = query->y;
  9645               query->success = true;
  9646             } break;
  9647             case COM_MOVEWINDOW : { // Move a window
  9648               MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
  9649               query->sender->window_x = query->x;
  9650               query->sender->window_y = query->y;
  9651               query->sender->is_moved = false;
  9652               query->success = true;
  9653             } break;
  9654             case COM_SHOWMOUSE : { // Show the mouse
  9655               query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
  9656               if (!query->success)
  9657                 cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
  9658             } break;
  9659             case COM_HIDEMOUSE : { // Hide the mouse
  9660               query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
  9661               if (!query->success)
  9662                 cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
  9663             } break;
  9664             case COM_SHOWWINDOW : { // We've to show a window
  9665               ShowWindow(query->sender->carbonWindow);
  9666               query->success = true;
  9667               query->sender->is_closed = false;
  9668             } break;
  9669             case COM_HIDEWINDOW : { // We've to show a window
  9670               HideWindow(query->sender->carbonWindow);
  9671               query->sender->is_closed = true;
  9672               query->sender->window_x = query->sender->window_y = 0;
  9673               query->success = true;
  9674             } break;
  9675             case COM_RELEASEWINDOW : { // We have to release a given window handle
  9676               query->success = true;
  9677               CFRelease(query->sender->carbonWindow);
  9678             } break;
  9679             case COM_CREATEWINDOW : { // We have to create a window
  9680               query->success = true;
  9681               WindowAttributes  windowAttrs;
  9682               Rect              contentRect;
  9683               if (query->createFullScreenWindow) {
  9684                 // To simulate a "true" full screen, we remove menus and close boxes
  9685                 windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
  9686                 // Define a full screen bound rect
  9687                 SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
  9688               } else { // Set the window size
  9689                 SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
  9690                 // Use default attributes
  9691                 windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
  9693               // Update window position
  9694               if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
  9695               else {
  9696                 query->sender->window_x = contentRect.left;
  9697                 query->sender->window_y = contentRect.top;
  9699               // Update window flags
  9700               query->sender->window_width = query->sender->width;
  9701               query->sender->window_height = query->sender->height;
  9702               query->sender->flush();
  9703               // Create the window
  9704               if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
  9705                 query->success = false;
  9706                 cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
  9708               // Send it to the foreground
  9709               if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
  9710               // Show it, if needed
  9711               if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
  9713               // Associate a valid event handler
  9714               EventTypeSpec eventList[] = {
  9715                 { kEventClassWindow, kEventWindowClose },
  9716                 { kEventClassWindow, kEventWindowResizeStarted },
  9717                 { kEventClassWindow, kEventWindowResizeCompleted },
  9718                 { kEventClassWindow, kEventWindowDragStarted},
  9719                 { kEventClassWindow, kEventWindowDragCompleted },
  9720                 { kEventClassWindow, kEventWindowPaint },
  9721                 { kEventClassWindow, kEventWindowBoundsChanging },
  9722                 { kEventClassWindow, kEventWindowCollapsed },
  9723                 { kEventClassWindow, kEventWindowExpanded },
  9724                 { kEventClassWindow, kEventWindowZoomed },
  9725                 { kEventClassKeyboard, kEventRawKeyDown },
  9726                 { kEventClassKeyboard, kEventRawKeyUp },
  9727                 { kEventClassKeyboard, kEventRawKeyRepeat },
  9728                 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
  9729                 { kEventClassMouse, kEventMouseMoved },
  9730                 { kEventClassMouse, kEventMouseDown },
  9731                 { kEventClassMouse, kEventMouseUp },
  9732                 { kEventClassMouse, kEventMouseDragged }
  9733               };
  9735               // Set up the handler
  9736               if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
  9737                                             eventList,(void*)query->sender,0)!=noErr) {
  9738                 query->success = false;
  9739                 cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
  9742               // Paint
  9743               query->sender->paint();
  9744             } break;
  9745             default :
  9746               cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
  9748             // Signal that the message has been processed
  9749             MPSignalSemaphore(c.sync_event);
  9753       // If we are here, the application is now finished
  9754       pthread_exit(0);
  9757     CImgDisplay& assign() {
  9758       if (is_empty()) return *this;
  9759       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9760       // Destroy the window associated to the display
  9761       _CbFreeAttachedWindow(c);
  9762       // Don't destroy the background thread here.
  9763       // If you check whether _CbFreeAttachedWindow() returned true,
  9764       //   - saying that there were no window left on screen - and
  9765       //   you destroy the background thread here, ReceiveNextEvent won't
  9766       //   work anymore if you create a new window after. So the
  9767       //  background thread must be killed (pthread_cancel() + pthread_join())
  9768       //   only on the application shutdown.
  9770       // Finalize graphics
  9771       _CbFinalizeGraphics();
  9773       // Do some cleanup
  9774       if (data) delete[] data;
  9775       if (title) delete[] title;
  9776       width = height = normalization = window_width = window_height = 0;
  9777       window_x = window_y = 0;
  9778       is_fullscreen = false;
  9779       is_closed = true;
  9780       min = max = 0;
  9781       title = 0;
  9782       flush();
  9783       if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
  9784         throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
  9785       return *this;
  9788     CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  9789                          const unsigned int normalization_type=3,
  9790                          const bool fullscreen_flag=false, const bool closed_flag=false) {
  9791       cimg::CarbonInfo& c = cimg::CarbonAttr();
  9793       // Allocate space for window title
  9794       const int s = cimg::strlen(ptitle)+1;
  9795       char *tmp_title = s?new char[s]:0;
  9796       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  9798       // Destroy previous window if existing
  9799       if (!is_empty()) assign();
  9801       // Set display variables
  9802       width = cimg::min(dimw,(unsigned int)screen_dimx());
  9803       height = cimg::min(dimh,(unsigned int)screen_dimy());
  9804       normalization = normalization_type<4?normalization_type:3;
  9805       is_fullscreen = fullscreen_flag;
  9806       is_closed = closed_flag;
  9807       lastKeyModifiers = 0;
  9808       title = tmp_title;
  9809       flush();
  9811       // Create the paint CR
  9812       if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
  9813         throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
  9815       // Create the thread if it's not already created
  9816       if (c.event_thread==0) {
  9817         // Background thread does not exists, so create it !
  9818         if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
  9819           throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
  9820         // Wait for thread initialization
  9821         MPWaitOnSemaphore(c.sync_event, kDurationForever);
  9824       // Init disp. graphics
  9825       data = new unsigned int[width*height];
  9826       _CbInitializeGraphics();
  9828       // Now ask the thread to create the window
  9829       _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
  9830       return *this;
  9833 #endif
  9835   };
  9837   /*
  9838    #--------------------------------------
  9842    # Definition of the CImg<T> structure
  9846    #--------------------------------------
  9847    */
  9849   //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
  9850   /**
  9851      This is the main class of the %CImg Library. It declares and constructs
  9852      an image, allows access to its pixel values, and is able to perform various image operations.
  9854      \par Image representation
  9856      A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
  9857      each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
  9858      and number of channels.
  9859      Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
  9860      is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
  9861      If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
  9863      Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
  9864      as well as images with less dimensions (1D scalar signal, 2D color images, ...).
  9865      Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
  9867      Concerning the pixel value type \c T :
  9868      fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
  9869      unsigned long, long, float, double, ... </tt>.
  9870      Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
  9871      while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
  9872      images that have floating-point pixel values. The default value for the template T is \c float.
  9873      Using your own template types may be possible. However, you will certainly have to define the complete set
  9874      of arithmetic and logical operators for your class.
  9876      \par Image structure
  9878      The \ref CImg<\c T> structure contains \a six fields :
  9879      - \ref width defines the number of \a columns of the image (size along the X-axis).
  9880      - \ref height defines the number of \a rows of the image (size along the Y-axis).
  9881      - \ref depth defines the number of \a slices of the image (size along the Z-axis).
  9882      - \ref dim defines the number of \a channels of the image (size along the V-axis).
  9883      - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
  9884      - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
  9885        another image.
  9887      You can access these fields publicly although it is recommended to use the dedicated functions
  9888      dimx(), dimy(), dimz(), dimv() and ptr() to do so.
  9889      Image dimensions are not limited to a specific range (as long as you got enough available memory).
  9890      A value of \e 1 usually means that the corresponding dimension is \a flat.
  9891      If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
  9892      Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
  9893      (a CImgInstanceException will be thrown instead).
  9894      Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).
  9896      \par Image declaration and construction
  9898      Declaring an image can be done by using one of the several available constructors.
  9899      Here is a list of the most used :
  9901      - Construct images from arbitrary dimensions :
  9902          - <tt>CImg<char> img;</tt> declares an empty image.
  9903          - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
  9904          \c unsigned \c char pixel values.
  9905          - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
  9906          - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
  9907          (colors are stored as an image with three channels).
  9908          - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
  9909          (with \c double pixel values).
  9910          - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
  9911          (with \c float pixels, which is the default value of the template parameter \c T).
  9912          - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to
  9913          do it, or use the specific constructor taking 5 parameters like this :
  9914          <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.
  9916      - Construct images from filenames :
  9917          - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
  9918          - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
  9919          - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
  9920          to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
  9922      - Construct images from C-style arrays :
  9923          - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
  9924          \c data_buffer (of size 256x256=65536).
  9925          - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
  9926          from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
  9927          - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
  9928          from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).
  9930          The complete list of constructors can be found <a href="#constructors">here</a>.
  9932      \par Most useful functions
  9934      The \ref CImg<\c T> class contains a lot of functions that operates on images.
  9935      Some of the most useful are :
  9937      - operator()(), operator[]() : allows to access or write pixel values.
  9938      - display() : displays the image in a new window.
  9939   **/
  9940   template<typename T>
  9941   struct CImg {
  9943     //! Variable representing the width of the instance image (i.e. dimensions along the X-axis).
  9944     /**
  9945        \remark
  9946        - Prefer using the function CImg<T>::dimx() to get information about the width of an image.
  9947        - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably
  9948        result in a library crash.
  9949        - Empty images have \c width defined to \c 0.
  9950     **/
  9951     unsigned int width;
  9953     //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis).
  9954     /**
  9955        \remark
  9956        - Prefer using the function CImg<T>::dimy() to get information about the height of an image.
  9957        - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably
  9958        result in a library crash.
  9959        - 1D signals have \c height defined to \c 1.
  9960        - Empty images have \c height defined to \c 0.
  9961     **/
  9962     unsigned int height;
  9964     //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
  9965     /**
  9966        \remark
  9967        - Prefer using the function CImg<T>::dimz() to get information about the depth of an image.
  9968        - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably
  9969        result in a library crash.
  9970        - Classical 2D images have \c depth defined to \c 1.
  9971        - Empty images have \c depth defined to \c 0.
  9972     **/
  9973     unsigned int depth;
  9975     //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis).
  9976     /**
  9977        \remark
  9978        - Prefer using the function CImg<T>::dimv() to get information about the depth of an image.
  9979        - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably
  9980        result in a library crash.
  9981        - Scalar-valued images (one value per pixel) have \c dim defined to \c 1.
  9982        - Empty images have \c depth defined to \c 0.
  9983     **/
  9984     unsigned int dim;
  9986     //! Variable telling if pixel buffer of the instance image is shared with another one.
  9987     bool is_shared;
  9989     //! Pointer to the first pixel of the pixel buffer.
  9990     T *data;
  9992     //! Iterator type for CImg<T>.
  9993     /**
  9994        \remark
  9995        - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer).
  9996        - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
  9997     **/
  9998     typedef T* iterator;
 10000     //! Const iterator type for CImg<T>.
 10001     /**
 10002        \remark
 10003        - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer).
 10004        - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
 10005     **/
 10006     typedef const T* const_iterator;
 10008     //! Get value type
 10009     typedef T value_type;
 10011     // Define common T-dependant types.
 10012     typedef typename cimg::superset<T,bool>::type Tbool;
 10013     typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 10014     typedef typename cimg::superset<T,char>::type Tchar;
 10015     typedef typename cimg::superset<T,unsigned short>::type Tushort;
 10016     typedef typename cimg::superset<T,short>::type Tshort;
 10017     typedef typename cimg::superset<T,unsigned int>::type Tuint;
 10018     typedef typename cimg::superset<T,int>::type Tint;
 10019     typedef typename cimg::superset<T,unsigned long>::type Tulong;
 10020     typedef typename cimg::superset<T,long>::type Tlong;
 10021     typedef typename cimg::superset<T,float>::type Tfloat;
 10022     typedef typename cimg::superset<T,double>::type Tdouble;
 10023     typedef typename cimg::last<T,bool>::type boolT;
 10024     typedef typename cimg::last<T,unsigned char>::type ucharT;
 10025     typedef typename cimg::last<T,char>::type charT;
 10026     typedef typename cimg::last<T,unsigned short>::type ushortT;
 10027     typedef typename cimg::last<T,short>::type shortT;
 10028     typedef typename cimg::last<T,unsigned int>::type uintT;
 10029     typedef typename cimg::last<T,int>::type intT;
 10030     typedef typename cimg::last<T,unsigned long>::type ulongT;
 10031     typedef typename cimg::last<T,long>::type longT;
 10032     typedef typename cimg::last<T,float>::type floatT;
 10033     typedef typename cimg::last<T,double>::type doubleT;
 10035     //@}
 10036     //---------------------------
 10037     //
 10038     //! \name Plugins
 10039     //@{
 10040     //---------------------------
 10041 #ifdef cimg_plugin
 10042 #include cimg_plugin
 10043 #endif
 10044 #ifdef cimg_plugin1
 10045 #include cimg_plugin1
 10046 #endif
 10047 #ifdef cimg_plugin2
 10048 #include cimg_plugin2
 10049 #endif
 10050 #ifdef cimg_plugin3
 10051 #include cimg_plugin3
 10052 #endif
 10053 #ifdef cimg_plugin4
 10054 #include cimg_plugin4
 10055 #endif
 10056 #ifdef cimg_plugin5
 10057 #include cimg_plugin5
 10058 #endif
 10059 #ifdef cimg_plugin6
 10060 #include cimg_plugin6
 10061 #endif
 10062 #ifdef cimg_plugin7
 10063 #include cimg_plugin7
 10064 #endif
 10065 #ifdef cimg_plugin8
 10066 #include cimg_plugin8
 10067 #endif
 10068 #ifndef cimg_plugin_greycstoration
 10069 #define cimg_plugin_greycstoration_count
 10070 #endif
 10071 #ifndef cimg_plugin_greycstoration_lock
 10072 #define cimg_plugin_greycstoration_lock
 10073 #endif
 10074 #ifndef cimg_plugin_greycstoration_unlock
 10075 #define cimg_plugin_greycstoration_unlock
 10076 #endif
 10078     //@}
 10080     //--------------------------------------
 10081     //
 10082     //! \name Constructors-Destructor-Copy
 10083     //@{
 10084     //--------------------------------------
 10086     //! Destructor.
 10087     /**
 10088        The destructor destroys the instance image.
 10089        \remark
 10090        - Destructing an empty or shared image does nothing.
 10091        - Otherwise, all memory used to store the pixel data of the instance image is freed.
 10092        - When destroying a non-shared image, be sure that every shared instances of the same image are
 10093        also destroyed to avoid further access to desallocated memory buffers.
 10094     **/
 10095     ~CImg() {
 10096       if (data && !is_shared) delete[] data;
 10099     //! Default constructor.
 10100     /**
 10101        The default constructor creates an empty instance image.
 10102        \remark
 10103        - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
 10104        set to 0 as well as its pointer to the pixel buffer \ref data.
 10105        - An empty image is non-shared.
 10106     **/
 10107     CImg():
 10108       width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
 10110     //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
 10111     /**
 10112        This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
 10113        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 10114        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 10115        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 10116        \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
 10117        \remark
 10118        - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
 10119        and all has its dimensions set to 0. No memory for pixel data is then allocated.
 10120        - This constructor creates only non-shared images.
 10121        - Image pixels allocated by this constructor are \b not \b initialized.
 10122        Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
 10123        to get an image of desired size with pixels set to a particular value.
 10124     **/
 10125     explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
 10126       is_shared(false) {
 10127       const unsigned long siz = dx*dy*dz*dv;
 10128       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
 10129       else { width = height = depth = dim = 0; data = 0; }
 10132     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
 10133     /**
 10134        This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T and sets all pixel
 10135        values of the created instance image to \p val.
 10136        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 10137        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 10138        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 10139        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 10140        \param val Default value for image pixels.
 10141        \remark
 10142        - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
 10143     **/
 10144     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
 10145       is_shared(false) {
 10146       const unsigned long siz = dx*dy*dz*dv;
 10147       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
 10148       else { width = height = depth = dim = 0; data = 0; }
 10151     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
 10152     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 10153          const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10154 #define _CImg_stdarg(img,a0,a1,N,t) { \
 10155         unsigned int _siz = (unsigned int)N; \
 10156         if (_siz--) { \
 10157           va_list ap; \
 10158           va_start(ap,a1); \
 10159           T *ptrd = (img).data; \
 10160           *(ptrd++) = (T)a0; \
 10161           if (_siz--) { \
 10162             *(ptrd++) = (T)a1; \
 10163             for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
 10164           } \
 10165           va_end(ap); \
 10166         }}
 10167       assign(dx,dy,dz,dv);
 10168       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 10171     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
 10172     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 10173          const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10174       assign(dx,dy,dz,dv);
 10175       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 10178     //! Construct an image with given size and with specified values given in a string.
 10179     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 10180          const char *const values, const bool repeat_pattern):is_shared(false) {
 10181       const unsigned long siz = dx*dy*dz*dv;
 10182       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
 10183       else { width = height = depth = dim = 0; data = 0; }
 10186     //! Construct an image from a raw memory buffer.
 10187     /**
 10188        This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
 10189        copying data values from the input raw pixel buffer \p data_buffer.
 10190     **/
 10191     template<typename t>
 10192     CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 10193          const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
 10194       if (shared)
 10195         throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
 10196                                     "(different pixel types).",
 10197                                     pixel_type(),CImg<t>::pixel_type());
 10198       const unsigned long siz = dx*dy*dz*dv;
 10199       if (data_buffer && siz) {
 10200         width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
 10201         const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 10202       } else { width = height = depth = dim = 0; data = 0; }
 10205 #ifndef cimg_use_visualcpp6
 10206     CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 10207          const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
 10208 #else
 10209     CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 10210          const unsigned int dz, const unsigned int dv, const bool shared)
 10211 #endif
 10213       const unsigned long siz = dx*dy*dz*dv;
 10214       if (data_buffer && siz) {
 10215         width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
 10216         if (is_shared) data = const_cast<T*>(data_buffer);
 10217         else { data = new T[siz]; cimg_std::memcpy(data,data_buffer,siz*sizeof(T)); }
 10218       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 10221    //! Default copy constructor.
 10222     /**
 10223        The default copy constructor creates a new instance image having same dimensions
 10224        (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
 10225        \param img The input image to copy.
 10226        \remark
 10227        - If the input image \p img is non-shared or have a different template type \p t != \p T,
 10228        the default copy constructor allocates a new pixel buffer and copy the pixel data
 10229        of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different
 10230        and the resulting instance image is non-shared.
 10231        - If the input image \p img is shared and has the same template type \p t == \p T,
 10232        the default copy constructor does not allocate a new pixel buffer and the resulting instance image
 10233        shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies
 10234        the created instance image.
 10235        - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
 10236        type \p t to type \p T.
 10237        - Copying an image having the same template type \p t == \p T is significantly faster.
 10238     **/
 10239     template<typename t>
 10240     CImg(const CImg<t>& img):is_shared(false) {
 10241       const unsigned int siz = img.size();
 10242       if (img.data && siz) {
 10243         width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
 10244         const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 10245       } else { width = height = depth = dim = 0; data = 0; }
 10248     CImg(const CImg<T>& img) {
 10249       const unsigned int siz = img.size();
 10250       if (img.data && siz) {
 10251         width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
 10252         if (is_shared) data = const_cast<T*>(img.data);
 10253         else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
 10254       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 10257    //! Advanced copy constructor.
 10258     /**
 10259        The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
 10260        \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
 10261        But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter
 10262        \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false).
 10263        \param img The input image to copy.
 10264        \param shared Boolean flag that decides if the copy is shared on non-shared.
 10265        \remark
 10266        - It is not possible to create a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
 10267        - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
 10268        - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
 10269        image is the same as the one used by the input image \p img.
 10270     **/
 10271     template<typename t>
 10272     CImg(const CImg<t>& img, const bool shared):is_shared(false) {
 10273       if (shared)
 10274         throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
 10275                                     "(different pixel types).",
 10276                                     pixel_type(),CImg<t>::pixel_type());
 10277       const unsigned int siz = img.size();
 10278       if (img.data && siz) {
 10279         width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
 10280         const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 10281       } else { width = height = depth = dim = 0; data = 0; }
 10284     CImg(const CImg<T>& img, const bool shared) {
 10285       const unsigned int siz = img.size();
 10286       if (img.data && siz) {
 10287         width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
 10288         if (is_shared) data = const_cast<T*>(img.data);
 10289         else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
 10290       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 10293     //! Construct an image using dimensions of another image
 10294     template<typename t>
 10295     CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10296       assign(img,dimensions);
 10299     //! Construct an image using dimensions of another image, and fill it with a default value
 10300     template<typename t>
 10301     CImg(const CImg<t>& img, const char *const dimensions, const T val):
 10302       width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10303       assign(img,dimensions).fill(val);
 10306    //! Construct an image from an image file.
 10307     /**
 10308        This constructor creates an instance image by reading it from a file.
 10309        \param filename Filename of the image file.
 10310        \remark
 10311        - The image format is deduced from the filename only by looking for the filename extension i.e. without
 10312        analyzing the file itself.
 10313        - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
 10314        More informations on this topic can be found in cimg_files_io.
 10315        - If the filename is not found, a CImgIOException is thrown by this constructor.
 10316     **/
 10317     CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10318       assign(filename);
 10321     //! Construct an image from the content of a CImgDisplay instance.
 10322     CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 10323       disp.snapshot(*this);
 10326     //! In-place version of the default constructor/destructor.
 10327     /**
 10328        This function replaces the instance image by an empty image.
 10329        \remark
 10330        - Memory used by the previous content of the instance image is freed if necessary.
 10331        - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
 10332        - This function is useful to free memory used by an image that is not of use, but which
 10333        has been created in the current code scope (i.e. not destroyed yet).
 10334     **/
 10335     CImg<T>& assign() {
 10336       if (data && !is_shared) delete[] data;
 10337       width = height = depth = dim = 0; is_shared = false; data = 0;
 10338       return *this;
 10341     //! In-place version of the default constructor.
 10342     /**
 10343        This function is strictly equivalent to \ref assign() and has been
 10344        introduced for having a STL-compliant function name.
 10345     **/
 10346     CImg<T>& clear() {
 10347       return assign();
 10350     //! In-place version of the previous constructor.
 10351     /**
 10352        This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
 10353        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 10354        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 10355        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 10356        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 10357        - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty
 10358        and all has its dimensions set to 0. No memory for pixel data is then allocated.
 10359        - Memory buffer used to store previous pixel values is freed if necessary.
 10360        - If the instance image is shared, this constructor actually does nothing more than verifying
 10361        that new and old image dimensions fit.
 10362        - Image pixels allocated by this function are \b not \b initialized.
 10363        Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
 10364        to assign an image of desired size with pixels set to a particular value.
 10365     **/
 10366     CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
 10367       const unsigned long siz = dx*dy*dz*dv;
 10368       if (!siz) return assign();
 10369       const unsigned long curr_siz = size();
 10370       if (siz!=curr_siz) {
 10371         if (is_shared)
 10372           throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
 10373                                       pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
 10374         else { if (data) delete[] data; data = new T[siz]; }
 10376       width = dx; height = dy; depth = dz; dim = dv;
 10377       return *this;
 10380     //! In-place version of the previous constructor.
 10381     /**
 10382        This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T
 10383        and sets all pixel values of the instance image to \p val.
 10384        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 10385        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 10386        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 10387        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 10388        \param val Default value for image pixels.
 10389        \remark
 10390        - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
 10391     **/
 10392     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
 10393       return assign(dx,dy,dz,dv).fill(val);
 10396     //! In-place version of the previous constructor.
 10397     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 10398                     const int val0, const int val1, ...) {
 10399       assign(dx,dy,dz,dv);
 10400       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 10401       return *this;
 10404     //! In-place version of the previous constructor.
 10405     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 10406                     const double val0, const double val1, ...) {
 10407       assign(dx,dy,dz,dv);
 10408       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 10409       return *this;
 10412     //! In-place version of the previous constructor.
 10413     template<typename t>
 10414     CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 10415                     const unsigned int dz=1, const unsigned int dv=1) {
 10416       const unsigned long siz = dx*dy*dz*dv;
 10417       if (!data_buffer || !siz) return assign();
 10418       assign(dx,dy,dz,dv);
 10419       const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 10420       return *this;
 10423 #ifndef cimg_use_visualcpp6
 10424     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 10425                     const unsigned int dz=1, const unsigned int dv=1)
 10426 #else
 10427     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 10428                     const unsigned int dz, const unsigned int dv)
 10429 #endif
 10431       const unsigned long siz = dx*dy*dz*dv;
 10432       if (!data_buffer || !siz) return assign();
 10433       const unsigned long curr_siz = size();
 10434       if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
 10435       if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
 10436         assign(dx,dy,dz,dv);
 10437         if (is_shared) cimg_std::memmove(data,data_buffer,siz*sizeof(T));
 10438         else cimg_std::memcpy(data,data_buffer,siz*sizeof(T));
 10439       } else {
 10440         T *new_data = new T[siz];
 10441         cimg_std::memcpy(new_data,data_buffer,siz*sizeof(T));
 10442         delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
 10444       return *this;
 10447     //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
 10448     template<typename t>
 10449     CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
 10450                     const unsigned int dz, const unsigned int dv, const bool shared) {
 10451       if (shared)
 10452         throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
 10453                                     "(different pixel types).",
 10454                                     pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
 10455       return assign(data_buffer,dx,dy,dz,dv);
 10458     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 10459                     const unsigned int dz, const unsigned int dv, const bool shared) {
 10460       const unsigned long siz = dx*dy*dz*dv;
 10461       if (!data_buffer || !siz) return assign();
 10462       if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
 10463       else {
 10464         if (!is_shared) {
 10465           if (data_buffer+siz<data || data_buffer>=data+size()) assign();
 10466           else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
 10467                           pixel_type());
 10469         width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
 10470         data = const_cast<T*>(data_buffer);
 10472       return *this;
 10475     //! In-place version of the default copy constructor.
 10476     /**
 10477        This function assigns a copy of the input image \p img to the current instance image.
 10478        \param img The input image to copy.
 10479        \remark
 10480        - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
 10481        becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
 10482        - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
 10483        of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
 10484     **/
 10485     template<typename t>
 10486     CImg<T>& assign(const CImg<t>& img) {
 10487       return assign(img.data,img.width,img.height,img.depth,img.dim);
 10490     //! In-place version of the advanced constructor.
 10491     /**
 10492        This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
 10493        current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
 10494        or non-shared (if the input parameter \p shared is set to \c false).
 10495        \param img The input image to copy.
 10496        \param shared Boolean flag that decides if the copy is shared or non-shared.
 10497        \remark
 10498        - It is not possible to assign a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
 10499        - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
 10500        - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
 10501        image is the same as the one used by the input image \p img.
 10502     **/
 10503     template<typename t>
 10504     CImg<T>& assign(const CImg<t>& img, const bool shared) {
 10505       return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
 10508     //! In-place version of the previous constructor.
 10509     template<typename t>
 10510     CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
 10511       if (dimensions) {
 10512         unsigned int siz[4] = { 0,1,1,1 };
 10513         const char *s = dimensions;
 10514         char tmp[256] = { 0 }, c = 0;
 10515         int val = 0;
 10516         for (unsigned int k=0; k<4; ++k) {
 10517           const int err = cimg_std::sscanf(s,"%[-0-9]%c",tmp,&c);
 10518           if (err>=1) {
 10519             const int err = cimg_std::sscanf(s,"%d",&val);
 10520             if (err==1) {
 10521               int val2 = val<0?-val:(c=='%'?val:-1);
 10522               if (val2>=0) {
 10523                 val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
 10524                 if (c!='%' && !val) val = 1;
 10526               siz[k] = val;
 10528             s+=cimg::strlen(tmp);
 10529             if (c=='%') ++s;
 10531           if (!err) {
 10532             if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
 10533             else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
 10534             else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
 10535             else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
 10536             else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
 10537             else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
 10538             else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
 10539             else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
 10540             else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
 10541             else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
 10542             else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
 10543             else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
 10544             else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
 10545             else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
 10546             else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
 10547             else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
 10548             else { ++s; --k; }
 10551         return assign(siz[0],siz[1],siz[2],siz[3]);
 10553       return assign();
 10556     //! In-place version of the previous constructor.
 10557     template<typename t>
 10558     CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
 10559       return assign(img,dimensions).fill(val);
 10562     //! In-place version of the previous constructor.
 10563     /**
 10564        This function replaces the instance image by the one that have been read from the given file.
 10565        \param filename Filename of the image file.
 10566        - The image format is deduced from the filename only by looking for the filename extension i.e. without
 10567        analyzing the file itself.
 10568        - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
 10569        More informations on this topic can be found in cimg_files_io.
 10570        - If the filename is not found, a CImgIOException is thrown by this constructor.
 10571     **/
 10572     CImg<T>& assign(const char *const filename) {
 10573       return load(filename);
 10576     //! In-place version of the previous constructor.
 10577     CImg<T>& assign(const CImgDisplay &disp) {
 10578       disp.snapshot(*this);
 10579       return *this;
 10582     //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
 10583     /**
 10584        The instance image is always empty after a call to this function.
 10585     **/
 10586     template<typename t>
 10587     CImg<t>& transfer_to(CImg<t>& img) {
 10588       img.assign(*this);
 10589       assign();
 10590       return img;
 10593     CImg<T>& transfer_to(CImg<T>& img) {
 10594       if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
 10595       return img;
 10598     //! Swap all fields of two images. Use with care !
 10599     CImg<T>& swap(CImg<T>& img) {
 10600       cimg::swap(width,img.width);
 10601       cimg::swap(height,img.height);
 10602       cimg::swap(depth,img.depth);
 10603       cimg::swap(dim,img.dim);
 10604       cimg::swap(data,img.data);
 10605       cimg::swap(is_shared,img.is_shared);
 10606       return img;
 10609     //@}
 10610     //-------------------------------------
 10611     //
 10612     //! \name Image Informations
 10613     //@{
 10614     //-------------------------------------
 10616     //! Return the type of the pixel values.
 10617     /**
 10618        \return a string describing the type of the image pixels (template parameter \p T).
 10619        - The string returned may contains spaces (<tt>"unsigned char"</tt>).
 10620        - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
 10621     **/
 10622     static const char* pixel_type() {
 10623       return cimg::type<T>::string();
 10626     //! Return the total number of pixel values in an image.
 10627     /**
 10628        - Equivalent to : dimx() * dimy() * dimz() * dimv().
 10630        \par example:
 10631        \code
 10632        CImg<> img(100,100,1,3);
 10633        if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
 10634        \endcode
 10635     **/
 10636     unsigned long size() const {
 10637       return width*height*depth*dim;
 10640     //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
 10641     int dimx() const {
 10642       return (int)width;
 10645     //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
 10646     int dimy() const {
 10647       return (int)height;
 10650     //! Return the number of slices of the instance image (size along the Z-axis).
 10651     int dimz() const {
 10652       return (int)depth;
 10655     //! Return the number of vector channels of the instance image (size along the V-axis).
 10656     int dimv() const {
 10657       return (int)dim;
 10660     //! Return \c true if image (*this) has the specified width.
 10661     bool is_sameX(const unsigned int dx) const {
 10662       return (width==dx);
 10665     //! Return \c true if images \c (*this) and \c img have same width.
 10666     template<typename t>
 10667     bool is_sameX(const CImg<t>& img) const {
 10668       return is_sameX(img.width);
 10671     //! Return \c true if images \c (*this) and the display \c disp have same width.
 10672     bool is_sameX(const CImgDisplay& disp) const {
 10673       return is_sameX(disp.width);
 10676     //! Return \c true if image (*this) has the specified height.
 10677     bool is_sameY(const unsigned int dy) const {
 10678       return (height==dy);
 10681     //! Return \c true if images \c (*this) and \c img have same height.
 10682     template<typename t>
 10683     bool is_sameY(const CImg<t>& img) const {
 10684       return is_sameY(img.height);
 10687     //! Return \c true if images \c (*this) and the display \c disp have same height.
 10688     bool is_sameY(const CImgDisplay& disp) const {
 10689       return is_sameY(disp.height);
 10692     //! Return \c true if image (*this) has the specified depth.
 10693     bool is_sameZ(const unsigned int dz) const {
 10694       return (depth==dz);
 10697     //! Return \c true if images \c (*this) and \c img have same depth.
 10698     template<typename t>
 10699     bool is_sameZ(const CImg<t>& img) const {
 10700       return is_sameZ(img.depth);
 10703     //! Return \c true if image (*this) has the specified number of channels.
 10704     bool is_sameV(const unsigned int dv) const {
 10705       return (dim==dv);
 10708     //! Return \c true if images \c (*this) and \c img have same dim.
 10709     template<typename t>
 10710     bool is_sameV(const CImg<t>& img) const {
 10711       return is_sameV(img.dim);
 10714     //! Return \c true if image (*this) has the specified width and height.
 10715     bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
 10716       return (is_sameX(dx) && is_sameY(dy));
 10719     //! Return \c true if images have same width and same height.
 10720     template<typename t>
 10721     bool is_sameXY(const CImg<t>& img) const {
 10722       return (is_sameX(img) && is_sameY(img));
 10725     //! Return \c true if image \c (*this) and the display \c disp have same width and same height.
 10726     bool is_sameXY(const CImgDisplay& disp) const {
 10727       return (is_sameX(disp) && is_sameY(disp));
 10730     //! Return \c true if image (*this) has the specified width and depth.
 10731     bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
 10732       return (is_sameX(dx) && is_sameZ(dz));
 10735     //! Return \c true if images have same width and same depth.
 10736     template<typename t>
 10737     bool is_sameXZ(const CImg<t>& img) const {
 10738       return (is_sameX(img) && is_sameZ(img));
 10741     //! Return \c true if image (*this) has the specified width and number of channels.
 10742     bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
 10743       return (is_sameX(dx) && is_sameV(dv));
 10746     //! Return \c true if images have same width and same number of channels.
 10747     template<typename t>
 10748     bool is_sameXV(const CImg<t>& img) const {
 10749       return (is_sameX(img) && is_sameV(img));
 10752     //! Return \c true if image (*this) has the specified height and depth.
 10753     bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
 10754       return (is_sameY(dy) && is_sameZ(dz));
 10757     //! Return \c true if images have same height and same depth.
 10758     template<typename t>
 10759     bool is_sameYZ(const CImg<t>& img) const {
 10760       return (is_sameY(img) && is_sameZ(img));
 10763     //! Return \c true if image (*this) has the specified height and number of channels.
 10764     bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
 10765       return (is_sameY(dy) && is_sameV(dv));
 10768     //! Return \c true if images have same height and same number of channels.
 10769     template<typename t>
 10770     bool is_sameYV(const CImg<t>& img) const {
 10771       return (is_sameY(img) && is_sameV(img));
 10774     //! Return \c true if image (*this) has the specified depth and number of channels.
 10775     bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
 10776       return (is_sameZ(dz) && is_sameV(dv));
 10779     //! Return \c true if images have same depth and same number of channels.
 10780     template<typename t>
 10781     bool is_sameZV(const CImg<t>& img) const {
 10782       return (is_sameZ(img) && is_sameV(img));
 10785     //! Return \c true if image (*this) has the specified width, height and depth.
 10786     bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
 10787       return (is_sameXY(dx,dy) && is_sameZ(dz));
 10790     //! Return \c true if images have same width, same height and same depth.
 10791     template<typename t>
 10792     bool is_sameXYZ(const CImg<t>& img) const {
 10793       return (is_sameXY(img) && is_sameZ(img));
 10796     //! Return \c true if image (*this) has the specified width, height and depth.
 10797     bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
 10798       return (is_sameXY(dx,dy) && is_sameV(dv));
 10801     //! Return \c true if images have same width, same height and same number of channels.
 10802     template<typename t>
 10803     bool is_sameXYV(const CImg<t>& img) const {
 10804       return (is_sameXY(img) && is_sameV(img));
 10807     //! Return \c true if image (*this) has the specified width, height and number of channels.
 10808     bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
 10809       return (is_sameXZ(dx,dz) && is_sameV(dv));
 10812     //! Return \c true if images have same width, same depth and same number of channels.
 10813     template<typename t>
 10814     bool is_sameXZV(const CImg<t>& img) const {
 10815       return (is_sameXZ(img) && is_sameV(img));
 10818     //! Return \c true if image (*this) has the specified height, depth and number of channels.
 10819     bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 10820       return (is_sameYZ(dy,dz) && is_sameV(dv));
 10823     //! Return \c true if images have same heigth, same depth and same number of channels.
 10824     template<typename t>
 10825     bool is_sameYZV(const CImg<t>& img) const {
 10826       return (is_sameYZ(img) && is_sameV(img));
 10829     //! Return \c true if image (*this) has the specified width, height, depth and number of channels.
 10830     bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 10831       return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
 10834     //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
 10835     template<typename t>
 10836     bool is_sameXYZV(const CImg<t>& img) const {
 10837       return (is_sameXYZ(img) && is_sameV(img));
 10840     //! Return \c true if current image is empty.
 10841     bool is_empty() const {
 10842       return !(data && width && height && depth && dim);
 10845     //! Return \p true if image is not empty.
 10846     operator bool() const {
 10847       return !is_empty();
 10850     //! Return an iterator to the first image pixel
 10851     iterator begin() {
 10852       return data;
 10855     const_iterator begin() const {
 10856       return data;
 10859     //! Return reference to the first image pixel
 10860     const T& first() const {
 10861       return *data;
 10864     T& first() {
 10865        return *data;
 10868     //! Return an iterator pointing after the last image pixel
 10869     iterator end() {
 10870       return data + size();
 10873     const_iterator end() const {
 10874       return data + size();
 10877     //! Return a reference to the last image pixel
 10878     const T& last() const {
 10879        return data[size() - 1];
 10882     T& last() {
 10883        return data[size() - 1];
 10886     //! Return a pointer to the pixel buffer.
 10887     T* ptr() {
 10888       return data;
 10891     const T* ptr() const {
 10892       return data;
 10895     //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
 10896     /**
 10897        \param x X-coordinate of the pixel.
 10898        \param y Y-coordinate of the pixel.
 10899        \param z Z-coordinate of the pixel.
 10900        \param v V-coordinate of the pixel.
 10902        - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer.
 10903        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
 10904        given coordinates are outside the image range (but function performances decrease).
 10906        \par example:
 10907        \code
 10908        CImg<float> img(100,100,1,1,0);   // Define a 100x100 greyscale image with float-valued pixels.
 10909        float *ptr = ptr(10,10);          // Get a pointer to the pixel located at (10,10).
 10910        float val = *ptr;                 // Get the pixel value.
 10911        \endcode
 10912     **/
 10913 #if cimg_debug>=3
 10914     T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 10915       const long off = offset(x,y,z,v);
 10916       if (off<0 || off>=(long)size()) {
 10917         cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
 10918                    "outside image range (%u,%u,%u,%u) (size=%lu)",
 10919                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
 10920         return data;
 10922       return data + off;
 10925     const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 10926       return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
 10928 #else
 10929     T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 10930       return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 10933     const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 10934       return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 10936 #endif
 10938     //! Return \c true if the memory buffers of the two images overlaps.
 10939     /**
 10940        May happen when using shared images.
 10941     **/
 10942     template<typename t>
 10943     bool is_overlapped(const CImg<t>& img) const {
 10944       const unsigned long csiz = size(), isiz = img.size();
 10945       return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
 10948     //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data.
 10949     /**
 10950        \param x X-coordinate of the pixel.
 10951        \param y Y-coordinate of the pixel.
 10952        \param z Z-coordinate of the pixel.
 10953        \param v V-coordinate of the pixel.
 10955        - No checking is done on the validity of the given coordinates.
 10957        \par Example:
 10958        \code
 10959        CImg<float> img(100,100,1,3,0);         // Define a 100x100 color image with float-valued black pixels.
 10960        long off = img.offset(10,10,0,2);       // Get the offset of the blue value of the pixel located at (10,10).
 10961        float val = img[off];                   // Get the blue value of the pixel.
 10962        \endcode
 10963     **/
 10964     long offset(const int x, const int y=0, const int z=0, const int v=0) const {
 10965       return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 10968     //! Fast access to pixel value for reading or writing.
 10969     /**
 10970        \param x X-coordinate of the pixel.
 10971        \param y Y-coordinate of the pixel.
 10972        \param z Z-coordinate of the pixel.
 10973        \param v V-coordinate of the pixel.
 10975        - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
 10976        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
 10977        (but function performances decrease).
 10979        \par example:
 10980        \code
 10981        CImg<float> img(100,100,1,3,0);                       // Define a 100x100 color image with float-valued black pixels.
 10982        const float valR = img(10,10,0,0);                    // Read the red component at coordinates (10,10).
 10983        const float valG = img(10,10,0,1);                    // Read the green component at coordinates (10,10)
 10984        const float valB = img(10,10,2);                      // Read the blue component at coordinates (10,10) (Z-coordinate omitted here).
 10985        const float avg = (valR + valG + valB)/3;             // Compute average pixel value.
 10986        img(10,10,0) = img(10,10,1) = img(10,10,2) = avg;     // Replace the pixel (10,10) by the average grey value.
 10987        \endcode
 10988     **/
 10989 #if cimg_debug>=3
 10990     T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 10991       const long off = offset(x,y,z,v);
 10992       if (!data || off>=(long)size()) {
 10993         cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
 10994                    "outside the image range (%u,%u,%u,%u) (size=%lu)",
 10995                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
 10996         return *data;
 10998       else return data[off];
 11001     const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 11002       return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
 11004 #else
 11005     T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 11006       return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 11009     const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 11010       return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 11012 #endif
 11014     //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
 11015     /**
 11016        \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr().
 11018        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
 11019        (but function performances decrease).
 11020        - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
 11021        with operator()() (see example below).
 11023        \par example:
 11024        \code
 11025        CImg<float> vec(1,10);        // Define a vector of float values (10 lines, 1 row).
 11026        const float val1 = vec(0,4);  // Get the fifth element using operator()().
 11027        const float val2 = vec[4];    // Get the fifth element using operator[]. Here, val2==val1.
 11028        \endcode
 11029     **/
 11030 #if cimg_debug>=3
 11031     T& operator[](const unsigned long off) {
 11032       if (!data || off>=size()) {
 11033         cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
 11034                    "outside the image range (%u,%u,%u,%u) (size=%lu)",
 11035                    pixel_type(),off,width,height,depth,dim,size());
 11036         return *data;
 11038       else return data[off];
 11041     const T& operator[](const unsigned long off) const {
 11042       return const_cast<CImg<T>*>(this)->operator[](off);
 11044 #else
 11045     T& operator[](const unsigned long off) {
 11046       return data[off];
 11049     const T& operator[](const unsigned long off) const {
 11050       return data[off];
 11052 #endif
 11054     //! Return a reference to the last image value
 11055     T& back() {
 11056       return operator()(size()-1);
 11059     const T& back() const {
 11060       return operator()(size()-1);
 11063     //! Return a reference to the first image value
 11064     T& front() {
 11065       return *data;
 11068     const T& front() const {
 11069       return *data;
 11072     //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
 11073     bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
 11074       return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
 11077     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
 11078     template<typename t>
 11079     bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
 11080       const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
 11081       const T *const ppixel = &pixel;
 11082       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 11083       unsigned long off = (unsigned long)(ppixel - data);
 11084       const unsigned long nv = off/whz;
 11085       off%=whz;
 11086       const unsigned long nz = off/wh;
 11087       off%=wh;
 11088       const unsigned long ny = off/width, nx = off%width;
 11089       x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
 11090       return true;
 11093     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
 11094     template<typename t>
 11095     bool contains(const T& pixel, t& x, t& y, t& z) const {
 11096       const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
 11097       const T *const ppixel = &pixel;
 11098       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 11099       unsigned long off = ((unsigned long)(ppixel - data))%whz;
 11100       const unsigned long nz = off/wh;
 11101       off%=wh;
 11102       const unsigned long ny = off/width, nx = off%width;
 11103       x = (t)nx; y = (t)ny; z = (t)nz;
 11104       return true;
 11107     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y).
 11108     template<typename t>
 11109     bool contains(const T& pixel, t& x, t& y) const {
 11110       const unsigned long wh = width*height, siz = wh*depth*dim;
 11111       const T *const ppixel = &pixel;
 11112       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 11113       unsigned long off = ((unsigned long)(ppixel - data))%wh;
 11114       const unsigned long ny = off/width, nx = off%width;
 11115       x = (t)nx; y = (t)ny;
 11116       return true;
 11119     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x).
 11120     template<typename t>
 11121     bool contains(const T& pixel, t& x) const {
 11122       const T *const ppixel = &pixel;
 11123       if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
 11124       x = (t)(((unsigned long)(ppixel - data))%width);
 11125       return true;
 11128     //! Return \c true if specified referenced value is inside the image boundaries.
 11129     bool contains(const T& pixel) const {
 11130       const T *const ppixel = &pixel;
 11131       return !is_empty() && ppixel>=data && ppixel<data+size();
 11134     //! Read a pixel value with Dirichlet boundary conditions.
 11135     T& at(const int off, const T out_val) {
 11136       return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
 11139     T at(const int off, const T out_val) const {
 11140       return (off<0 || off>=(int)size())?out_val:(*this)[off];
 11143     //! Read a pixel value with Neumann boundary conditions.
 11144     T& at(const int off) {
 11145       if (!size())
 11146         throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
 11147                                     pixel_type());
 11148       return _at(off);
 11151     T at(const int off) const {
 11152       if (!size())
 11153         throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
 11154                                     pixel_type());
 11155       return _at(off);
 11158     T& _at(const int off) {
 11159       const unsigned int siz = (unsigned int)size();
 11160       return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
 11163     T _at(const int off) const {
 11164       const unsigned int siz = (unsigned int)size();
 11165       return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
 11168     //! Read a pixel value with Dirichlet boundary conditions.
 11169     T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
 11170       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
 11171         (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 11174     T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
 11175       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
 11178     //! Read a pixel value with Neumann boundary conditions.
 11179     T& atXYZV(const int x, const int y, const int z, const int v) {
 11180       if (is_empty())
 11181         throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
 11182                                     pixel_type());
 11183       return _atXYZV(x,y,z,v);
 11186     T atXYZV(const int x, const int y, const int z, const int v) const {
 11187       if (is_empty())
 11188         throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
 11189                                     pixel_type());
 11190       return _atXYZV(x,y,z,v);
 11193     T& _atXYZV(const int x, const int y, const int z, const int v) {
 11194       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 11195                      z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 11198     T _atXYZV(const int x, const int y, const int z, const int v) const {
 11199       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 11200                      z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 11203     //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
 11204     T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
 11205       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
 11206         (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 11209     T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
 11210       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
 11213     //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
 11214     T& atXYZ(const int x, const int y, const int z, const int v=0) {
 11215       if (is_empty())
 11216         throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
 11217                                     pixel_type());
 11218       return _atXYZ(x,y,z,v);
 11221     T atXYZ(const int x, const int y, const int z, const int v=0) const {
 11222       if (is_empty())
 11223         throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
 11224                                     pixel_type());
 11225       return _atXYZ(x,y,z,v);
 11228     T& _atXYZ(const int x, const int y, const int z, const int v=0) {
 11229       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
 11230                      z<0?0:(z>=dimz()?dimz()-1:z),v);
 11233     T _atXYZ(const int x, const int y, const int z, const int v=0) const {
 11234       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
 11235                      z<0?0:(z>=dimz()?dimz()-1:z),v);
 11238     //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
 11239     T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
 11240       return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 11243     T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
 11244       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
 11247     //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
 11248     T& atXY(const int x, const int y, const int z=0, const int v=0) {
 11249       if (is_empty())
 11250         throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
 11251                                     pixel_type());
 11252       return _atXY(x,y,z,v);
 11255     T atXY(const int x, const int y, const int z=0, const int v=0) const {
 11256       if (is_empty())
 11257         throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
 11258                                     pixel_type());
 11259       return _atXY(x,y,z,v);
 11262     T& _atXY(const int x, const int y, const int z=0, const int v=0) {
 11263       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 11266     T _atXY(const int x, const int y, const int z=0, const int v=0) const {
 11267       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 11270     //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
 11271     T& atX(const int x, const int y, const int z, const int v, const T out_val) {
 11272       return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 11275     T atX(const int x, const int y, const int z, const int v, const T out_val) const {
 11276       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
 11279     //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
 11280     T& atX(const int x, const int y=0, const int z=0, const int v=0) {
 11281       if (is_empty())
 11282         throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
 11283                                     pixel_type());
 11284       return _atX(x,y,z,v);
 11287     T atX(const int x, const int y=0, const int z=0, const int v=0) const {
 11288       if (is_empty())
 11289         throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
 11290                                     pixel_type());
 11291       return _atX(x,y,z,v);
 11294     T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
 11295       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 11298     T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
 11299       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 11302     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
 11303     Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
 11304       const int
 11305         x = (int)fx-(fx>=0?0:1), nx = x+1,
 11306         y = (int)fy-(fy>=0?0:1), ny = y+1,
 11307         z = (int)fz-(fz>=0?0:1), nz = z+1,
 11308         v = (int)fv-(fv>=0?0:1), nv = v+1;
 11309       const float
 11310         dx = fx-x,
 11311         dy = fy-y,
 11312         dz = fz-z,
 11313         dv = fv-v;
 11314       const Tfloat
 11315         Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
 11316         Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
 11317         Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
 11318         Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
 11319         Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
 11320         Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
 11321         Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
 11322         Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
 11323       return Icccc +
 11324         dx*(Inccc-Icccc +
 11325             dy*(Icccc+Inncc-Icncc-Inccc +
 11326                 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 11327                     dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 11328                 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 11329             dz*(Icccc+Incnc-Iccnc-Inccc +
 11330                 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 11331             dv*(Icccc+Inccn-Inccc-Icccn)) +
 11332         dy*(Icncc-Icccc +
 11333             dz*(Icccc+Icnnc-Iccnc-Icncc +
 11334                 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 11335             dv*(Icccc+Icncn-Icncc-Icccn)) +
 11336         dz*(Iccnc-Icccc +
 11337             dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 11338         dv*(Icccn-Icccc);
 11341     //! Read a pixel value using linear interpolation and Neumann boundary conditions.
 11342     Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 11343       if (is_empty())
 11344         throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
 11345                                     pixel_type());
 11346       return _linear_atXYZV(fx,fy,fz,fv);
 11349     Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 11350       const float
 11351         nfx = fx<0?0:(fx>width-1?width-1:fx),
 11352         nfy = fy<0?0:(fy>height-1?height-1:fy),
 11353         nfz = fz<0?0:(fz>depth-1?depth-1:fz),
 11354         nfv = fv<0?0:(fv>dim-1?dim-1:fv);
 11355       const unsigned int
 11356         x = (unsigned int)nfx,
 11357         y = (unsigned int)nfy,
 11358         z = (unsigned int)nfz,
 11359         v = (unsigned int)nfv;
 11360       const float
 11361         dx = nfx-x,
 11362         dy = nfy-y,
 11363         dz = nfz-z,
 11364         dv = nfv-v;
 11365       const unsigned int
 11366         nx = dx>0?x+1:x,
 11367         ny = dy>0?y+1:y,
 11368         nz = dz>0?z+1:z,
 11369         nv = dv>0?v+1:v;
 11370       const Tfloat
 11371         Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
 11372         Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
 11373         Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
 11374         Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
 11375         Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
 11376         Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
 11377         Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
 11378         Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
 11379       return Icccc +
 11380         dx*(Inccc-Icccc +
 11381             dy*(Icccc+Inncc-Icncc-Inccc +
 11382                 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 11383                     dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 11384                 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 11385             dz*(Icccc+Incnc-Iccnc-Inccc +
 11386                 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 11387             dv*(Icccc+Inccn-Inccc-Icccn)) +
 11388         dy*(Icncc-Icccc +
 11389             dz*(Icccc+Icnnc-Iccnc-Icncc +
 11390                 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 11391             dv*(Icccc+Icncn-Icncc-Icccn)) +
 11392         dz*(Iccnc-Icccc +
 11393             dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 11394         dv*(Icccn-Icccc);
 11397     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
 11398     Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
 11399       const int
 11400         x = (int)fx-(fx>=0?0:1), nx = x+1,
 11401         y = (int)fy-(fy>=0?0:1), ny = y+1,
 11402         z = (int)fz-(fz>=0?0:1), nz = z+1;
 11403       const float
 11404         dx = fx-x,
 11405         dy = fy-y,
 11406         dz = fz-z;
 11407       const Tfloat
 11408         Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
 11409         Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
 11410         Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
 11411         Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
 11412       return Iccc +
 11413         dx*(Incc-Iccc +
 11414             dy*(Iccc+Innc-Icnc-Incc +
 11415                 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 11416             dz*(Iccc+Incn-Iccn-Incc)) +
 11417         dy*(Icnc-Iccc +
 11418             dz*(Iccc+Icnn-Iccn-Icnc)) +
 11419         dz*(Iccn-Iccc);
 11422     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
 11423     Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
 11424       if (is_empty())
 11425         throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
 11426                                     pixel_type());
 11427       return _linear_atXYZ(fx,fy,fz,v);
 11430     Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
 11431       const float
 11432         nfx = fx<0?0:(fx>width-1?width-1:fx),
 11433         nfy = fy<0?0:(fy>height-1?height-1:fy),
 11434         nfz = fz<0?0:(fz>depth-1?depth-1:fz);
 11435       const unsigned int
 11436         x = (unsigned int)nfx,
 11437         y = (unsigned int)nfy,
 11438         z = (unsigned int)nfz;
 11439       const float
 11440         dx = nfx-x,
 11441         dy = nfy-y,
 11442         dz = nfz-z;
 11443       const unsigned int
 11444         nx = dx>0?x+1:x,
 11445         ny = dy>0?y+1:y,
 11446         nz = dz>0?z+1:z;
 11447       const Tfloat
 11448         Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
 11449         Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
 11450         Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
 11451         Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
 11452       return Iccc +
 11453         dx*(Incc-Iccc +
 11454             dy*(Iccc+Innc-Icnc-Incc +
 11455                 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 11456             dz*(Iccc+Incn-Iccn-Incc)) +
 11457         dy*(Icnc-Iccc +
 11458             dz*(Iccc+Icnn-Iccn-Icnc)) +
 11459         dz*(Iccn-Iccc);
 11462     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
 11463     Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
 11464       const int
 11465         x = (int)fx-(fx>=0?0:1), nx = x+1,
 11466         y = (int)fy-(fy>=0?0:1), ny = y+1;
 11467       const float
 11468         dx = fx-x,
 11469         dy = fy-y;
 11470       const Tfloat
 11471         Icc = (Tfloat)atXY(x,y,z,v,out_val),  Inc = (Tfloat)atXY(nx,y,z,v,out_val),
 11472         Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
 11473       return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 11476     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
 11477     Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 11478       if (is_empty())
 11479         throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
 11480                                     pixel_type());
 11481       return _linear_atXY(fx,fy,z,v);
 11484     Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 11485       const float
 11486         nfx = fx<0?0:(fx>width-1?width-1:fx),
 11487         nfy = fy<0?0:(fy>height-1?height-1:fy);
 11488       const unsigned int
 11489         x = (unsigned int)nfx,
 11490         y = (unsigned int)nfy;
 11491       const float
 11492         dx = nfx-x,
 11493         dy = nfy-y;
 11494       const unsigned int
 11495         nx = dx>0?x+1:x,
 11496         ny = dy>0?y+1:y;
 11497       const Tfloat
 11498         Icc = (Tfloat)(*this)(x,y,z,v),  Inc = (Tfloat)(*this)(nx,y,z,v),
 11499         Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
 11500       return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 11503     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
 11504     Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
 11505       const int
 11506         x = (int)fx-(fx>=0?0:1), nx = x+1;
 11507       const float
 11508         dx = fx-x;
 11509       const Tfloat
 11510         Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
 11511       return Ic + dx*(In-Ic);
 11514     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
 11515     Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 11516       if (is_empty())
 11517         throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
 11518                                     pixel_type());
 11519       return _linear_atX(fx,y,z,v);
 11522     Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 11523       const float
 11524         nfx = fx<0?0:(fx>width-1?width-1:fx);
 11525       const unsigned int
 11526         x = (unsigned int)nfx;
 11527       const float
 11528         dx = nfx-x;
 11529       const unsigned int
 11530         nx = dx>0?x+1:x;
 11531       const Tfloat
 11532         Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
 11533       return Ic + dx*(In-Ic);
 11536     //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
 11537     Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
 11538       const int
 11539         x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
 11540         y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
 11541       const float
 11542         dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
 11543         dy = fy-y;
 11544       const Tfloat
 11545         Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
 11546         Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
 11547         Ipc = (Tfloat)atXY(px,y,z,v,out_val),  Icc = (Tfloat)atXY(x,y,z,v,out_val),
 11548         Inc = (Tfloat)atXY(nx,y,z,v,out_val),  Iac = (Tfloat)atXY(ax,y,z,v,out_val),
 11549         Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
 11550         Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
 11551         Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
 11552         Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
 11553         valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
 11554         valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
 11555         u0p = Icp - Ipp,
 11556         u1p = Iap - Inp,
 11557         ap = 2*(Icp-Inp) + u0p + u1p,
 11558         bp = 3*(Inp-Icp) - 2*u0p - u1p,
 11559         u0c = Icc - Ipc,
 11560         u1c = Iac - Inc,
 11561         ac = 2*(Icc-Inc) + u0c + u1c,
 11562         bc = 3*(Inc-Icc) - 2*u0c - u1c,
 11563         u0n = Icn - Ipn,
 11564         u1n = Ian - Inn,
 11565         an = 2*(Icn-Inn) + u0n + u1n,
 11566         bn = 3*(Inn-Icn) - 2*u0n - u1n,
 11567         u0a = Ica - Ipa,
 11568         u1a = Iaa - Ina,
 11569         aa = 2*(Ica-Ina) + u0a + u1a,
 11570         ba = 3*(Ina-Ica) - 2*u0a - u1a,
 11571         valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 11572         valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 11573         valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 11574         vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 11575         u0 = valc - valp,
 11576         u1 = vala - valn,
 11577         a = 2*(valc-valn) + u0 + u1,
 11578         b = 3*(valn-valc) - 2*u0 - u1,
 11579         val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 11580       return val<valm?valm:(val>valM?valM:val);
 11583     //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
 11584     Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 11585       if (is_empty())
 11586         throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
 11587                                     pixel_type());
 11588       return _cubic_atXY(fx,fy,z,v);
 11591     Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 11592       const float
 11593         nfx = fx<0?0:(fx>width-1?width-1:fx),
 11594         nfy = fy<0?0:(fy>height-1?height-1:fy);
 11595       const int
 11596         x = (int)nfx,
 11597         y = (int)nfy;
 11598       const float
 11599         dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
 11600         dy = nfy-y;
 11601       const int
 11602         px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
 11603         py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
 11604       const Tfloat
 11605         Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
 11606         Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
 11607         Ipc = (Tfloat)(*this)(px,y,z,v),  Icc = (Tfloat)(*this)(x,y,z,v),
 11608         Inc = (Tfloat)(*this)(nx,y,z,v),  Iac = (Tfloat)(*this)(ax,y,z,v),
 11609         Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
 11610         Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
 11611         Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
 11612         Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
 11613         valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
 11614         valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
 11615         u0p = Icp - Ipp,
 11616         u1p = Iap - Inp,
 11617         ap = 2*(Icp-Inp) + u0p + u1p,
 11618         bp = 3*(Inp-Icp) - 2*u0p - u1p,
 11619         u0c = Icc - Ipc,
 11620         u1c = Iac - Inc,
 11621         ac = 2*(Icc-Inc) + u0c + u1c,
 11622         bc = 3*(Inc-Icc) - 2*u0c - u1c,
 11623         u0n = Icn - Ipn,
 11624         u1n = Ian - Inn,
 11625         an = 2*(Icn-Inn) + u0n + u1n,
 11626         bn = 3*(Inn-Icn) - 2*u0n - u1n,
 11627         u0a = Ica - Ipa,
 11628         u1a = Iaa - Ina,
 11629         aa = 2*(Ica-Ina) + u0a + u1a,
 11630         ba = 3*(Ina-Ica) - 2*u0a - u1a,
 11631         valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 11632         valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 11633         valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 11634         vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 11635         u0 = valc - valp,
 11636         u1 = vala - valn,
 11637         a = 2*(valc-valn) + u0 + u1,
 11638         b = 3*(valn-valc) - 2*u0 - u1,
 11639         val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 11640       return val<valm?valm:(val>valM?valM:val);
 11643     //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
 11644     Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
 11645       const int
 11646         x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
 11647       const float
 11648         dx = fx-x;
 11649       const Tfloat
 11650         Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
 11651         In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
 11652         valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 11653         u0 = Ic - Ip,
 11654         u1 = Ia - In,
 11655         a = 2*(Ic-In) + u0 + u1,
 11656         b = 3*(In-Ic) - 2*u0 - u1,
 11657         val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 11658       return val<valm?valm:(val>valM?valM:val);
 11661     //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
 11662     Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 11663       if (is_empty())
 11664         throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
 11665                                     pixel_type());
 11666       return _cubic_atX(fx,y,z,v);
 11669     Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 11670       const float
 11671         nfx = fx<0?0:(fx>width-1?width-1:fx);
 11672       const int
 11673         x = (int)nfx;
 11674       const float
 11675         dx = nfx-x;
 11676       const int
 11677         px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
 11678       const Tfloat
 11679         Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
 11680         In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
 11681         valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 11682         u0 = Ic - Ip,
 11683         u1 = Ia - In,
 11684         a = 2*(Ic-In) + u0 + u1,
 11685         b = 3*(In-Ic) - 2*u0 - u1,
 11686         val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 11687       return val<valm?valm:(val>valM?valM:val);
 11690     //! Set a pixel value, with 3D float coordinates, using linear interpolation.
 11691     CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
 11692                            const bool add=false) {
 11693       const int
 11694         x = (int)fx-(fx>=0?0:1), nx = x+1,
 11695         y = (int)fy-(fy>=0?0:1), ny = y+1,
 11696         z = (int)fz-(fz>=0?0:1), nz = z+1;
 11697       const float
 11698         dx = fx-x,
 11699         dy = fy-y,
 11700         dz = fz-z;
 11701       if (v>=0 && v<dimv()) {
 11702         if (z>=0 && z<dimz()) {
 11703           if (y>=0 && y<dimy()) {
 11704             if (x>=0 && x<dimx()) {
 11705               const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
 11706               (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
 11708             if (nx>=0 && nx<dimx()) {
 11709               const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
 11710               (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
 11713           if (ny>=0 && ny<dimy()) {
 11714             if (x>=0 && x<dimx()) {
 11715               const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
 11716               (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
 11718             if (nx>=0 && nx<dimx()) {
 11719               const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
 11720               (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
 11724         if (nz>=0 && nz<dimz()) {
 11725           if (y>=0 && y<dimy()) {
 11726             if (x>=0 && x<dimx()) {
 11727               const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
 11728               (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
 11730             if (nx>=0 && nx<dimx()) {
 11731               const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
 11732               (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
 11735           if (ny>=0 && ny<dimy()) {
 11736             if (x>=0 && x<dimx()) {
 11737               const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
 11738               (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
 11740             if (nx>=0 && nx<dimx()) {
 11741               const float w1 = dx*dy, w2 = add?1:(1-w1);
 11742               (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
 11747       return *this;
 11750     //! Set a pixel value, with 2D float coordinates, using linear interpolation.
 11751     CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
 11752                           const bool add=false) {
 11753       const int
 11754         x = (int)fx-(fx>=0?0:1), nx = x+1,
 11755         y = (int)fy-(fy>=0?0:1), ny = y+1;
 11756       const float
 11757         dx = fx-x,
 11758         dy = fy-y;
 11759       if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
 11760         if (y>=0 && y<dimy()) {
 11761           if (x>=0 && x<dimx()) {
 11762             const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
 11763             (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
 11765           if (nx>=0 && nx<dimx()) {
 11766             const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
 11767             (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
 11770         if (ny>=0 && ny<dimy()) {
 11771           if (x>=0 && x<dimx()) {
 11772             const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
 11773             (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
 11775           if (nx>=0 && nx<dimx()) {
 11776             const float w1 = dx*dy, w2 = add?1:(1-w1);
 11777             (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
 11781       return *this;
 11784     //! Return a reference to the minimum pixel value of the instance image
 11785     const T& min() const {
 11786       if (is_empty())
 11787         throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
 11788                                     pixel_type());
 11789       const T *ptrmin = data;
 11790       T min_value = *ptrmin;
 11791       cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 11792       return *ptrmin;
 11795     //! Return a reference to the minimum pixel value of the instance image
 11796     T& min() {
 11797       if (is_empty())
 11798         throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
 11799                                     pixel_type());
 11800       T *ptrmin = data;
 11801       T min_value = *ptrmin;
 11802       cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 11803       return *ptrmin;
 11806     //! Return a reference to the maximum pixel value of the instance image
 11807     const T& max() const {
 11808       if (is_empty())
 11809         throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
 11810                                     pixel_type());
 11811       const T *ptrmax = data;
 11812       T max_value = *ptrmax;
 11813       cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 11814       return *ptrmax;
 11817     //! Return a reference to the maximum pixel value of the instance image
 11818     T& max() {
 11819       if (is_empty())
 11820         throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
 11821                                     pixel_type());
 11822       T *ptrmax = data;
 11823       T max_value = *ptrmax;
 11824       cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 11825       return *ptrmax;
 11828     //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 11829     template<typename t>
 11830     const T& minmax(t& max_val) const {
 11831       if (is_empty())
 11832         throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
 11833                                     pixel_type());
 11834       const T *ptrmin = data;
 11835       T min_value = *ptrmin, max_value = min_value;
 11836       cimg_for(*this,ptr,T) {
 11837         const T val = *ptr;
 11838         if (val<min_value) { min_value = val; ptrmin = ptr; }
 11839         if (val>max_value) max_value = val;
 11841       max_val = (t)max_value;
 11842       return *ptrmin;
 11845     //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 11846     template<typename t>
 11847     T& minmax(t& max_val) {
 11848       if (is_empty())
 11849         throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
 11850                                     pixel_type());
 11851       T *ptrmin = data;
 11852       T min_value = *ptrmin, max_value = min_value;
 11853       cimg_for(*this,ptr,T) {
 11854         const T val = *ptr;
 11855         if (val<min_value) { min_value = val; ptrmin = ptr; }
 11856         if (val>max_value) max_value = val;
 11858       max_val = (t)max_value;
 11859       return *ptrmin;
 11862     //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 11863     template<typename t>
 11864     const T& maxmin(t& min_val) const {
 11865       if (is_empty())
 11866         throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
 11867                                     pixel_type());
 11868       const T *ptrmax = data;
 11869       T max_value = *ptrmax, min_value = max_value;
 11870       cimg_for(*this,ptr,T) {
 11871         const T val = *ptr;
 11872         if (val>max_value) { max_value = val; ptrmax = ptr; }
 11873         if (val<min_value) min_value = val;
 11875       min_val = (t)min_value;
 11876       return *ptrmax;
 11879     //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 11880     template<typename t>
 11881     T& maxmin(t& min_val) {
 11882       if (is_empty())
 11883         throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
 11884                                     pixel_type());
 11885       T *ptrmax = data;
 11886       T max_value = *ptrmax, min_value = max_value;
 11887       cimg_for(*this,ptr,T) {
 11888         const T val = *ptr;
 11889         if (val>max_value) { max_value = val; ptrmax = ptr; }
 11890         if (val<min_value) min_value = val;
 11892       min_val = (t)min_value;
 11893       return *ptrmax;
 11896     //! Return the sum of all the pixel values in an image.
 11897     Tfloat sum() const {
 11898       if (is_empty())
 11899         throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
 11900                                                   pixel_type(),width,height,depth,dim,data);
 11901       Tfloat res = 0;
 11902       cimg_for(*this,ptr,T) res+=*ptr;
 11903       return res;
 11906     //! Return the mean pixel value of the instance image.
 11907     Tfloat mean() const {
 11908       if (is_empty())
 11909         throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",
 11910                                     pixel_type());
 11911       Tfloat val = 0;
 11912       cimg_for(*this,ptr,T) val+=*ptr;
 11913       return val/size();
 11916     //! Return the variance of the image.
 11917     /**
 11918        @param variance_method Determines how to calculate the variance
 11919        <table border="0">
 11920        <tr><td>0</td>
 11921        <td>Second moment:
 11922        @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
 11923        = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
 11924        with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
 11925        <tr><td>1</td>
 11926        <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
 11927        <tr><td>2</td>
 11928        <td>Least median of squares</td></tr>
 11929        <tr><td>3</td>
 11930        <td>Least trimmed of squares</td></tr>
 11931        </table>
 11932     */
 11933     Tfloat variance(const unsigned int variance_method=1) const {
 11934       Tfloat foo;
 11935       return variancemean(variance_method,foo);
 11938     //! Return the variance and the mean of the image.
 11939     template<typename t>
 11940     Tfloat variancemean(const unsigned int variance_method, t& mean) const {
 11941       if (is_empty())
 11942         throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",
 11943                                     pixel_type());
 11944       Tfloat variance = 0, average = 0;
 11945       const unsigned int siz = size();
 11946       switch (variance_method) {
 11947       case 3 : { // Least trimmed of Squares
 11948         CImg<Tfloat> buf(*this);
 11949         const unsigned int siz2 = siz>>1;
 11950         { cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }}
 11951         buf.sort();
 11952         Tfloat a = 0;
 11953         const Tfloat *ptrs = buf.ptr();
 11954         for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
 11955         const Tfloat sig = (Tfloat)(2.6477*cimg_std::sqrt(a/siz2));
 11956         variance = sig*sig;
 11957       } break;
 11958       case 2 : { // Least Median of Squares (MAD)
 11959         CImg<Tfloat> buf(*this);
 11960         buf.sort();
 11961         const unsigned int siz2 = siz>>1;
 11962         const Tfloat med_i = buf[siz2];
 11963         cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
 11964         buf.sort();
 11965         const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
 11966         variance = sig*sig;
 11967       } break;
 11968       case 1 : { // Least mean square (robust definition)
 11969         Tfloat S = 0, S2 = 0;
 11970         cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
 11971         variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
 11972         average = S;
 11973       } break;
 11974       case 0 :{ // Least mean square (standard definition)
 11975         Tfloat S = 0, S2 = 0;
 11976         cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
 11977         variance = (S2 - S*S/siz)/siz;
 11978         average = S;
 11979       } break;
 11980       default :
 11981         throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
 11982                                     pixel_type(),variance_method);
 11984       mean = (t)(average/siz);
 11985       return variance>0?variance:0;
 11988     //! Return the kth smallest element of the image.
 11989     // (Adapted from the numerical recipies for CImg)
 11990     T kth_smallest(const unsigned int k) const {
 11991       if (is_empty())
 11992         throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
 11993                                     pixel_type(),width,height,depth,dim,data);
 11994       CImg<T> arr(*this);
 11995       unsigned long l = 0, ir = size()-1;
 11996       for (;;) {
 11997         if (ir<=l+1) {
 11998           if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
 11999           return arr[k];
 12000         } else {
 12001           const unsigned long mid = (l+ir)>>1;
 12002           cimg::swap(arr[mid],arr[l+1]);
 12003           if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
 12004           if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
 12005           if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
 12006           unsigned long i = l+1, j = ir;
 12007           const T pivot = arr[l+1];
 12008           for (;;) {
 12009             do ++i; while (arr[i]<pivot);
 12010             do --j; while (arr[j]>pivot);
 12011             if (j<i) break;
 12012             cimg::swap(arr[i],arr[j]);
 12014           arr[l+1] = arr[j];
 12015           arr[j] = pivot;
 12016           if (j>=k) ir=j-1;
 12017           if (j<=k) l=i;
 12020       return 0;
 12023     //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
 12024     CImg<T>& stats(const unsigned int variance_method=1) {
 12025       return get_stats(variance_method).transfer_to(*this);
 12028     CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
 12029       if (is_empty()) return CImg<Tfloat>();
 12030       const unsigned long siz = size();
 12031       const T *const odata = data;
 12032       const T *pm = odata, *pM = odata;
 12033       Tfloat S = 0, S2 = 0;
 12034       T m = *pm, M = m;
 12035       cimg_for(*this,ptr,T) {
 12036         const T val = *ptr;
 12037         const Tfloat fval = (Tfloat)val;
 12038         if (val<m) { m = val; pm = ptr; }
 12039         if (val>M) { M = val; pM = ptr; }
 12040         S+=fval;
 12041         S2+=fval*fval;
 12043       const Tfloat
 12044         mean_value = S/siz,
 12045         _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
 12046         (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
 12047          variance(variance_method)),
 12048         variance_value = _variance_value>0?_variance_value:0;
 12049       int
 12050         xm = 0, ym = 0, zm = 0, vm = 0,
 12051         xM = 0, yM = 0, zM = 0, vM = 0;
 12052       contains(*pm,xm,ym,zm,vm);
 12053       contains(*pM,xM,yM,zM,vM);
 12054       return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
 12055                                      (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
 12056                                      (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
 12059     //! Return the median value of the image.
 12060     T median() const {
 12061       const unsigned int s = size();
 12062       const T res = kth_smallest(s>>1);
 12063       return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
 12066     //! Compute the MSE (Mean-Squared Error) between two images.
 12067     template<typename t>
 12068     Tfloat MSE(const CImg<t>& img) const {
 12069       if (img.size()!=size())
 12070         throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
 12071                                     pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
 12073       Tfloat vMSE = 0;
 12074       const t* ptr2 = img.end();
 12075       cimg_for(*this,ptr1,T) {
 12076         const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
 12077         vMSE += diff*diff;
 12079       vMSE/=img.size();
 12080       return vMSE;
 12083     //! Compute the PSNR between two images.
 12084     template<typename t>
 12085     Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
 12086       const Tfloat vMSE = (Tfloat)cimg_std::sqrt(MSE(img));
 12087       return (vMSE!=0)?(Tfloat)(20*cimg_std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
 12090     //! Return the trace of the image, viewed as a matrix.
 12091     Tfloat trace() const {
 12092       if (is_empty())
 12093         throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
 12094                                     pixel_type(),width,height,depth,dim,data);
 12095       Tfloat res = 0;
 12096       cimg_forX(*this,k) res+=(*this)(k,k);
 12097       return res;
 12100     //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
 12101     template<typename t>
 12102     Tfloat dot(const CImg<t>& img) const {
 12103       if (is_empty())
 12104         throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
 12105                                     pixel_type(),width,height,depth,dim,data);
 12106       if (!img)
 12107         throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
 12108                                     pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
 12109       const unsigned long nb = cimg::min(size(),img.size());
 12110       Tfloat res = 0;
 12111       for (unsigned long off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
 12112       return res;
 12115     //! Return the determinant of the image, viewed as a matrix.
 12116     Tfloat det() const {
 12117       if (is_empty() || width!=height || depth!=1 || dim!=1)
 12118         throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
 12119                                     pixel_type(),width,height,depth,dim,data);
 12120       switch (width) {
 12121       case 1 : return (Tfloat)((*this)(0,0));
 12122       case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
 12123       case 3 : {
 12124         const Tfloat
 12125           a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
 12126           b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
 12127           c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
 12128         return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
 12130       default : {
 12131         CImg<Tfloat> lu(*this);
 12132         CImg<uintT> indx;
 12133         bool d;
 12134         lu._LU(indx,d);
 12135         Tfloat res = d?(Tfloat)1:(Tfloat)-1;
 12136         cimg_forX(lu,i) res*=lu(i,i);
 12137         return res;
 12140       return 0;
 12143     //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
 12144     Tfloat norm(const int norm_type=2) const {
 12145       if (is_empty())
 12146         throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
 12147                                     pixel_type(),width,height,depth,dim,data);
 12148       Tfloat res = 0;
 12149       switch (norm_type) {
 12150       case -1 : {
 12151         cimg_foroff(*this,off) {
 12152           const Tfloat tmp = cimg::abs((Tfloat)data[off]);
 12153           if (tmp>res) res = tmp;
 12155         return res;
 12156       } break;
 12157       case 1 : {
 12158         cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
 12159         return res;
 12160       } break;
 12161       case 2 : return (Tfloat)cimg_std::sqrt(dot(*this)); break;
 12162       default :
 12163         throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
 12164                                     pixel_type(),norm_type);
 12166       return 0;
 12169     //! Return a C-string containing the values of the instance image.
 12170     CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
 12171       if (is_empty()) return CImg<charT>(1,1,1,1,0);
 12172       const unsigned int siz = (unsigned int)size();
 12173       CImgList<charT> items;
 12174       char item[256] = { 0 };
 12175       const T *ptrs = ptr();
 12176       for (unsigned int off = 0; off<siz-1; ++off) {
 12177         cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
 12178         const int l = cimg::strlen(item);
 12179         items.insert(CImg<charT>(item,l+1));
 12180         items[items.size-1](l) = separator;
 12182       cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
 12183       items.insert(CImg<charT>(item,cimg::strlen(item)+1));
 12184       CImg<ucharT> res = items.get_append('x');
 12185       if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
 12186       return res;
 12189     //! Display informations about the image on the standard error output.
 12190     /**
 12191        \param title Name for the considered image (optional).
 12192        \param display_stats Compute and display image statistics (optional).
 12193     **/
 12194     const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
 12195       int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
 12196       static CImg<doubleT> st;
 12197       if (!is_empty() && display_stats) {
 12198         st = get_stats();
 12199         xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
 12200         xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
 12202       const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
 12203       const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
 12204       char ntitle[64] = { 0 };
 12205       if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 12206       cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
 12207                    title?title:ntitle,(void*)this,width,height,depth,dim,
 12208                    mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 12209                    mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 12210                    pixel_type(),(void*)data,is_shared?"shared":"not shared");
 12211       if (!is_empty()) cimg_foroff(*this,off) {
 12212         cimg_std::fprintf(cimg_stdout,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
 12213         if (off!=siz1) cimg_std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
 12214         if (off==7 && siz>16) { off = siz1-8; if (off!=7) cimg_std::fprintf(cimg_stdout,"... "); }
 12216       if (!is_empty() && display_stats)
 12217         cimg_std::fprintf(cimg_stdout," ], min = %g, max = %g, mean = %g, std = %g, coords(min) = (%u,%u,%u,%u), coords(max) = (%u,%u,%u,%u).\n",
 12218                      st[0],st[1],st[2],cimg_std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
 12219       else cimg_std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
 12220       return *this;
 12223     //@}
 12224     //------------------------------------------
 12225     //
 12226     //! \name Arithmetic and Boolean Operators
 12227     //@{
 12228     //------------------------------------------
 12230     //! Assignment operator.
 12231     /**
 12232        This operator assigns a copy of the input image \p img to the current instance image.
 12233        \param img The input image to copy.
 12234        \remark
 12235        - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
 12236     **/
 12237     template<typename t>
 12238     CImg<T>& operator=(const CImg<t>& img) {
 12239       return assign(img);
 12242     CImg<T>& operator=(const CImg<T>& img) {
 12243       return assign(img);
 12246     //! Assign values of a C-array to the instance image.
 12247     /**
 12248        \param buf Pointer to a C-style array having a size of (at least) <tt>this->size()</tt>.
 12250        - Replace pixel values by the content of the array \c buf.
 12251        - Warning : the value types in the array and in the image must be the same.
 12253        \par example:
 12254        \code
 12255        float tab[4*4] = { 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16 };  // Define a 4x4 matrix in C-style.
 12256        CImg<float> matrice(4,4);                                        // Define a 4x4 greyscale image.
 12257        matrice = tab;                                                   // Fill the image by the values in tab.
 12258        \endcode
 12259     **/
 12260     CImg<T>& operator=(const T *buf) {
 12261       return assign(buf,width,height,depth,dim);
 12264     //! Assign a value to each image pixel of the instance image.
 12265     CImg<T>& operator=(const T val) {
 12266       return fill(val);
 12269     //! Operator+
 12270     /**
 12271        \remark
 12272        - This operator can be used to get a non-shared copy of an image.
 12273     **/
 12274     CImg<T> operator+() const {
 12275       return CImg<T>(*this,false);
 12278     //! Operator+=;
 12279 #ifdef cimg_use_visualcpp6
 12280     CImg<T>& operator+=(const T val)
 12281 #else
 12282     template<typename t>
 12283     CImg<T>& operator+=(const t val)
 12284 #endif
 12286       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
 12287       return *this;
 12290     //! Operator+=
 12291     template<typename t>
 12292     CImg<T>& operator+=(const CImg<t>& img) {
 12293       if (is_overlapped(img)) return *this+=+img;
 12294       const unsigned int smin = cimg::min(size(),img.size());
 12295       t *ptrs = img.data + smin;
 12296       for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
 12297       return *this;
 12300     //! Operator++ (prefix)
 12301     CImg<T>& operator++() {
 12302       cimg_for(*this,ptr,T) ++(*ptr);
 12303       return *this;
 12306     //! Operator++ (postfix)
 12307     CImg<T> operator++(int) {
 12308       const CImg<T> copy(*this,false);
 12309       ++*this;
 12310       return copy;
 12313     //! Operator-.
 12314     CImg<T> operator-() const {
 12315       return CImg<T>(width,height,depth,dim,0)-=*this;
 12318     //! Operator-=.
 12319 #ifdef cimg_use_visualcpp6
 12320     CImg<T>& operator-=(const T val)
 12321 #else
 12322     template<typename t>
 12323     CImg<T>& operator-=(const t val)
 12324 #endif
 12326       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
 12327       return *this;
 12330     //! Operator-=.
 12331     template<typename t>
 12332     CImg<T>& operator-=(const CImg<t>& img) {
 12333       if (is_overlapped(img)) return *this-=+img;
 12334       const unsigned int smin = cimg::min(size(),img.size());
 12335       t *ptrs = img.data+smin;
 12336       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
 12337       return *this;
 12340     //! Operator-- (prefix).
 12341     CImg<T>& operator--() {
 12342       cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
 12343       return *this;
 12346     //! Operator-- (postfix).
 12347     CImg<T> operator--(int) {
 12348       CImg<T> copy(*this,false);
 12349       --*this;
 12350       return copy;
 12353     //! Operator*=.
 12354 #ifdef cimg_use_visualcpp6
 12355     CImg<T>& operator*=(const double val)
 12356 #else
 12357     template<typename t>
 12358     CImg<T>& operator*=(const t val)
 12359 #endif
 12361       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
 12362       return *this;
 12365     //! Operator*=.
 12366     template<typename t>
 12367     CImg<T>& operator*=(const CImg<t>& img) {
 12368       return ((*this)*img).transfer_to(*this);
 12371     //! Operator/=.
 12372 #ifdef cimg_use_visualcpp6
 12373     CImg<T>& operator/=(const double val)
 12374 #else
 12375     template<typename t>
 12376     CImg<T>& operator/=(const t val)
 12377 #endif
 12379       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
 12380       return *this;
 12383     //! Operator/=.
 12384     template<typename t>
 12385     CImg<T>& operator/=(const CImg<t>& img) {
 12386       return assign(*this*img.get_invert());
 12389     //! Modulo.
 12390     template<typename t>
 12391     CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
 12392       typedef typename cimg::superset<T,t>::type Tt;
 12393       return CImg<Tt>(*this,false)%=img;
 12396     //! Modulo.
 12397     CImg<T> operator%(const T val) const {
 12398       return (+*this)%=val;
 12401     //! In-place modulo.
 12402     CImg<T>& operator%=(const T val) {
 12403       cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
 12404       return *this;
 12407     //! In-place modulo.
 12408     template<typename t>
 12409     CImg<T>& operator%=(const CImg<t>& img) {
 12410       if (is_overlapped(img)) return *this%=+img;
 12411       typedef typename cimg::superset<T,t>::type Tt;
 12412       const unsigned int smin = cimg::min(size(),img.size());
 12413       const t *ptrs = img.data + smin;
 12414       for (T *ptrd = data + smin; ptrd>data; ) {
 12415         T& val = *(--ptrd);
 12416         val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
 12418       return *this;
 12421     //! Bitwise AND.
 12422     template<typename t>
 12423     CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
 12424       typedef typename cimg::superset<T,t>::type Tt;
 12425       return CImg<Tt>(*this,false)&=img;
 12428     //! Bitwise AND.
 12429     CImg<T> operator&(const T val) const {
 12430       return (+*this)&=val;
 12433     //! In-place bitwise AND.
 12434     template<typename t>
 12435     CImg<T>& operator&=(const CImg<t>& img) {
 12436       if (is_overlapped(img)) return *this&=+img;
 12437       const unsigned int smin = cimg::min(size(),img.size());
 12438       const t *ptrs = img.data + smin;
 12439       for (T *ptrd = data + smin; ptrd>data; ) {
 12440         T& val = *(--ptrd);
 12441         val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
 12443       return *this;
 12446     //! In-place bitwise AND.
 12447     CImg<T>& operator&=(const T val) {
 12448       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
 12449       return *this;
 12452     //! Bitwise OR.
 12453     template<typename t>
 12454     CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
 12455       typedef typename cimg::superset<T,t>::type Tt;
 12456       return CImg<Tt>(*this,false)|=img;
 12459     //! Bitwise OR.
 12460     CImg<T> operator|(const T val) const {
 12461       return (+*this)|=val;
 12464     //! In-place bitwise OR.
 12465     template<typename t>
 12466     CImg<T>& operator|=(const CImg<t>& img) {
 12467       if (is_overlapped(img)) return *this|=+img;
 12468       const unsigned int smin = cimg::min(size(),img.size());
 12469       const t *ptrs = img.data + smin;
 12470       for (T *ptrd = data + smin; ptrd>data; ) {
 12471         T& val = *(--ptrd);
 12472         val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
 12474       return *this;
 12477     //! In-place bitwise OR.
 12478     CImg<T>& operator|=(const T val) {
 12479       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
 12480       return *this;
 12483     //! Bitwise XOR.
 12484     template<typename t>
 12485     CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
 12486       typedef typename cimg::superset<T,t>::type Tt;
 12487       return CImg<Tt>(*this,false)^=img;
 12490     //! Bitwise XOR.
 12491     CImg<T> operator^(const T val) const {
 12492       return (+*this)^=val;
 12495     //! In-place bitwise XOR.
 12496     template<typename t>
 12497     CImg<T>& operator^=(const CImg<t>& img) {
 12498       if (is_overlapped(img)) return *this^=+img;
 12499       const unsigned int smin = cimg::min(size(),img.size());
 12500       const t *ptrs = img.data + smin;
 12501       for (T *ptrd = data+smin; ptrd>data; ) {
 12502         T& val = *(--ptrd);
 12503         val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
 12505       return *this;
 12508     //! In-place bitwise XOR.
 12509     CImg<T>& operator^=(const T val) {
 12510       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
 12511       return *this;
 12514     //! Bitwise NOT.
 12515     CImg<T> operator~() const {
 12516       CImg<T> res(width,height,depth,dim);
 12517       const T *ptrs = end();
 12518       cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
 12519       return res;
 12522     //! Bitwise left shift.
 12523     CImg<T>& operator<<=(const int n) {
 12524       cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
 12525       return *this;
 12528     //! Bitwise left shift.
 12529     CImg<T> operator<<(const int n) const {
 12530       return (+*this)<<=n;
 12533     //! Bitwise right shift.
 12534     CImg<T>& operator>>=(const int n) {
 12535       cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
 12536       return *this;
 12539     //! Bitwise right shift.
 12540     CImg<T> operator>>(const int n) const {
 12541       return (+*this)>>=n;
 12544     //! Boolean equality.
 12545     template<typename t>
 12546     bool operator==(const CImg<t>& img) const {
 12547       const unsigned int siz = size();
 12548       bool vequal = true;
 12549       if (siz!=img.size()) return false;
 12550       t *ptrs = img.data + siz;
 12551       for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
 12552       return vequal;
 12555     //! Boolean difference.
 12556     template<typename t>
 12557     bool operator!=(const CImg<t>& img) const {
 12558       return !((*this)==img);
 12561     //! Return a list of two images { *this, img }.
 12562     template<typename t>
 12563     CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
 12564       typedef typename cimg::superset<T,t>::type Tt;
 12565       return CImgList<Tt>(*this,img);
 12568     //! Return a copy of \p list, where image *this has been inserted at first position.
 12569     template<typename t>
 12570     CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
 12571       typedef typename cimg::superset<T,t>::type Tt;
 12572       return CImgList<Tt>(list).insert(*this,0);
 12575     //! Return a list of two images { *this, img }.
 12576     template<typename t>
 12577     CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
 12578       return (*this)<<img;
 12581     //! Insert an image into the begining of an image list.
 12582     template<typename t>
 12583     CImgList<t>& operator>>(const CImgList<t>& list) const {
 12584       return list.insert(*this,0);
 12587     //! Display an image into a CImgDisplay.
 12588     const CImg<T>& operator>>(CImgDisplay& disp) const {
 12589       return display(disp);
 12592     //@}
 12593     //---------------------------------------
 12594     //
 12595     //! \name Usual Mathematics Functions
 12596     //@{
 12597     //---------------------------------------
 12599     //! Apply a R->R function on all pixel values.
 12600     template<typename t>
 12601     CImg<T>& apply(t& func) {
 12602       cimg_for(*this,ptr,T) *ptr = func(*ptr);
 12603       return *this;
 12606     template<typename t>
 12607     CImg<T> get_apply(t& func) const {
 12608       return (+*this).apply(func);
 12611     //! Pointwise multiplication between two images.
 12612     template<typename t>
 12613     CImg<T>& mul(const CImg<t>& img) {
 12614       if (is_overlapped(img)) return mul(+img);
 12615       t *ptrs = img.data;
 12616       T *ptrf = data + cimg::min(size(),img.size());
 12617       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
 12618       return *this;
 12621     template<typename t>
 12622     CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
 12623       typedef typename cimg::superset<T,t>::type Tt;
 12624       return CImg<Tt>(*this,false).mul(img);
 12627     //! Pointwise division between two images.
 12628     template<typename t>
 12629     CImg<T>& div(const CImg<t>& img) {
 12630       if (is_overlapped(img)) return div(+img);
 12631       t *ptrs = img.data;
 12632       T *ptrf = data + cimg::min(size(),img.size());
 12633       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
 12634       return *this;
 12637     template<typename t>
 12638     CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
 12639       typedef typename cimg::superset<T,t>::type Tt;
 12640       return CImg<Tt>(*this,false).div(img);
 12643     //! Pointwise max operator between two images.
 12644     template<typename t>
 12645     CImg<T>& max(const CImg<t>& img) {
 12646       if (is_overlapped(img)) return max(+img);
 12647       t *ptrs = img.data;
 12648       T *ptrf = data + cimg::min(size(),img.size());
 12649       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
 12650       return *this;
 12653     template<typename t>
 12654     CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
 12655       typedef typename cimg::superset<T,t>::type Tt;
 12656       return CImg<Tt>(*this,false).max(img);
 12659     //! Pointwise max operator between an image and a value.
 12660     CImg<T>& max(const T val) {
 12661       cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
 12662       return *this;
 12665     CImg<T> get_max(const T val) const {
 12666       return (+*this).max(val);
 12669     //! Pointwise min operator between two images.
 12670     template<typename t>
 12671     CImg<T>& min(const CImg<t>& img) {
 12672       if (is_overlapped(img)) return min(+img);
 12673       t *ptrs = img.data;
 12674       T *ptrf = data + cimg::min(size(),img.size());
 12675       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
 12676       return *this;
 12679     template<typename t>
 12680     CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
 12681       typedef typename cimg::superset<T,t>::type Tt;
 12682       return CImg<Tt>(*this,false).min(img);
 12685     //! Pointwise min operator between an image and a value.
 12686     CImg<T>& min(const T val) {
 12687       cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
 12688       return *this;
 12691     CImg<T> get_min(const T val) const {
 12692       return (+*this).min(val);
 12695     //! Compute the square value of each pixel.
 12696     CImg<T>& sqr() {
 12697       cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
 12698       return *this;
 12701     CImg<Tfloat> get_sqr() const {
 12702       return CImg<Tfloat>(*this,false).sqr();
 12705     //! Compute the square root of each pixel value.
 12706     CImg<T>& sqrt() {
 12707       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sqrt((double)(*ptr));
 12708       return *this;
 12711     CImg<Tfloat> get_sqrt() const {
 12712       return CImg<Tfloat>(*this,false).sqrt();
 12715     //! Compute the exponential of each pixel value.
 12716     CImg<T>& exp() {
 12717       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::exp((double)(*ptr));
 12718       return *this;
 12721     CImg<Tfloat> get_exp() const {
 12722       return CImg<Tfloat>(*this,false).exp();
 12725     //! Compute the log of each each pixel value.
 12726     CImg<T>& log() {
 12727       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log((double)(*ptr));
 12728       return *this;
 12731     CImg<Tfloat> get_log() const {
 12732       return CImg<Tfloat>(*this,false).log();
 12735     //! Compute the log10 of each each pixel value.
 12736     CImg<T>& log10() {
 12737       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log10((double)(*ptr));
 12738       return *this;
 12741     CImg<Tfloat> get_log10() const {
 12742       return CImg<Tfloat>(*this,false).log10();
 12745     //! Compute the power by p of each pixel value.
 12746     CImg<T>& pow(const double p) {
 12747       if (p==0) return fill(1);
 12748       if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)cimg_std::sqrt((double)val); } return *this; }
 12749       if (p==1) return *this;
 12750       if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
 12751       if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
 12752       if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
 12753       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::pow((double)(*ptr),p);
 12754       return *this;
 12757     CImg<Tfloat> get_pow(const double p) const {
 12758       return CImg<Tfloat>(*this,false).pow(p);
 12761     //! Compute the power of each pixel value.
 12762     template<typename t>
 12763     CImg<T>& pow(const CImg<t>& img) {
 12764       if (is_overlapped(img)) return pow(+img);
 12765       t *ptrs = img.data;
 12766       T *ptrf = data + cimg::min(size(),img.size());
 12767       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)cimg_std::pow((double)*ptrd,(double)(*(ptrs++)));
 12768       return *this;
 12771     template<typename t>
 12772     CImg<Tfloat> get_pow(const CImg<t>& img) const {
 12773       return CImg<Tfloat>(*this,false).pow(img);
 12776     //! Compute the absolute value of each pixel value.
 12777     CImg<T>& abs() {
 12778       cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
 12779       return *this;
 12782     CImg<Tfloat> get_abs() const {
 12783       return CImg<Tfloat>(*this,false).abs();
 12786     //! Compute the cosinus of each pixel value.
 12787     CImg<T>& cos() {
 12788       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::cos((double)(*ptr));
 12789       return *this;
 12792     CImg<Tfloat> get_cos() const {
 12793       return CImg<Tfloat>(*this,false).cos();
 12796     //! Compute the sinus of each pixel value.
 12797     CImg<T>& sin() {
 12798       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sin((double)(*ptr));
 12799       return *this;
 12802     CImg<Tfloat> get_sin() const {
 12803       return CImg<Tfloat>(*this,false).sin();
 12806     //! Compute the tangent of each pixel.
 12807     CImg<T>& tan() {
 12808       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::tan((double)(*ptr));
 12809       return *this;
 12812     CImg<Tfloat> get_tan() const {
 12813       return CImg<Tfloat>(*this,false).tan();
 12816     //! Compute the arc-cosine of each pixel value.
 12817     CImg<T>& acos() {
 12818       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::acos((double)(*ptr));
 12819       return *this;
 12822     CImg<Tfloat> get_acos() const {
 12823       return CImg<Tfloat>(*this,false).acos();
 12826     //! Compute the arc-sinus of each pixel value.
 12827     CImg<T>& asin() {
 12828       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::asin((double)(*ptr));
 12829       return *this;
 12832     CImg<Tfloat> get_asin() const {
 12833       return CImg<Tfloat>(*this,false).asin();
 12836     //! Compute the arc-tangent of each pixel.
 12837     CImg<T>& atan() {
 12838       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::atan((double)(*ptr));
 12839       return *this;
 12842     CImg<Tfloat> get_atan() const {
 12843       return CImg<Tfloat>(*this,false).atan();
 12846     //! Compute image with rounded pixel values.
 12847     /**
 12848        \param x Rounding precision.
 12849        \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
 12850     **/
 12851     CImg<T>& round(const float x, const int rounding_type=0) {
 12852       cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
 12853       return *this;
 12856     CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
 12857       return (+*this).round(x,rounding_type);
 12860     //! Fill the instance image with random values between specified range.
 12861     CImg<T>& rand(const T val_min, const T val_max) {
 12862       const float delta = (float)val_max - (float)val_min;
 12863       cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
 12864       return *this;
 12867     CImg<T> get_rand(const T val_min, const T val_max) const {
 12868       return (+*this).rand(val_min,val_max);
 12871     //@}
 12872     //-----------------------------------
 12873     //
 12874     //! \name Usual Image Transformations
 12875     //@{
 12876     //-----------------------------------
 12878     //! Fill an image by a value \p val.
 12879     /**
 12880        \param val = fill value
 12881        \note All pixel values of the instance image will be initialized by \p val.
 12882     **/
 12883     CImg<T>& fill(const T val) {
 12884       if (is_empty()) return *this;
 12885       if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
 12886       else cimg_std::memset(data,(int)val,size()*sizeof(T));
 12887       return *this;
 12890     CImg<T> get_fill(const T val) const {
 12891       return CImg<T>(width,height,depth,dim).fill(val);
 12894     //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
 12895     CImg<T>& fill(const T val0, const T val1) {
 12896       if (is_empty()) return *this;
 12897       T *ptr, *ptr_end = end()-1;
 12898       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
 12899       if (ptr!=ptr_end+1) *(ptr++) = val0;
 12900       return *this;
 12903     CImg<T> get_fill(const T val0, const T val1) const {
 12904       return CImg<T>(width,height,depth,dim).fill(val0,val1);
 12907     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
 12908     CImg<T>& fill(const T val0, const T val1, const T val2) {
 12909       if (is_empty()) return *this;
 12910       T *ptr, *ptr_end = end()-2;
 12911       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
 12912       ptr_end+=2;
 12913       switch (ptr_end-ptr) {
 12914       case 2 : *(--ptr_end) = val1;
 12915       case 1 : *(--ptr_end) = val0;
 12917       return *this;
 12920     CImg<T> get_fill(const T val0, const T val1, const T val2) const {
 12921       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
 12924     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
 12925     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
 12926       if (is_empty()) return *this;
 12927       T *ptr, *ptr_end = end()-3;
 12928       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
 12929       ptr_end+=3;
 12930       switch (ptr_end-ptr) {
 12931       case 3 : *(--ptr_end) = val2;
 12932       case 2 : *(--ptr_end) = val1;
 12933       case 1 : *(--ptr_end) = val0;
 12935       return *this;
 12938     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
 12939       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
 12942     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
 12943     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
 12944       if (is_empty()) return *this;
 12945       T *ptr, *ptr_end = end()-4;
 12946       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
 12947       ptr_end+=4;
 12948       switch (ptr_end-ptr) {
 12949       case 4 : *(--ptr_end) = val3;
 12950       case 3 : *(--ptr_end) = val2;
 12951       case 2 : *(--ptr_end) = val1;
 12952       case 1 : *(--ptr_end) = val0;
 12954       return *this;
 12957     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
 12958       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
 12961     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
 12962     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
 12963       if (is_empty()) return *this;
 12964       T *ptr, *ptr_end = end()-5;
 12965       for (ptr = data; ptr<ptr_end; ) {
 12966         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 12968       ptr_end+=5;
 12969       switch (ptr_end-ptr) {
 12970       case 5 : *(--ptr_end) = val4;
 12971       case 4 : *(--ptr_end) = val3;
 12972       case 3 : *(--ptr_end) = val2;
 12973       case 2 : *(--ptr_end) = val1;
 12974       case 1 : *(--ptr_end) = val0;
 12976       return *this;
 12979     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
 12980       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
 12983     //! Fill sequentially pixel values.
 12984     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
 12985       if (is_empty()) return *this;
 12986       T *ptr, *ptr_end = end()-6;
 12987       for (ptr = data; ptr<ptr_end; ) {
 12988         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
 12990       ptr_end+=6;
 12991       switch (ptr_end-ptr) {
 12992       case 6 : *(--ptr_end) = val5;
 12993       case 5 : *(--ptr_end) = val4;
 12994       case 4 : *(--ptr_end) = val3;
 12995       case 3 : *(--ptr_end) = val2;
 12996       case 2 : *(--ptr_end) = val1;
 12997       case 1 : *(--ptr_end) = val0;
 12999       return *this;
 13002     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) const {
 13003       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
 13006     //! Fill sequentially pixel values.
 13007     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13008                   const T val7) {
 13009       if (is_empty()) return *this;
 13010       T *ptr, *ptr_end = end()-7;
 13011       for (ptr = data; ptr<ptr_end; ) {
 13012         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
 13013         *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
 13015       ptr_end+=7;
 13016       switch (ptr_end-ptr) {
 13017       case 7 : *(--ptr_end) = val6;
 13018       case 6 : *(--ptr_end) = val5;
 13019       case 5 : *(--ptr_end) = val4;
 13020       case 4 : *(--ptr_end) = val3;
 13021       case 3 : *(--ptr_end) = val2;
 13022       case 2 : *(--ptr_end) = val1;
 13023       case 1 : *(--ptr_end) = val0;
 13025       return *this;
 13028     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13029                      const T val7) const {
 13030       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
 13033     //! Fill sequentially pixel values.
 13034     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13035                   const T val7, const T val8) {
 13036       if (is_empty()) return *this;
 13037       T *ptr, *ptr_end = end()-8;
 13038       for (ptr = data; ptr<ptr_end; ) {
 13039         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
 13040         *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13041         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
 13043       ptr_end+=8;
 13044       switch (ptr_end-ptr) {
 13045       case 8 : *(--ptr_end) = val7;
 13046       case 7 : *(--ptr_end) = val6;
 13047       case 6 : *(--ptr_end) = val5;
 13048       case 5 : *(--ptr_end) = val4;
 13049       case 4 : *(--ptr_end) = val3;
 13050       case 3 : *(--ptr_end) = val2;
 13051       case 2 : *(--ptr_end) = val1;
 13052       case 1 : *(--ptr_end) = val0;
 13054       return *this;
 13057     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13058                      const T val7, const T val8) const {
 13059       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
 13062     //! Fill sequentially pixel values.
 13063     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13064                   const T val7, const T val8, const T val9) {
 13065       if (is_empty()) return *this;
 13066       T *ptr, *ptr_end = end()-9;
 13067       for (ptr = data; ptr<ptr_end; ) {
 13068         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
 13069         *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
 13071       ptr_end+=9;
 13072       switch (ptr_end-ptr) {
 13073       case 9 : *(--ptr_end) = val8;
 13074       case 8 : *(--ptr_end) = val7;
 13075       case 7 : *(--ptr_end) = val6;
 13076       case 6 : *(--ptr_end) = val5;
 13077       case 5 : *(--ptr_end) = val4;
 13078       case 4 : *(--ptr_end) = val3;
 13079       case 3 : *(--ptr_end) = val2;
 13080       case 2 : *(--ptr_end) = val1;
 13081       case 1 : *(--ptr_end) = val0;
 13083       return *this;
 13086     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13087                      const T val7, const T val8, const T val9) const {
 13088       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
 13091     //! Fill sequentially pixel values.
 13092     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13093                   const T val7, const T val8, const T val9, const T val10) {
 13094       if (is_empty()) return *this;
 13095       T *ptr, *ptr_end = end()-10;
 13096       for (ptr = data; ptr<ptr_end; ) {
 13097         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
 13098         *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
 13099         *(ptr++) = val10;
 13101       ptr_end+=10;
 13102       switch (ptr_end-ptr) {
 13103       case 10 : *(--ptr_end) = val9;
 13104       case 9 : *(--ptr_end) = val8;
 13105       case 8 : *(--ptr_end) = val7;
 13106       case 7 : *(--ptr_end) = val6;
 13107       case 6 : *(--ptr_end) = val5;
 13108       case 5 : *(--ptr_end) = val4;
 13109       case 4 : *(--ptr_end) = val3;
 13110       case 3 : *(--ptr_end) = val2;
 13111       case 2 : *(--ptr_end) = val1;
 13112       case 1 : *(--ptr_end) = val0;
 13114       return *this;
 13117     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13118                      const T val7, const T val8, const T val9, const T val10) const {
 13119       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
 13122     //! Fill sequentially pixel values.
 13123     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13124                   const T val7, const T val8, const T val9, const T val10, const T val11) {
 13125       if (is_empty()) return *this;
 13126       T *ptr, *ptr_end = end()-11;
 13127       for (ptr = data; ptr<ptr_end; ) {
 13128         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13129         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 13131       ptr_end+=11;
 13132       switch (ptr_end-ptr) {
 13133       case 11 : *(--ptr_end) = val10;
 13134       case 10 : *(--ptr_end) = val9;
 13135       case 9 : *(--ptr_end) = val8;
 13136       case 8 : *(--ptr_end) = val7;
 13137       case 7 : *(--ptr_end) = val6;
 13138       case 6 : *(--ptr_end) = val5;
 13139       case 5 : *(--ptr_end) = val4;
 13140       case 4 : *(--ptr_end) = val3;
 13141       case 3 : *(--ptr_end) = val2;
 13142       case 2 : *(--ptr_end) = val1;
 13143       case 1 : *(--ptr_end) = val0;
 13145       return *this;
 13148     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13149                      const T val7, const T val8, const T val9, const T val10, const T val11) const {
 13150       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
 13153     //! Fill sequentially pixel values.
 13154     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13155                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
 13156       if (is_empty()) return *this;
 13157       T *ptr, *ptr_end = end()-12;
 13158       for (ptr = data; ptr<ptr_end; ) {
 13159         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13160         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 13161         *(ptr++) = val12;
 13163       ptr_end+=12;
 13164       switch (ptr_end-ptr) {
 13165       case 12 : *(--ptr_end) = val11;
 13166       case 11 : *(--ptr_end) = val10;
 13167       case 10 : *(--ptr_end) = val9;
 13168       case 9 : *(--ptr_end) = val8;
 13169       case 8 : *(--ptr_end) = val7;
 13170       case 7 : *(--ptr_end) = val6;
 13171       case 6 : *(--ptr_end) = val5;
 13172       case 5 : *(--ptr_end) = val4;
 13173       case 4 : *(--ptr_end) = val3;
 13174       case 3 : *(--ptr_end) = val2;
 13175       case 2 : *(--ptr_end) = val1;
 13176       case 1 : *(--ptr_end) = val0;
 13178       return *this;
 13181     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13182                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
 13183       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
 13186     //! Fill sequentially pixel values.
 13187     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13188                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13189                   const T val13) {
 13190       if (is_empty()) return *this;
 13191       T *ptr, *ptr_end = end()-13;
 13192       for (ptr = data; ptr<ptr_end; ) {
 13193         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13194         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 13195         *(ptr++) = val12; *(ptr++) = val13;
 13197       ptr_end+=13;
 13198       switch (ptr_end-ptr) {
 13199       case 13 : *(--ptr_end) = val12;
 13200       case 12 : *(--ptr_end) = val11;
 13201       case 11 : *(--ptr_end) = val10;
 13202       case 10 : *(--ptr_end) = val9;
 13203       case 9 : *(--ptr_end) = val8;
 13204       case 8 : *(--ptr_end) = val7;
 13205       case 7 : *(--ptr_end) = val6;
 13206       case 6 : *(--ptr_end) = val5;
 13207       case 5 : *(--ptr_end) = val4;
 13208       case 4 : *(--ptr_end) = val3;
 13209       case 3 : *(--ptr_end) = val2;
 13210       case 2 : *(--ptr_end) = val1;
 13211       case 1 : *(--ptr_end) = val0;
 13213       return *this;
 13216     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13217                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13218                      const T val13) const {
 13219       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 13220                                                   val13);
 13223     //! Fill sequentially pixel values.
 13224     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13225                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13226                   const T val13, const T val14) {
 13227       if (is_empty()) return *this;
 13228       T *ptr, *ptr_end = end()-14;
 13229       for (ptr = data; ptr<ptr_end; ) {
 13230         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13231         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 13232         *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
 13234       ptr_end+=14;
 13235       switch (ptr_end-ptr) {
 13236       case 14 : *(--ptr_end) = val13;
 13237       case 13 : *(--ptr_end) = val12;
 13238       case 12 : *(--ptr_end) = val11;
 13239       case 11 : *(--ptr_end) = val10;
 13240       case 10 : *(--ptr_end) = val9;
 13241       case 9 : *(--ptr_end) = val8;
 13242       case 8 : *(--ptr_end) = val7;
 13243       case 7 : *(--ptr_end) = val6;
 13244       case 6 : *(--ptr_end) = val5;
 13245       case 5 : *(--ptr_end) = val4;
 13246       case 4 : *(--ptr_end) = val3;
 13247       case 3 : *(--ptr_end) = val2;
 13248       case 2 : *(--ptr_end) = val1;
 13249       case 1 : *(--ptr_end) = val0;
 13251       return *this;
 13254     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13255                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13256                      const T val13, const T val14) const {
 13257       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 13258                                                   val13,val14);
 13261     //! Fill sequentially pixel values.
 13262     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13263                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13264                   const T val13, const T val14, const T val15) {
 13265       if (is_empty()) return *this;
 13266       T *ptr, *ptr_end = end()-15;
 13267       for (ptr = data; ptr<ptr_end; ) {
 13268         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 13269         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 13270         *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
 13272       ptr_end+=15;
 13273       switch (ptr_end-ptr) {
 13274       case 15 : *(--ptr_end) = val14;
 13275       case 14 : *(--ptr_end) = val13;
 13276       case 13 : *(--ptr_end) = val12;
 13277       case 12 : *(--ptr_end) = val11;
 13278       case 11 : *(--ptr_end) = val10;
 13279       case 10 : *(--ptr_end) = val9;
 13280       case 9 : *(--ptr_end) = val8;
 13281       case 8 : *(--ptr_end) = val7;
 13282       case 7 : *(--ptr_end) = val6;
 13283       case 6 : *(--ptr_end) = val5;
 13284       case 5 : *(--ptr_end) = val4;
 13285       case 4 : *(--ptr_end) = val3;
 13286       case 3 : *(--ptr_end) = val2;
 13287       case 2 : *(--ptr_end) = val1;
 13288       case 1 : *(--ptr_end) = val0;
 13290       return *this;
 13293     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 13294                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 13295                      const T val13, const T val14, const T val15) const {
 13296       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 13297                                                   val13,val14,val15);
 13300     //! Fill image values according to the values found in the specified string.
 13301     CImg<T>& fill(const char *const values, const bool repeat_pattern) {
 13302       if (is_empty() || !values) return *this;
 13303       T *ptrd = data, *ptr_end = data + size();
 13304       const char *nvalues = values;
 13305       const unsigned int siz = size();
 13306       char cval[64] = { 0 },  sep = 0;
 13307       int err = 0; double val = 0; unsigned int nb = 0;
 13308       while ((err=cimg_std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%c",cval,&sep))>0 &&
 13309              cimg_std::sscanf(cval,"%lf",&val)>0 && nb<siz) {
 13310         nvalues += cimg::strlen(cval);
 13311         *(ptrd++) = (T)val;
 13312         ++nb;
 13313         if (err!=2) break; else ++nvalues;
 13315       if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
 13316       return *this;
 13319     CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
 13320       return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
 13323     //! Fill image values according to the values found in the specified image.
 13324     template<typename t>
 13325     CImg<T>& fill(const CImg<t>& values, const bool repeat_pattern=true) {
 13326       if (is_empty() || !values) return *this;
 13327       T *ptrd = data, *ptrd_end = ptrd + size();
 13328       for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
 13329       if (repeat_pattern && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
 13330       return *this;
 13333     template<typename t>
 13334     CImg<T> get_fill(const CImg<t>& values, const bool repeat_pattern=true) const {
 13335       return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
 13338     //! Fill image values along the X-axis at the specified pixel position (y,z,v).
 13339     CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
 13340 #define _cimg_fill1(x,y,z,v,off,siz,t) { \
 13341     va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
 13342     for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
 13343     va_end(ap); }
 13344       if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
 13345       return *this;
 13348     CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
 13349       if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
 13350       return *this;
 13353     //! Fill image values along the Y-axis at the specified pixel position (x,z,v).
 13354     CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
 13355       if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
 13356       return *this;
 13359     CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
 13360       if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
 13361       return *this;
 13364     //! Fill image values along the Z-axis at the specified pixel position (x,y,v).
 13365     CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
 13366       const unsigned int wh = width*height;
 13367       if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
 13368       return *this;
 13371     CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
 13372       const unsigned int wh = width*height;
 13373       if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
 13374       return *this;
 13377     //! Fill image values along the V-axis at the specified pixel position (x,y,z).
 13378     CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
 13379       const unsigned int whz = width*height*depth;
 13380       if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
 13381       return *this;
 13384     CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
 13385       const unsigned int whz = width*height*depth;
 13386       if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
 13387       return *this;
 13390     //! Linear normalization of the pixel values between \a a and \a b.
 13391     CImg<T>& normalize(const T a, const T b) {
 13392       if (is_empty()) return *this;
 13393       const T na = a<b?a:b, nb = a<b?b:a;
 13394       T m, M = maxmin(m);
 13395       const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
 13396       if (m==M) return fill(0);
 13397       if (m!=na || M!=nb) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(nb-na)+na);
 13398       return *this;
 13401     CImg<T> get_normalize(const T a, const T b) const {
 13402       return (+*this).normalize(a,b);
 13405     //! Cut pixel values between \a a and \a b.
 13406     CImg<T>& cut(const T a, const T b) {
 13407       if (is_empty()) return *this;
 13408       const T na = a<b?a:b, nb = a<b?b:a;
 13409       cimg_for(*this,ptr,T) *ptr = (*ptr<na)?na:((*ptr>nb)?nb:*ptr);
 13410       return *this;
 13413     CImg<T> get_cut(const T a, const T b) const {
 13414       return (+*this).cut(a,b);
 13417     //! Quantize pixel values into \n levels.
 13418     CImg<T>& quantize(const unsigned int n, const bool keep_range=true) {
 13419       if (is_empty()) return *this;
 13420       if (!n)
 13421         throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
 13422                                     pixel_type());
 13423       Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
 13424       if (range>0) {
 13425         if (keep_range) cimg_for(*this,ptr,T) {
 13426           const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 13427           *ptr = (T)(m + cimg::min(val,n-1)*range/n);
 13428         } else cimg_for(*this,ptr,T) {
 13429           const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 13430           *ptr = (T)cimg::min(val,n-1);
 13433       return *this;
 13436     CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
 13437       return (+*this).quantize(n,keep_range);
 13440     //! Threshold the image.
 13441     /**
 13442        \param value Threshold value.
 13443        \param soft Enable soft thresholding.
 13444        \param strict Tells if the threshold is strict.
 13445     **/
 13446     CImg<T>& threshold(const T value, const bool soft=false, const bool strict=false) {
 13447       if (is_empty()) return *this;
 13448       if (strict) {
 13449         if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>value?(T)(v-value):v<-value?(T)(v+value):(T)0; }
 13450         else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
 13451       } else {
 13452         if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-value?(T)(v+value):(T)0; }
 13453         else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
 13455       return *this;
 13458     CImg<T> get_threshold(const T value, const bool soft=false, const bool strict=false) const {
 13459       return (+*this).threshold(value,soft,strict);
 13462     //! Rotate an image.
 13463     /**
 13464        \param angle = rotation angle (in degrees).
 13465        \param cond = rotation type. can be :
 13466        - 0 = zero-value at borders
 13467        - 1 = nearest pixel.
 13468        - 2 = Fourier style.
 13469        \note Returned image will probably have a different size than the instance image *this.
 13470     **/
 13471     CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
 13472       return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
 13475     CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
 13476       if (is_empty()) return *this;
 13477       CImg<T> dest;
 13478       const float nangle = cimg::mod(angle,360.0f);
 13479       if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
 13480         const int wm1 = dimx()-1, hm1 = dimy()-1;
 13481         const int iangle = (int)nangle/90;
 13482         switch (iangle) {
 13483         case 1 : {
 13484           dest.assign(height,width,depth,dim);
 13485           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
 13486         } break;
 13487         case 2 : {
 13488           dest.assign(width,height,depth,dim);
 13489           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
 13490         } break;
 13491         case 3 : {
 13492           dest.assign(height,width,depth,dim);
 13493           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
 13494         } break;
 13495         default :
 13496           return *this;
 13498       } else { // generic version
 13499         const float
 13500           rad = (float)(nangle*cimg::valuePI/180.0),
 13501           ca = (float)cimg_std::cos(rad),
 13502           sa = (float)cimg_std::sin(rad),
 13503           ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
 13504           vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
 13505           w2 = 0.5f*width, h2 = 0.5f*height,
 13506           dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
 13507         dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
 13508         switch (border_conditions) {
 13509         case 0 : {
 13510           switch (interpolation) {
 13511           case 2 : {
 13512             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13513               dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
 13514           } break;
 13515           case 1 : {
 13516             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13517               dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
 13518           } break;
 13519           default : {
 13520             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13521               dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0);
 13524         } break;
 13525         case 1 : {
 13526           switch (interpolation) {
 13527           case 2 :
 13528             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13529               dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
 13530             break;
 13531           case 1 :
 13532             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13533               dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
 13534             break;
 13535           default :
 13536             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13537               dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
 13539         } break;
 13540         case 2 : {
 13541           switch (interpolation) {
 13542           case 2 :
 13543             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13544               dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
 13545                                             cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
 13546             break;
 13547           case 1 :
 13548             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13549               dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
 13550                                              cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
 13551             break;
 13552           default :
 13553             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 13554               dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
 13555                                       cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
 13557         } break;
 13558         default :
 13559           throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid border conditions %d (should be 0,1 or 2).",
 13560                                       pixel_type(),border_conditions);
 13563       return dest;
 13566     //! Rotate an image around a center point (\c cx,\c cy).
 13567     /**
 13568        \param angle = rotation angle (in degrees).
 13569        \param cx = X-coordinate of the rotation center.
 13570        \param cy = Y-coordinate of the rotation center.
 13571        \param zoom = zoom.
 13572        \param cond = rotation type. can be :
 13573        - 0 = zero-value at borders
 13574        - 1 = repeat image at borders
 13575        - 2 = zero-value at borders and linear interpolation
 13576     **/
 13577     CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
 13578                     const unsigned int border_conditions=3, const unsigned int interpolation=1) {
 13579       return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
 13582     CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
 13583                        const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
 13584       if (interpolation>2)
 13585         throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
 13586                                     pixel_type(),interpolation);
 13587       if (is_empty()) return *this;
 13588       CImg<T> dest(width,height,depth,dim);
 13589       const float nangle = cimg::mod(angle,360.0f);
 13590       if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
 13591         const int iangle = (int)nangle/90;
 13592         switch (iangle) {
 13593         case 1 : {
 13594           dest.fill(0);
 13595           const unsigned int
 13596             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
 13597             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
 13598             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
 13599             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
 13600           cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
 13601             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
 13602         } break;
 13603         case 2 : {
 13604           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
 13605         } break;
 13606         case 3 : {
 13607           dest.fill(0);
 13608           const unsigned int
 13609             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
 13610             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
 13611             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
 13612             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
 13613           cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
 13614             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
 13615         } break;
 13616         default :
 13617           return *this;
 13619       } else {
 13620         const float
 13621           rad = (float)((nangle*cimg::valuePI)/180.0),
 13622           ca = (float)cimg_std::cos(rad)/zoom,
 13623           sa = (float)cimg_std::sin(rad)/zoom;
 13624         switch (border_conditions) { // generic version
 13625         case 0 : {
 13626           switch (interpolation) {
 13627           case 2 : {
 13628             cimg_forXY(dest,x,y)
 13629               cimg_forZV(*this,z,v)
 13630               dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
 13631           } break;
 13632           case 1 : {
 13633             cimg_forXY(dest,x,y)
 13634               cimg_forZV(*this,z,v)
 13635               dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
 13636           } break;
 13637           default : {
 13638             cimg_forXY(dest,x,y)
 13639               cimg_forZV(*this,z,v)
 13640               dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0);
 13643         } break;
 13644         case 1 : {
 13645           switch (interpolation) {
 13646           case 2 : {
 13647             cimg_forXY(dest,x,y)
 13648               cimg_forZV(*this,z,v)
 13649               dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
 13650             } break;
 13651           case 1 : {
 13652             cimg_forXY(dest,x,y)
 13653               cimg_forZV(*this,z,v)
 13654               dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
 13655           } break;
 13656           default : {
 13657             cimg_forXY(dest,x,y)
 13658               cimg_forZV(*this,z,v)
 13659               dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
 13662         } break;
 13663         case 2 : {
 13664           switch (interpolation) {
 13665           case 2 : {
 13666             cimg_forXY(dest,x,y)
 13667               cimg_forZV(*this,z,v)
 13668               dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
 13669                                             cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
 13670             } break;
 13671           case 1 : {
 13672             cimg_forXY(dest,x,y)
 13673               cimg_forZV(*this,z,v)
 13674               dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
 13675                                              cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
 13676           } break;
 13677           default : {
 13678             cimg_forXY(dest,x,y)
 13679               cimg_forZV(*this,z,v)
 13680               dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
 13681                                       cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
 13684         } break;
 13685         default :
 13686           throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
 13687                                       pixel_type(),border_conditions);
 13690       return dest;
 13693     //! Resize an image.
 13694     /**
 13695        \param pdx Number of columns (new size along the X-axis).
 13696        \param pdy Number of rows (new size along the Y-axis).
 13697        \param pdz Number of slices (new size along the Z-axis).
 13698        \param pdv Number of vector-channels (new size along the V-axis).
 13699        \param interpolation_type Method of interpolation :
 13700        - -1 = no interpolation : raw memory resizing.
 13701        - 0 = no interpolation : additional space is filled according to \p border_condition.
 13702        - 1 = bloc interpolation (nearest point).
 13703        - 2 = moving average interpolation.
 13704        - 3 = linear interpolation.
 13705        - 4 = grid interpolation.
 13706        - 5 = bi-cubic interpolation.
 13707        \param border_condition Border condition type.
 13708        \param center Set centering type (only if \p interpolation_type=0).
 13709        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 13710     **/
 13711     CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 13712                     const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
 13713       if (!pdx || !pdy || !pdz || !pdv) return assign();
 13714       const unsigned int
 13715         tdx = pdx<0?-pdx*width/100:pdx,
 13716         tdy = pdy<0?-pdy*height/100:pdy,
 13717         tdz = pdz<0?-pdz*depth/100:pdz,
 13718         tdv = pdv<0?-pdv*dim/100:pdv,
 13719         dx = tdx?tdx:1,
 13720         dy = tdy?tdy:1,
 13721         dz = tdz?tdz:1,
 13722         dv = tdv?tdv:1;
 13723       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
 13724       if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
 13725         width = dx; height = dy; depth = dz; dim = dv;
 13726         return *this;
 13728       return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
 13731     CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 13732                        const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
 13733       if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
 13734       const unsigned int
 13735         tdx = pdx<0?-pdx*width/100:pdx,
 13736         tdy = pdy<0?-pdy*height/100:pdy,
 13737         tdz = pdz<0?-pdz*depth/100:pdz,
 13738         tdv = pdv<0?-pdv*dim/100:pdv,
 13739         dx = tdx?tdx:1,
 13740         dy = tdy?tdy:1,
 13741         dz = tdz?tdz:1,
 13742         dv = tdv?tdv:1;
 13743       if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
 13744       if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
 13746       CImg<T> res;
 13748       switch (interpolation_type) {
 13749       case -1 : // Raw resizing
 13750         cimg_std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
 13751         break;
 13753       case 0 :  { // No interpolation
 13754         const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
 13755         res.assign(dx,dy,dz,dv);
 13756         switch (border_condition) {
 13757         case 1 : {
 13758           if (center) {
 13759             const int
 13760               x0 = (res.dimx()-dimx())/2,
 13761               y0 = (res.dimy()-dimy())/2,
 13762               z0 = (res.dimz()-dimz())/2,
 13763               v0 = (res.dimv()-dimv())/2,
 13764               x1 = x0 + (int)bx,
 13765               y1 = y0 + (int)by,
 13766               z1 = z0 + (int)bz,
 13767               v1 = v0 + (int)bv;
 13768             res.draw_image(x0,y0,z0,v0,*this);
 13769             cimg_for_outXYZV(res,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) res(x,y,z,v) = _atXYZV(x-x0,y-y0,z-z0,v-v0);
 13770           } else {
 13771             res.draw_image(*this);
 13772             cimg_for_outXYZV(res,0,0,0,0,bx,by,bz,bv,x,y,z,v) res(x,y,z,v) = _atXYZV(x,y,z,v);
 13774           } break;
 13775         case 2 : {
 13776           int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
 13777           if (center) {
 13778             const int
 13779               x0 = (res.dimx()-dimx())/2,
 13780               y0 = (res.dimy()-dimy())/2,
 13781               z0 = (res.dimz()-dimz())/2,
 13782               v0 = (res.dimv()-dimv())/2;
 13783             nx0 = x0>0?x0-(1+x0/width)*width:x0;
 13784             ny0 = y0>0?y0-(1+y0/height)*height:y0;
 13785             nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
 13786             nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
 13788           for (int k = nv0; k<(int)dv; k+=dimv())
 13789             for (int z = nz0; z<(int)dz; z+=dimz())
 13790               for (int y = ny0; y<(int)dy; y+=dimy())
 13791                 for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
 13792           } break;
 13793         default : {
 13794           res.fill(0);
 13795           if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
 13796           else res.draw_image(*this);
 13799       } break;
 13801       case 1 : { // Nearest-neighbor interpolation
 13802         res.assign(dx,dy,dz,dv);
 13803         unsigned int
 13804           *const offx = new unsigned int[dx],
 13805           *const offy = new unsigned int[dy+1],
 13806           *const offz = new unsigned int[dz+1],
 13807           *const offv = new unsigned int[dv+1],
 13808           *poffx, *poffy, *poffz, *poffv,
 13809           curr, old;
 13810         const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
 13811         poffx = offx; curr = 0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }}
 13812         poffy = offy; curr = 0; { cimg_forY(res,y) { old=curr; curr=(y+1)*height/dy; *(poffy++) = width*((unsigned int)curr-(unsigned int)old); }} *poffy=0;
 13813         poffz = offz; curr = 0; { cimg_forZ(res,z) { old=curr; curr=(z+1)*depth/dz; *(poffz++) = wh*((unsigned int)curr-(unsigned int)old); }} *poffz=0;
 13814         poffv = offv; curr = 0; { cimg_forV(res,k) { old=curr; curr=(k+1)*dim/dv; *(poffv++) = whd*((unsigned int)curr-(unsigned int)old); }} *poffv=0;
 13815         T *ptrd = res.data;
 13816         const T* ptrv = data;
 13817         poffv = offv;
 13818         for (unsigned int k=0; k<dv; ) {
 13819           const T *ptrz = ptrv;
 13820           poffz = offz;
 13821           for (unsigned int z=0; z<dz; ) {
 13822             const T *ptry = ptrz;
 13823             poffy = offy;
 13824             for (unsigned int y=0; y<dy; ) {
 13825               const T *ptrx = ptry;
 13826               poffx = offx;
 13827               cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
 13828               ++y;
 13829               unsigned int dy = *(poffy++);
 13830               for (;!dy && y<dy; cimg_std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
 13831               ptry+=dy;
 13833             ++z;
 13834             unsigned int dz = *(poffz++);
 13835             for (;!dz && z<dz; cimg_std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
 13836             ptrz+=dz;
 13838           ++k;
 13839           unsigned int dv = *(poffv++);
 13840           for (;!dv && k<dv; cimg_std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
 13841           ptrv+=dv;
 13843         delete[] offx; delete[] offy; delete[] offz; delete[] offv;
 13844       } break;
 13846       case 2 : { // Moving average
 13847         bool instance_first = true;
 13848         if (dx!=width) {
 13849           CImg<Tfloat> tmp(dx,height,depth,dim,0);
 13850           for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
 13851             const unsigned int d = cimg::min(b,c);
 13852             a-=d; b-=d; c-=d;
 13853             cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
 13854             if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
 13855             if (!c) { ++s; c = dx; }
 13857           tmp.transfer_to(res);
 13858           instance_first = false;
 13860         if (dy!=height) {
 13861           CImg<Tfloat> tmp(dx,dy,depth,dim,0);
 13862           for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
 13863             const unsigned int d = cimg::min(b,c);
 13864             a-=d; b-=d; c-=d;
 13865             if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
 13866             else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
 13867             if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
 13868             if (!c) { ++s; c = dy; }
 13870           tmp.transfer_to(res);
 13871           instance_first = false;
 13873         if (dz!=depth) {
 13874           CImg<Tfloat> tmp(dx,dy,dz,dim,0);
 13875           for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
 13876             const unsigned int d = cimg::min(b,c);
 13877             a-=d; b-=d; c-=d;
 13878             if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
 13879             else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
 13880             if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
 13881             if (!c) { ++s; c = dz; }
 13883           tmp.transfer_to(res);
 13884           instance_first = false;
 13886         if (dv!=dim) {
 13887           CImg<Tfloat> tmp(dx,dy,dz,dv,0);
 13888           for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
 13889             const unsigned int d = cimg::min(b,c);
 13890             a-=d; b-=d; c-=d;
 13891             if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
 13892             else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
 13893             if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
 13894             if (!c) { ++s; c = dv; }
 13896           tmp.transfer_to(res);
 13897           instance_first = false;
 13899       } break;
 13901       case 3 : { // Linear interpolation
 13902         const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
 13903         const float
 13904           sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
 13905           sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
 13906           sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
 13907           sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
 13909         unsigned int *const off = new unsigned int[dimmax], *poff;
 13910         float *const foff = new float[dimmax], *pfoff, old, curr;
 13911         CImg<T> resx, resy, resz, resv;
 13912         T *ptrd;
 13914         if (dx!=width) {
 13915           if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
 13916           else {
 13917             resx.assign(dx,height,depth,dim);
 13918             curr = old = 0; poff = off; pfoff = foff;
 13919             cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
 13920             ptrd = resx.data;
 13921             const T *ptrs0 = data;
 13922             cimg_forYZV(resx,y,z,k) {
 13923               poff = off; pfoff = foff;
 13924               const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
 13925               cimg_forX(resx,x) {
 13926                 const float alpha = *(pfoff++);
 13927                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
 13928                 *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
 13929                 ptrs+=*(poff++);
 13931               ptrs0+=width;
 13934         } else resx.assign(*this,true);
 13936         if (dy!=height) {
 13937           if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
 13938           else {
 13939             resy.assign(dx,dy,depth,dim);
 13940             curr = old = 0; poff = off; pfoff = foff;
 13941             cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
 13942             cimg_forXZV(resy,x,z,k) {
 13943               ptrd = resy.ptr(x,0,z,k);
 13944               const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
 13945               poff = off; pfoff = foff;
 13946               cimg_forY(resy,y) {
 13947                 const float alpha = *(pfoff++);
 13948                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
 13949                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 13950                 ptrd+=dx;
 13951                 ptrs+=*(poff++);
 13955           resx.assign();
 13956         } else resy.assign(resx,true);
 13958         if (dz!=depth) {
 13959           if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
 13960           else {
 13961             const unsigned int wh = dx*dy;
 13962             resz.assign(dx,dy,dz,dim);
 13963             curr = old = 0; poff = off; pfoff = foff;
 13964             cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
 13965             cimg_forXYV(resz,x,y,k) {
 13966               ptrd = resz.ptr(x,y,0,k);
 13967               const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
 13968               poff = off; pfoff = foff;
 13969               cimg_forZ(resz,z) {
 13970                 const float alpha = *(pfoff++);
 13971                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
 13972                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 13973                 ptrd+=wh;
 13974                 ptrs+=*(poff++);
 13978           resy.assign();
 13979         } else resz.assign(resy,true);
 13981         if (dv!=dim) {
 13982           if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
 13983           else {
 13984             const unsigned int whd = dx*dy*dz;
 13985             resv.assign(dx,dy,dz,dv);
 13986             curr = old = 0; poff = off; pfoff = foff;
 13987             cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
 13988             cimg_forXYZ(resv,x,y,z) {
 13989               ptrd = resv.ptr(x,y,z,0);
 13990               const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
 13991               poff = off; pfoff = foff;
 13992               cimg_forV(resv,k) {
 13993                 const float alpha = *(pfoff++);
 13994                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
 13995                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 13996                 ptrd+=whd;
 13997                 ptrs+=*(poff++);
 14001           resz.assign();
 14002         } else resv.assign(resz,true);
 14004         delete[] off; delete[] foff;
 14005         return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
 14006       } break;
 14008       case 4 : { // Grid filling
 14009         res.assign(dx,dy,dz,dv,0);
 14010         cimg_forXYZV(*this,x,y,z,k) res(x*dx/width,y*dy/height,z*dz/depth,k*dv/dim) = (*this)(x,y,z,k);
 14011       } break;
 14013       case 5 : { // Cubic interpolation
 14014         const float
 14015           sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
 14016           sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
 14017           sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
 14018           sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
 14019         res.assign(dx,dy,dz,dv);
 14020         T *ptrd = res.ptr();
 14021         float cx, cy, cz, ck = 0;
 14022         cimg_forV(res,k) { cz = 0;
 14023         cimg_forZ(res,z) { cy = 0;
 14024         cimg_forY(res,y) { cx = 0;
 14025         cimg_forX(res,x) {
 14026           *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
 14027           cx+=sx;
 14028         } cy+=sy;
 14029         } cz+=sz;
 14030         } ck+=sv;
 14032       } break;
 14034       default : // Invalid interpolation method
 14035         throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
 14036                                     "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
 14037                                     pixel_type(),interpolation_type);
 14039       return res;
 14042     //! Resize an image.
 14043     /**
 14044        \param src  Image giving the geometry of the resize.
 14045        \param interpolation_type  Interpolation method :
 14046        - 1 = raw memory
 14047        - 0 = no interpolation : additional space is filled with 0.
 14048        - 1 = bloc interpolation (nearest point).
 14049        - 2 = mosaic : image is repeated if necessary.
 14050        - 3 = linear interpolation.
 14051        - 4 = grid interpolation.
 14052        - 5 = bi-cubic interpolation.
 14053        \param border_condition Border condition type.
 14054        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 14055     **/
 14056     template<typename t>
 14057     CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
 14058                     const int border_condition=-1, const bool center=false) {
 14059       return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 14062     template<typename t>
 14063     CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
 14064                        const int border_condition=-1, const bool center=false) const {
 14065       return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 14068     //! Resize an image.
 14069     /**
 14070        \param disp = Display giving the geometry of the resize.
 14071        \param interpolation_type = Resizing type :
 14072        - 0 = no interpolation : additional space is filled with 0.
 14073        - 1 = bloc interpolation (nearest point).
 14074        - 2 = mosaic : image is repeated if necessary.
 14075        - 3 = linear interpolation.
 14076        - 4 = grid interpolation.
 14077        - 5 = bi-cubic interpolation.
 14078        - 6 = moving average (best quality for photographs)
 14079        \param border_condition Border condition type.
 14080        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 14081     **/
 14082     CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
 14083                     const int border_condition=-1, const bool center=false) {
 14084       return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 14087     CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
 14088                        const int border_condition=-1, const bool center=false) const {
 14089       return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 14092     //! Half-resize an image, using a special optimized filter.
 14093     CImg<T>& resize_halfXY() {
 14094       return get_resize_halfXY().transfer_to(*this);
 14097     CImg<T> get_resize_halfXY() const {
 14098       if (is_empty()) return *this;
 14099       const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
 14100                               0.1231940459f,  0.1935127547f, 0.1231940459f,
 14101                               0.07842776544f, 0.1231940459f, 0.07842776544f };
 14102       T I[9] = { 0 };
 14103       CImg<T> dest(width/2,height/2,depth,dim);
 14104       cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
 14105         if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
 14106                           (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 14107                            I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 14108                            I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 14109       return dest;
 14112     //! Upscale an image by a factor 2x.
 14113     /**
 14114        Use anisotropic upscaling algorithm described at
 14115        http://scale2x.sourceforge.net/algorithm.html
 14116     **/
 14117     CImg<T>& resize_doubleXY() {
 14118       return get_resize_doubleXY().transfer_to(*this);
 14121     CImg<T> get_resize_doubleXY() const {
 14122 #define _cimg_gs2x_for3(bound,i) \
 14123  for (int i = 0, _p1##i = 0, \
 14124       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 14125       _n1##i<(int)(bound) || i==--_n1##i; \
 14126       _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
 14128 #define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
 14129   _cimg_gs2x_for3((img).height,y) for (int x = 0, \
 14130    _p1##x = 0, \
 14131    _n1##x = (int)( \
 14132    (I[1] = (img)(0,_p1##y,z,v)), \
 14133    (I[3] = I[4] = (img)(0,y,z,v)), \
 14134    (I[7] = (img)(0,_n1##y,z,v)),        \
 14135    1>=(img).width?(int)((img).width)-1:1); \
 14136    (_n1##x<(int)((img).width) && ( \
 14137    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 14138    (I[5] = (img)(_n1##x,y,z,v)), \
 14139    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 14140    x==--_n1##x; \
 14141    I[1] = I[2], \
 14142    I[3] = I[4], I[4] = I[5], \
 14143    I[7] = I[8], \
 14144    _p1##x = x++, ++_n1##x)
 14146       if (is_empty()) return *this;
 14147       CImg<T> res(2*width,2*height,depth,dim);
 14148       CImg_3x3(I,T);
 14149       cimg_forZV(*this,z,k) {
 14151           *ptrd1 = res.ptr(0,0,0,k),
 14152           *ptrd2 = ptrd1 + res.width;
 14153         _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
 14154           if (Icp!=Icn && Ipc!=Inc) {
 14155             *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 14156             *(ptrd1++) = Icp==Inc?Inc:Icc;
 14157             *(ptrd2++) = Ipc==Icn?Ipc:Icc;
 14158             *(ptrd2++) = Icn==Inc?Inc:Icc;
 14159           } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
 14162       return res;
 14165     //! Upscale an image by a factor 3x.
 14166     /**
 14167        Use anisotropic upscaling algorithm described at
 14168        http://scale2x.sourceforge.net/algorithm.html
 14169     **/
 14170     CImg<T>& resize_tripleXY() {
 14171       return get_resize_tripleXY().transfer_to(*this);
 14174     CImg<T> get_resize_tripleXY() const {
 14175 #define _cimg_gs3x_for3(bound,i) \
 14176  for (int i = 0, _p1##i = 0, \
 14177       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 14178       _n1##i<(int)(bound) || i==--_n1##i; \
 14179       _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
 14181 #define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
 14182   _cimg_gs3x_for3((img).height,y) for (int x = 0, \
 14183    _p1##x = 0, \
 14184    _n1##x = (int)( \
 14185    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
 14186    (I[3] = I[4] = (img)(0,y,z,v)), \
 14187    (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
 14188    1>=(img).width?(int)((img).width)-1:1); \
 14189    (_n1##x<(int)((img).width) && ( \
 14190    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 14191    (I[5] = (img)(_n1##x,y,z,v)), \
 14192    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 14193    x==--_n1##x; \
 14194    I[0] = I[1], I[1] = I[2], \
 14195    I[3] = I[4], I[4] = I[5], \
 14196    I[6] = I[7], I[7] = I[8], \
 14197    _p1##x = x++, ++_n1##x)
 14199       if (is_empty()) return *this;
 14200       CImg<T> res(3*width,3*height,depth,dim);
 14201       CImg_3x3(I,T);
 14202       cimg_forZV(*this,z,k) {
 14204           *ptrd1 = res.ptr(0,0,0,k),
 14205           *ptrd2 = ptrd1 + res.width,
 14206           *ptrd3 = ptrd2 + res.width;
 14207         _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
 14208           if (Icp != Icn && Ipc != Inc) {
 14209             *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 14210             *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
 14211             *(ptrd1++) = Icp==Inc?Inc:Icc;
 14212             *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
 14213             *(ptrd2++) = Icc;
 14214             *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
 14215             *(ptrd3++) = Ipc==Icn?Ipc:Icc;
 14216             *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
 14217             *(ptrd3++) = Icn==Inc?Inc:Icc;
 14218           } else {
 14219             *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
 14220             *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
 14221             *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
 14225       return res;
 14228     // Warp an image.
 14229     template<typename t>
 14230     CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
 14231                   const bool interpolation=true, const unsigned int border_conditions=0) {
 14232       return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
 14235     template<typename t>
 14236     CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
 14237                      const bool interpolation=true, const unsigned int border_conditions=0) const {
 14238       if (is_empty() || !warp) return *this;
 14239       if (!is_sameXYZ(warp))
 14240         throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and warping field (%u,%u,%u,%u,%p) "
 14241                                     "have different XYZ dimensions.",
 14242                                     pixel_type(),width,height,depth,dim,data,
 14243                                     warp.width,warp.height,warp.depth,warp.dim,warp.data);
 14244       CImg<T> res(width,height,depth,dim);
 14245       switch (warp.dim) {
 14246       case 1 : // 1D warping.
 14247         if (relative) { // Relative warp coordinates
 14248           if (interpolation) switch (border_conditions) {
 14249           case 2 : {
 14250             cimg_forXYZV(*this,x,y,z,v)
 14251               res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
 14252           } break;
 14253           case 1 : {
 14254             cimg_forXYZV(*this,x,y,z,v)
 14255               res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
 14256           } break;
 14257           default : {
 14258             cimg_forXYZV(*this,x,y,z,v)
 14259               res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
 14261           } else switch (border_conditions) {
 14262           case 2 : {
 14263             cimg_forXYZV(*this,x,y,z,v)
 14264               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
 14265           } break;
 14266           case 1 : {
 14267             cimg_forXYZV(*this,x,y,z,v)
 14268               res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
 14269           } break;
 14270           default : {
 14271             cimg_forXYZV(*this,x,y,z,v)
 14272               res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
 14275         } else { // Absolute warp coordinates
 14276           if (interpolation) switch (border_conditions) {
 14277           case 2 : {
 14278             cimg_forXYZV(*this,x,y,z,v)
 14279               res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
 14280           } break;
 14281           case 1 : {
 14282             cimg_forXYZV(*this,x,y,z,v)
 14283               res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
 14284           } break;
 14285           default : {
 14286             cimg_forXYZV(*this,x,y,z,v)
 14287               res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
 14289           } else switch (border_conditions) {
 14290           case 2 : {
 14291             cimg_forXYZV(*this,x,y,z,v)
 14292               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
 14293           } break;
 14294           case 1 : {
 14295             cimg_forXYZV(*this,x,y,z,v)
 14296               res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
 14297           } break;
 14298           default : {
 14299             cimg_forXYZV(*this,x,y,z,v)
 14300               res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
 14304         break;
 14306       case 2 : // 2D warping
 14307         if (relative) { // Relative warp coordinates
 14308           if (interpolation) switch (border_conditions) {
 14309           case 2 : {
 14310             cimg_forXYZV(*this,x,y,z,v)
 14311               res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 14312                                              cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
 14313           } break;
 14314           case 1 : {
 14315             cimg_forXYZV(*this,x,y,z,v)
 14316               res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
 14317           } break;
 14318           default : {
 14319             cimg_forXYZV(*this,x,y,z,v)
 14320               res(x,y,z,v) = (T)linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v,0);
 14322           } else switch (border_conditions) {
 14323           case 2 : {
 14324             cimg_forXYZV(*this,x,y,z,v)
 14325               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 14326                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
 14327           } break;
 14328           case 1 : {
 14329             cimg_forXYZV(*this,x,y,z,v)
 14330               res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
 14331           } break;
 14332           default : {
 14333             cimg_forXYZV(*this,x,y,z,v)
 14334               res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
 14337         } else { // Absolute warp coordinates
 14338           if (interpolation) switch (border_conditions) {
 14339           case 2 : {
 14340             cimg_forXYZV(*this,x,y,z,v)
 14341               res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
 14342                                              cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
 14343           } break;
 14344           case 1 : {
 14345             cimg_forXYZV(*this,x,y,z,v)
 14346               res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
 14347           } break;
 14348           default : {
 14349             cimg_forXYZV(*this,x,y,z,v)
 14350               res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
 14352           } else switch (border_conditions) {
 14353           case 2 : {
 14354             cimg_forXYZV(*this,x,y,z,v)
 14355               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 14356                                      cimg::mod((int)warp(x,y,z,1),(int)depth),z,v);
 14357           } break;
 14358           case 1 : {
 14359             cimg_forXYZV(*this,x,y,z,v)
 14360               res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
 14361           } break;
 14362           default : {
 14363             cimg_forXYZV(*this,x,y,z,v)
 14364               res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
 14368         break;
 14370       case 3 : // 3D warping
 14371         if (relative) { // Relative warp coordinates
 14372           if (interpolation) switch (border_conditions) {
 14373           case 2 : {
 14374             cimg_forXYZV(*this,x,y,z,v)
 14375               res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 14376                                               cimg::mod(y-(float)warp(x,y,z,1),(float)height),
 14377                                               cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
 14378           } break;
 14379           case 1 : {
 14380             cimg_forXYZV(*this,x,y,z,v)
 14381               res(x,y,z,v) = (T)_linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v);
 14382           } break;
 14383           default : {
 14384             cimg_forXYZV(*this,x,y,z,v)
 14385               res(x,y,z,v) = (T)linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v,0);
 14387           } else switch (border_conditions) {
 14388           case 2 : {
 14389             cimg_forXYZV(*this,x,y,z,v)
 14390               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 14391                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),
 14392                                      cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
 14393           } break;
 14394           case 1 : {
 14395             cimg_forXYZV(*this,x,y,z,v)
 14396               res(x,y,z,v) = _atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v);
 14397           } break;
 14398           default : {
 14399             cimg_forXYZV(*this,x,y,z,v)
 14400               res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v,0);
 14403         } else { // Absolute warp coordinates
 14404           if (interpolation) switch (border_conditions) {
 14405           case 2 : {
 14406             cimg_forXYZV(*this,x,y,z,v)
 14407               res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
 14408                                               cimg::mod((float)warp(x,y,z,1),(float)height),
 14409                                               cimg::mod((float)warp(x,y,z,2),(float)depth),v);
 14410           } break;
 14411           case 1 : {
 14412             cimg_forXYZV(*this,x,y,z,v)
 14413               res(x,y,z,v) = (T)_linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v);
 14414           } break;
 14415           default : {
 14416             cimg_forXYZV(*this,x,y,z,v)
 14417               res(x,y,z,v) = (T)linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v,0);
 14419           } else switch (border_conditions) {
 14420           case 2 : {
 14421             cimg_forXYZV(*this,x,y,z,v)
 14422               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 14423                                      cimg::mod((int)warp(x,y,z,1),(int)height),
 14424                                      cimg::mod((int)warp(x,y,z,2),(int)depth),v);
 14425           } break;
 14426           case 1 : {
 14427             cimg_forXYZV(*this,x,y,z,v)
 14428               res(x,y,z,v) = _atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v);
 14429           } break;
 14430           default : {
 14431             cimg_forXYZV(*this,x,y,z,v)
 14432               res(x,y,z,v) = atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v,0);
 14436         break;
 14438       default : // 4D warping
 14439         if (relative) { // Relative warp coordinates
 14440           if (interpolation) switch (border_conditions) {
 14441           case 2 : {
 14442             cimg_forXYZV(*this,x,y,z,v)
 14443               res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 14444                                                cimg::mod(y-(float)warp(x,y,z,1),(float)height),
 14445                                                cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
 14446                                                cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
 14447           } break;
 14448           case 1 : {
 14449             cimg_forXYZV(*this,x,y,z,v)
 14450               res(x,y,z,v) = (T)_linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3));
 14451           } break;
 14452           default : {
 14453             cimg_forXYZV(*this,x,y,z,v)
 14454               res(x,y,z,v) = (T)linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3),0);
 14456           } else switch (border_conditions) {
 14457           case 2 : {
 14458             cimg_forXYZV(*this,x,y,z,v)
 14459               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 14460                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),
 14461                                      cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
 14462                                      cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
 14463           } break;
 14464           case 1 : {
 14465             cimg_forXYZV(*this,x,y,z,v)
 14466               res(x,y,z,v) = _atXYZV(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3));
 14467           } break;
 14468           default : {
 14469             cimg_forXYZV(*this,x,y,z,v)
 14470               res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3),0);
 14473         } else { // Absolute warp coordinates
 14474           if (interpolation) switch (border_conditions) {
 14475           case 2 : {
 14476             cimg_forXYZV(*this,x,y,z,v)
 14477               res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
 14478                                                cimg::mod((float)warp(x,y,z,1),(float)height),
 14479                                                cimg::mod((float)warp(x,y,z,2),(float)depth),
 14480                                                cimg::mod((float)warp(x,y,z,3),(float)dim));
 14481           } break;
 14482           case 1 : {
 14483             cimg_forXYZV(*this,x,y,z,v)
 14484               res(x,y,z,v) = (T)_linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3));
 14485           } break;
 14486           default : {
 14487             cimg_forXYZV(*this,x,y,z,v)
 14488               res(x,y,z,v) = (T)linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3),0);
 14490           } else switch (border_conditions) {
 14491           case 2 : {
 14492             cimg_forXYZV(*this,x,y,z,v)
 14493               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 14494                                      cimg::mod((int)warp(x,y,z,1),(int)height),
 14495                                      cimg::mod((int)warp(x,y,z,2),(int)depth),
 14496                                      cimg::mod((int)warp(x,y,z,3),(int)dim));
 14497           } break;
 14498           case 1 : {
 14499             cimg_forXYZV(*this,x,y,z,v)
 14500               res(x,y,z,v) = _atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3));
 14501           } break;
 14502           default : {
 14503             cimg_forXYZV(*this,x,y,z,v)
 14504               res(x,y,z,v) = atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3),0);
 14509       return res;
 14512     // Permute axes order (internal).
 14513     template<typename t>
 14514     CImg<t> _get_permute_axes(const char *permut, const t&) const {
 14515       if (is_empty() || !permut) return CImg<t>(*this,false);
 14516       CImg<t> res;
 14517       const T* ptrs = data;
 14518       if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
 14519       if (!cimg::strncasecmp(permut,"xyvz",4)) {
 14520         res.assign(width,height,dim,depth);
 14521         cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
 14523       if (!cimg::strncasecmp(permut,"xzyv",4)) {
 14524         res.assign(width,depth,height,dim);
 14525         cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
 14527       if (!cimg::strncasecmp(permut,"xzvy",4)) {
 14528         res.assign(width,depth,dim,height);
 14529         cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
 14531       if (!cimg::strncasecmp(permut,"xvyz",4)) {
 14532         res.assign(width,dim,height,depth);
 14533         cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
 14535       if (!cimg::strncasecmp(permut,"xvzy",4)) {
 14536         res.assign(width,dim,depth,height);
 14537         cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
 14539       if (!cimg::strncasecmp(permut,"yxzv",4)) {
 14540         res.assign(height,width,depth,dim);
 14541         cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
 14543       if (!cimg::strncasecmp(permut,"yxvz",4)) {
 14544         res.assign(height,width,dim,depth);
 14545         cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
 14547       if (!cimg::strncasecmp(permut,"yzxv",4)) {
 14548         res.assign(height,depth,width,dim);
 14549         cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
 14551       if (!cimg::strncasecmp(permut,"yzvx",4)) {
 14552         res.assign(height,depth,dim,width);
 14553         switch (width) {
 14554         case 1 : {
 14555           t *ptrR = res.ptr(0,0,0,0);
 14556           for (unsigned long siz = height*depth*dim; siz; --siz) {
 14557             *(ptrR++) = (t)*(ptrs++);
 14559         } break;
 14560         case 2 : {
 14561           t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
 14562           for (unsigned long siz = height*depth*dim; siz; --siz) {
 14563             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
 14565         } break;
 14566         case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
 14567           t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
 14568           for (unsigned long siz = height*depth*dim; siz; --siz) {
 14569             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
 14571         } break;
 14572         case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
 14573           t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2), *ptrA = res.ptr(0,0,0,3);
 14574           for (unsigned long siz = height*depth*dim; siz; --siz) {
 14575             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
 14577         } break;
 14578         default : {
 14579           cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
 14580           return res;
 14584       if (!cimg::strncasecmp(permut,"yvxz",4)) {
 14585         res.assign(height,dim,width,depth);
 14586         cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
 14588       if (!cimg::strncasecmp(permut,"yvzx",4)) {
 14589         res.assign(height,dim,depth,width);
 14590         cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
 14592       if (!cimg::strncasecmp(permut,"zxyv",4)) {
 14593         res.assign(depth,width,height,dim);
 14594         cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
 14596       if (!cimg::strncasecmp(permut,"zxvy",4)) {
 14597         res.assign(depth,width,dim,height);
 14598         cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
 14600       if (!cimg::strncasecmp(permut,"zyxv",4)) {
 14601         res.assign(depth,height,width,dim);
 14602         cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
 14604       if (!cimg::strncasecmp(permut,"zyvx",4)) {
 14605         res.assign(depth,height,dim,width);
 14606         cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
 14608       if (!cimg::strncasecmp(permut,"zvxy",4)) {
 14609         res.assign(depth,dim,width,height);
 14610         cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
 14612       if (!cimg::strncasecmp(permut,"zvyx",4)) {
 14613         res.assign(depth,dim,height,width);
 14614         cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
 14616       if (!cimg::strncasecmp(permut,"vxyz",4)) {
 14617         res.assign(dim,width,height,depth);
 14618         switch (dim) {
 14619         case 1 : {
 14620           const T *ptrR = ptr(0,0,0,0);
 14621           t *ptrd = res.ptr();
 14622           for (unsigned long siz = width*height*depth; siz; --siz) {
 14623             *(ptrd++) = (t)*(ptrR++);
 14625         } break;
 14626         case 2 : {
 14627           const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
 14628           t *ptrd = res.ptr();
 14629           for (unsigned long siz = width*height*depth; siz; --siz) {
 14630             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
 14632         } break;
 14633         case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
 14634           const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
 14635           t *ptrd = res.ptr();
 14636           for (unsigned long siz = width*height*depth; siz; --siz) {
 14637             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
 14639         } break;
 14640         case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
 14641           const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2), *ptrA = ptr(0,0,0,3);
 14642           t *ptrd = res.ptr();
 14643           for (unsigned long siz = width*height*depth; siz; --siz) {
 14644             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
 14646         } break;
 14647         default : {
 14648           cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
 14652       if (!cimg::strncasecmp(permut,"vxzy",4)) {
 14653         res.assign(dim,width,depth,height);
 14654         cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
 14656       if (!cimg::strncasecmp(permut,"vyxz",4)) {
 14657         res.assign(dim,height,width,depth);
 14658         cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
 14660       if (!cimg::strncasecmp(permut,"vyzx",4)) {
 14661         res.assign(dim,height,depth,width);
 14662         cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
 14664       if (!cimg::strncasecmp(permut,"vzxy",4)) {
 14665         res.assign(dim,depth,width,height);
 14666         cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
 14668       if (!cimg::strncasecmp(permut,"vzyx",4)) {
 14669         res.assign(dim,depth,height,width);
 14670         cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
 14672       if (!res)
 14673         throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",
 14674                                     pixel_type(),permut);
 14675       return res;
 14678     //! Permute axes order.
 14679     /**
 14680        This function permutes image axes.
 14681        \param permut = String describing the permutation (4 characters).
 14682     **/
 14683     CImg<T>& permute_axes(const char *order) {
 14684       return get_permute_axes(order).transfer_to(*this);
 14687     CImg<T> get_permute_axes(const char *order) const {
 14688       const T foo = (T)0;
 14689       return _get_permute_axes(order,foo);
 14692     //! Invert endianness.
 14693     CImg<T>& invert_endianness() {
 14694       cimg::invert_endianness(data,size());
 14695       return *this;
 14698     CImg<T> get_invert_endianness() const {
 14699       return (+*this).invert_endianness();
 14702     //! Mirror an image along the specified axis.
 14703     CImg<T>& mirror(const char axis) {
 14704       if (is_empty()) return *this;
 14705       T *pf, *pb, *buf = 0;
 14706       switch (cimg::uncase(axis)) {
 14707       case 'x' : {
 14708         pf = data; pb = ptr(width-1);
 14709         const unsigned int width2 = width/2;
 14710         for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
 14711           for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
 14712           pf+=width - width2;
 14713           pb+=width + width2;
 14715       } break;
 14716       case 'y' : {
 14717         buf = new T[width];
 14718         pf = data; pb = ptr(0,height-1);
 14719         const unsigned int height2 = height/2;
 14720         for (unsigned int zv=0; zv<depth*dim; ++zv) {
 14721           for (unsigned int y=0; y<height2; ++y) {
 14722             cimg_std::memcpy(buf,pf,width*sizeof(T));
 14723             cimg_std::memcpy(pf,pb,width*sizeof(T));
 14724             cimg_std::memcpy(pb,buf,width*sizeof(T));
 14725             pf+=width;
 14726             pb-=width;
 14728           pf+=width*(height - height2);
 14729           pb+=width*(height + height2);
 14731       } break;
 14732       case 'z' : {
 14733         buf = new T[width*height];
 14734         pf = data; pb = ptr(0,0,depth-1);
 14735         const unsigned int depth2 = depth/2;
 14736         cimg_forV(*this,v) {
 14737           for (unsigned int z=0; z<depth2; ++z) {
 14738             cimg_std::memcpy(buf,pf,width*height*sizeof(T));
 14739             cimg_std::memcpy(pf,pb,width*height*sizeof(T));
 14740             cimg_std::memcpy(pb,buf,width*height*sizeof(T));
 14741             pf+=width*height;
 14742             pb-=width*height;
 14744           pf+=width*height*(depth - depth2);
 14745           pb+=width*height*(depth + depth2);
 14747       } break;
 14748       case 'v' : {
 14749         buf = new T[width*height*depth];
 14750         pf = data; pb = ptr(0,0,0,dim-1);
 14751         const unsigned int dim2 = dim/2;
 14752         for (unsigned int v=0; v<dim2; ++v) {
 14753           cimg_std::memcpy(buf,pf,width*height*depth*sizeof(T));
 14754           cimg_std::memcpy(pf,pb,width*height*depth*sizeof(T));
 14755           cimg_std::memcpy(pb,buf,width*height*depth*sizeof(T));
 14756           pf+=width*height*depth;
 14757           pb-=width*height*depth;
 14759       } break;
 14760       default :
 14761         throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
 14762                                     pixel_type(),axis);
 14764       if (buf) delete[] buf;
 14765       return *this;
 14768     CImg<T> get_mirror(const char axis) const {
 14769       return (+*this).mirror(axis);
 14772     //! Translate the image.
 14773     /**
 14774        \param deltax Amount of displacement along the X-axis.
 14775        \param deltay Amount of displacement along the Y-axis.
 14776        \param deltaz Amount of displacement along the Z-axis.
 14777        \param deltav Amount of displacement along the V-axis.
 14778        \param border_condition Border condition.
 14780        - \c border_condition can be :
 14781           - 0 : Zero border condition (Dirichlet).
 14782           - 1 : Nearest neighbors (Neumann).
 14783           - 2 : Repeat Pattern (Fourier style).
 14784     **/
 14785     CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 14786                        const int border_condition=0) {
 14787       if (is_empty()) return *this;
 14788       if (deltax) // Translate along X-axis
 14789         switch (border_condition) {
 14790         case 0 :
 14791           if (cimg::abs(deltax)>=dimx()) return fill(0);
 14792           if (deltax>0) cimg_forYZV(*this,y,z,k) {
 14793             cimg_std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
 14794             cimg_std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
 14795           } else cimg_forYZV(*this,y,z,k) {
 14796             cimg_std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T));
 14797             cimg_std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T));
 14799           break;
 14800         case 1 :
 14801           if (deltax>0) {
 14802             const int ndeltax = (deltax>=dimx())?width-1:deltax;
 14803             if (!ndeltax) return *this;
 14804             cimg_forYZV(*this,y,z,k) {
 14805               cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
 14806               T *ptrd = ptr(width-1,y,z,k);
 14807               const T val = *ptrd;
 14808               for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
 14810           } else {
 14811             const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
 14812             if (!ndeltax) return *this;
 14813             cimg_forYZV(*this,y,z,k) {
 14814               cimg_std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
 14815               T *ptrd = ptr(0,y,z,k);
 14816               const T val = *ptrd;
 14817               for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
 14820           break;
 14821         case 2 : {
 14822           const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
 14823           if (!ndeltax) return *this;
 14824           T* buf = new T[cimg::abs(ndeltax)];
 14825           if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
 14826             cimg_std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
 14827             cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
 14828             cimg_std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
 14829           } else cimg_forYZV(*this,y,z,k) {
 14830             cimg_std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
 14831             cimg_std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
 14832             cimg_std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
 14834           delete[] buf;
 14835         } break;
 14838       if (deltay) // Translate along Y-axis
 14839         switch (border_condition) {
 14840         case 0 :
 14841           if (cimg::abs(deltay)>=dimy()) return fill(0);
 14842           if (deltay>0) cimg_forZV(*this,z,k) {
 14843             cimg_std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
 14844             cimg_std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
 14845           } else cimg_forZV(*this,z,k) {
 14846             cimg_std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T));
 14847             cimg_std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T));
 14849           break;
 14850         case 1 :
 14851           if (deltay>0) {
 14852             const int ndeltay = (deltay>=dimy())?height-1:deltay;
 14853             if (!ndeltay) return *this;
 14854             cimg_forZV(*this,z,k) {
 14855               cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
 14856               T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
 14857               for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
 14859           } else {
 14860             const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
 14861             if (!ndeltay) return *this;
 14862             cimg_forZV(*this,z,k) {
 14863               cimg_std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
 14864               T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
 14865               for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
 14868           break;
 14869         case 2 : {
 14870           const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
 14871           if (!ndeltay) return *this;
 14872           T* buf = new T[width*cimg::abs(ndeltay)];
 14873           if (ndeltay>0) cimg_forZV(*this,z,k) {
 14874             cimg_std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
 14875             cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
 14876             cimg_std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
 14877           } else cimg_forZV(*this,z,k) {
 14878             cimg_std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
 14879             cimg_std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
 14880             cimg_std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
 14882           delete[] buf;
 14883         } break;
 14886       if (deltaz) // Translate along Z-axis
 14887         switch (border_condition) {
 14888         case 0 :
 14889           if (cimg::abs(deltaz)>=dimz()) return fill(0);
 14890           if (deltaz>0) cimg_forV(*this,k) {
 14891             cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
 14892             cimg_std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
 14893           } else cimg_forV(*this,k) {
 14894             cimg_std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T));
 14895             cimg_std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T));
 14897           break;
 14898         case 1 :
 14899           if (deltaz>0) {
 14900             const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
 14901             if (!ndeltaz) return *this;
 14902             cimg_forV(*this,k) {
 14903               cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
 14904               T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
 14905               for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
 14907           } else {
 14908             const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
 14909             if (!ndeltaz) return *this;
 14910             cimg_forV(*this,k) {
 14911               cimg_std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
 14912               T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
 14913               for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
 14916           break;
 14917         case 2 : {
 14918           const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
 14919           if (!ndeltaz) return *this;
 14920           T* buf = new T[width*height*cimg::abs(ndeltaz)];
 14921           if (ndeltaz>0) cimg_forV(*this,k) {
 14922             cimg_std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
 14923             cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
 14924             cimg_std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
 14925           } else cimg_forV(*this,k) {
 14926             cimg_std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
 14927             cimg_std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
 14928             cimg_std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
 14930           delete[] buf;
 14931         } break;
 14934       if (deltav) // Translate along V-axis
 14935         switch (border_condition) {
 14936         case 0 :
 14937           if (cimg::abs(deltav)>=dimv()) return fill(0);
 14938           if (deltav>0) {
 14939             cimg_std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
 14940             cimg_std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
 14941           } else cimg_forV(*this,k) {
 14942             cimg_std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T));
 14943             cimg_std::memset(data,0,-deltav*width*height*depth*sizeof(T));
 14945           break;
 14946         case 1 :
 14947           if (deltav>0) {
 14948             const int ndeltav = (deltav>=dimv())?dim-1:deltav;
 14949             if (!ndeltav) return *this;
 14950             cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
 14951             T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
 14952             for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
 14953           } else {
 14954             const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
 14955             if (!ndeltav) return *this;
 14956             cimg_std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
 14957             T *ptrd = ptr(0,0,0,1);
 14958             for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
 14960           break;
 14961         case 2 : {
 14962           const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
 14963           if (!ndeltav) return *this;
 14964           T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
 14965           if (ndeltav>0) {
 14966             cimg_std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
 14967             cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
 14968             cimg_std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
 14969           } else {
 14970             cimg_std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
 14971             cimg_std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
 14972             cimg_std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
 14974           delete[] buf;
 14975         } break;
 14977       return *this;
 14980     CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 14981                           const int border_condition=0) const {
 14982       return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
 14985     //! Get a square region of the image.
 14986     /**
 14987        \param x0 = X-coordinate of the upper-left crop rectangle corner.
 14988        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 14989        \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 14990        \param v0 = V-coordinate of the upper-left crop rectangle corner.
 14991        \param x1 = X-coordinate of the lower-right crop rectangle corner.
 14992        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 14993        \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 14994        \param v1 = V-coordinate of the lower-right crop rectangle corner.
 14995        \param border_condition = Dirichlet (false) or Neumann border conditions.
 14996     **/
 14997     CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
 14998                   const int x1, const int y1, const int z1, const int v1,
 14999                   const bool border_condition=false) {
 15000       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
 15003     CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
 15004                      const int x1, const int y1, const int z1, const int v1,
 15005                      const bool border_condition=false) const {
 15006       if (is_empty()) return *this;
 15007       const int
 15008         nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
 15009         ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
 15010         nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
 15011         nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
 15012       CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
 15013       if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
 15014         if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
 15015         else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
 15016       } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
 15017       return dest;
 15020     //! Get a rectangular part of the instance image.
 15021     /**
 15022        \param x0 = X-coordinate of the upper-left crop rectangle corner.
 15023        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 15024        \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 15025        \param x1 = X-coordinate of the lower-right crop rectangle corner.
 15026        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 15027        \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 15028        \param border_condition = determine the type of border condition if
 15029        some of the desired region is outside the image.
 15030     **/
 15031     CImg<T>& crop(const int x0, const int y0, const int z0,
 15032                   const int x1, const int y1, const int z1,
 15033                   const bool border_condition=false) {
 15034       return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 15037     CImg<T> get_crop(const int x0, const int y0, const int z0,
 15038                      const int x1, const int y1, const int z1,
 15039                      const bool border_condition=false) const {
 15040       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 15043     //! Get a rectangular part of the instance image.
 15044     /**
 15045        \param x0 = X-coordinate of the upper-left crop rectangle corner.
 15046        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 15047        \param x1 = X-coordinate of the lower-right crop rectangle corner.
 15048        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 15049        \param border_condition = determine the type of border condition if
 15050        some of the desired region is outside the image.
 15051     **/
 15052     CImg<T>& crop(const int x0, const int y0,
 15053                   const int x1, const int y1,
 15054                   const bool border_condition=false) {
 15055       return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 15058     CImg<T> get_crop(const int x0, const int y0,
 15059                      const int x1, const int y1,
 15060                      const bool border_condition=false) const {
 15061       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 15064     //! Get a rectangular part of the instance image.
 15065     /**
 15066        \param x0 = X-coordinate of the upper-left crop rectangle corner.
 15067        \param x1 = X-coordinate of the lower-right crop rectangle corner.
 15068        \param border_condition = determine the type of border condition if
 15069        some of the desired region is outside the image.
 15070     **/
 15071     CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
 15072       return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 15075     CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
 15076       return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 15079     //! Autocrop an image, regarding of the specified backround value.
 15080     CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
 15081       if (is_empty()) return *this;
 15082       const int lmax = cimg::strlen(axes);
 15083       for (int l = 0; l<lmax; ++l) autocrop(value,axes[l]);
 15084       return *this;
 15087     CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
 15088       return (+*this).autocrop(value,axes);
 15091     //! Autocrop an image, regarding of the specified backround color.
 15092     CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
 15093       if (is_empty()) return *this;
 15094       const int lmax = cimg::strlen(axes);
 15095       for (int l = 0; l<lmax; ++l) autocrop(color,axes[l]);
 15096       return *this;
 15099     CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
 15100       return (+*this).autocrop(color,axes);
 15103     //! Autocrop an image, regarding of the specified backround color.
 15104     template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
 15105       return get_autocrop(color,axes).transfer_to(*this);
 15108     template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
 15109       return get_autocrop(color.data,axes);
 15112     //! Autocrop an image along specified axis, regarding of the specified backround value.
 15113     CImg<T>& autocrop(const T value, const char axis) {
 15114       return get_autocrop(value,axis).transfer_to(*this);
 15117     CImg<T> get_autocrop(const T value, const char axis) const {
 15118       if (is_empty()) return *this;
 15119       CImg<T> res;
 15120       const CImg<intT> coords = _get_autocrop(value,axis);
 15121       switch (cimg::uncase(axis)) {
 15122         case 'x' : {
 15123           const int x0 = coords[0], x1 = coords[1];
 15124           if (x0>=0 && x1>=0) res = get_crop(x0,x1);
 15125         } break;
 15126         case 'y' : {
 15127           const int y0 = coords[0], y1 = coords[1];
 15128           if (y0>=0 && y1>=0) res = get_crop(0,y0,width-1,y1);
 15129         } break;
 15130         case 'z' : {
 15131           const int z0 = coords[0], z1 = coords[1];
 15132           if (z0>=0 && z1>=0) res = get_crop(0,0,z0,width-1,height-1,z1);
 15133         } break;
 15134         case 'v' : {
 15135           const int v0 = coords[0], v1 = coords[1];
 15136           if (v0>=0 && v1>=0) res = get_crop(0,0,0,v0,width-1,height-1,depth-1,v1);
 15137         } break;
 15139       return res;
 15142     //! Autocrop an image along specified axis, regarding of the specified backround color.
 15143     CImg<T>& autocrop(const T *const color, const char axis) {
 15144       return get_autocrop(color,axis).transfer_to(*this);
 15147     CImg<T> get_autocrop(const T *const color, const char axis) const {
 15148       if (is_empty()) return *this;
 15149       CImg<T> res;
 15150       switch (cimg::uncase(axis)) {
 15151         case 'x' : {
 15152           int x0 = width, x1 = -1;
 15153           cimg_forV(*this,k) {
 15154             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 15155             const int nx0 = coords[0], nx1 = coords[1];
 15156             if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
 15158           if (x0<=x1) res = get_crop(x0,x1);
 15159         } break;
 15160         case 'y' : {
 15161           int y0 = height, y1 = -1;
 15162           cimg_forV(*this,k) {
 15163             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 15164             const int ny0 = coords[0], ny1 = coords[1];
 15165             if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
 15167           if (y0<=y1) res = get_crop(0,y0,width-1,y1);
 15168         } break;
 15169         case 'z' : {
 15170           int z0 = depth, z1 = -1;
 15171           cimg_forV(*this,k) {
 15172             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 15173             const int nz0 = coords[0], nz1 = coords[1];
 15174             if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
 15176           if (z0<=z1) res = get_crop(0,0,z0,width-1,height-1,z1);
 15177         } break;
 15178       default :
 15179           throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c', must be 'x','y' or 'z'.",
 15180                                       pixel_type(),axis);
 15182       return res;
 15185     //! Autocrop an image along specified axis, regarding of the specified backround color.
 15186     template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char axis) {
 15187       return get_autocrop(color,axis).transfer_to(*this);
 15190     template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char axis) const {
 15191       return get_autocrop(color.data,axis);
 15194     CImg<intT> _get_autocrop(const T value, const char axis) const {
 15195       CImg<intT> res;
 15196       int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
 15197       switch (cimg::uncase(axis)) {
 15198       case 'x' : {
 15199         cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
 15200           if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 15201         if (x0>=0) {
 15202           for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
 15203             if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
 15205         res = CImg<intT>::vector(x0,x1);
 15206       } break;
 15207       case 'y' : {
 15208         cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
 15209           if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 15210         if (y0>=0) {
 15211           for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
 15212             if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
 15214         res = CImg<intT>::vector(y0,y1);
 15215       } break;
 15216       case 'z' : {
 15217         cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
 15218           if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 15219         if (z0>=0) {
 15220           for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
 15221             if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
 15223         res = CImg<intT>::vector(z0,z1);
 15224       } break;
 15225       case 'v' : {
 15226         cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
 15227           if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 15228         if (v0>=0) {
 15229           for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
 15230             if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
 15232         res = CImg<intT>::vector(v0,v1);
 15233       } break;
 15234       default :
 15235         throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
 15236                                     pixel_type(),axis);
 15238       return res;
 15241     //! Get a set of columns.
 15242     CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
 15243       return get_columns(x0,x1).transfer_to(*this);
 15246     CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
 15247       return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
 15250     //! Get one column.
 15251     CImg<T>& column(const unsigned int x0) {
 15252       return columns(x0,x0);
 15255     CImg<T> get_column(const unsigned int x0) const {
 15256       return get_columns(x0,x0);
 15259     //! Get a set of lines.
 15260     CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
 15261       return get_lines(y0,y1).transfer_to(*this);
 15264     CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
 15265       return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
 15268     //! Get a line.
 15269     CImg<T>& line(const unsigned int y0) {
 15270       return lines(y0,y0);
 15273     CImg<T> get_line(const unsigned int y0) const {
 15274       return get_lines(y0,y0);
 15277     //! Get a set of slices.
 15278     CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
 15279       return get_slices(z0,z1).transfer_to(*this);
 15282     CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
 15283       return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
 15286     //! Get a slice.
 15287     CImg<T>& slice(const unsigned int z0) {
 15288       return slices(z0,z0);
 15291     CImg<T> get_slice(const unsigned int z0) const {
 15292       return get_slices(z0,z0);
 15295     //! Get a set of channels.
 15296     CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
 15297       return get_channels(v0,v1).transfer_to(*this);
 15300     CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
 15301       return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
 15304     //! Get a channel.
 15305     CImg<T>& channel(const unsigned int v0) {
 15306       return channels(v0,v0);
 15309     CImg<T> get_channel(const unsigned int v0) const {
 15310       return get_channels(v0,v0);
 15313     //! Get a shared-memory image referencing a set of points of the instance image.
 15314     CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 15315                               const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
 15316       const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 15317       if (beg>end || beg>=size() || end>=size())
 15318         throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 15319                                     "a (%u,%u,%u,%u) image.",
 15320                                     pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 15321       return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 15324     const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 15325                                     const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
 15326       const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 15327       if (beg>end || beg>=size() || end>=size())
 15328         throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 15329                                     "a (%u,%u,%u,%u) image.",
 15330                                     pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 15331       return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 15334     //! Return a shared-memory image referencing a set of lines of the instance image.
 15335     CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 15336                              const unsigned int z0=0, const unsigned int v0=0) {
 15337       const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 15338       if (beg>end || beg>=size() || end>=size())
 15339         throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 15340                                     "a (%u,%u,%u,%u) image.",
 15341                                     pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 15342       return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 15345     const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 15346                                    const unsigned int z0=0, const unsigned int v0=0) const {
 15347       const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 15348       if (beg>end || beg>=size() || end>=size())
 15349         throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 15350                                     "a (%u,%u,%u,%u) image.",
 15351                                     pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 15352       return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 15355     //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
 15356     CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
 15357       return get_shared_lines(y0,y0,z0,v0);
 15360     const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
 15361       return get_shared_lines(y0,y0,z0,v0);
 15364     //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
 15365     CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
 15366       const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 15367       if (beg>end || beg>=size() || end>=size())
 15368         throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 15369                                     "a (%u,%u,%u,%u) image.",
 15370                                     pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 15371       return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 15374     const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
 15375       const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 15376       if (beg>end || beg>=size() || end>=size())
 15377         throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 15378                                     "a (%u,%u,%u,%u) image.",
 15379                                     pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 15380       return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 15383     //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
 15384     CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
 15385       return get_shared_planes(z0,z0,v0);
 15388     const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
 15389       return get_shared_planes(z0,z0,v0);
 15392     //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
 15393     CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
 15394       const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 15395       if (beg>end || beg>=size() || end>=size())
 15396         throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 15397                                     "a (%u,%u,%u,%u) image.",
 15398                                     pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 15399       return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 15402     const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
 15403       const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 15404       if (beg>end || beg>=size() || end>=size())
 15405         throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 15406                                     "a (%u,%u,%u,%u) image.",
 15407                                     pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 15408       return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 15411     //! Return a shared-memory image referencing one channel v0 of the instance image.
 15412     CImg<T> get_shared_channel(const unsigned int v0) {
 15413       return get_shared_channels(v0,v0);
 15416     const CImg<T> get_shared_channel(const unsigned int v0) const {
 15417       return get_shared_channels(v0,v0);
 15420     //! Return a shared version of the instance image.
 15421     CImg<T> get_shared() {
 15422       return CImg<T>(data,width,height,depth,dim,true);
 15425     const CImg<T> get_shared() const {
 15426       return CImg<T>(data,width,height,depth,dim,true);
 15429     //! Return a 2D representation of a 3D image, with three slices.
 15430     CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 15431                            const int dx=-100, const int dy=-100, const int dz=-100) {
 15432       return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
 15435     CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 15436                               const int dx=-100, const int dy=-100, const int dz=-100) const {
 15437       if (is_empty()) return *this;
 15438       const unsigned int
 15439         nx0 = (x0>=width)?width-1:x0,
 15440         ny0 = (y0>=height)?height-1:y0,
 15441         nz0 = (z0>=depth)?depth-1:z0;
 15442       CImg<T>
 15443         imgxy(width,height,1,dim),
 15444         imgzy(depth,height,1,dim),
 15445         imgxz(width,depth,1,dim);
 15446       { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
 15447       { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
 15448       { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
 15449       imgxy.resize(dx,dy,1,dim,1);
 15450       imgzy.resize(dz,dy,1,dim,1);
 15451       imgxz.resize(dx,dz,1,dim,1);
 15452       return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
 15453         draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
 15456     //! Compute the image histogram.
 15457     /**
 15458        The histogram H of an image I is a 1D-function where H(x) is the number of
 15459        occurences of the value x in I.
 15460        \param nblevels = Number of different levels of the computed histogram.
 15461        For classical images, this value is 256. You should specify more levels
 15462        if you are working with CImg<float> or images with high range of pixel values.
 15463        \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
 15464        won't be counted.
 15465        \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
 15466        won't be counted.
 15467        \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum
 15468        pixel values of the current image, then uses these values for the histogram computation.
 15469        \result The histogram is returned as a 1D CImg<float> image H, having a size of (nblevels,1,1,1) such that
 15470        H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I.
 15471        \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
 15472        are not multi-dimensional.
 15473     **/
 15474     CImg<T>& histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
 15475       return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
 15478     CImg<floatT> get_histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
 15479       if (is_empty()) return CImg<floatT>();
 15480       if (!nblevels)
 15481         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
 15482                                     pixel_type());
 15483       T vmin = val_min, vmax = val_max;
 15484       CImg<floatT> res(nblevels,1,1,1,0);
 15485       if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
 15486       if (vmin<vmax) cimg_for(*this,ptr,T) {
 15487         const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
 15488         if (pos>=0 && pos<(int)nblevels) ++res[pos];
 15489       } else res[0]+=size();
 15490       return res;
 15493     //! Compute the histogram-equalized version of the instance image.
 15494     /**
 15495        The histogram equalization is a classical image processing algorithm that enhances the image contrast
 15496        by expanding its histogram.
 15497        \param nblevels = Number of different levels of the computed histogram.
 15498        For classical images, this value is 256. You should specify more levels
 15499        if you are working with CImg<float> or images with high range of pixel values.
 15500        \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
 15501        won't be changed.
 15502        \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
 15503        won't be changed.
 15504        \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
 15505        \return A new image with same size is returned, where pixels have been equalized.
 15506     **/
 15507     CImg<T>& equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
 15508       if (is_empty()) return *this;
 15509       T vmin = val_min, vmax = val_max;
 15510       if (vmin==vmax && vmin==0) vmin = minmax(vmax);
 15511       if (vmin<vmax) {
 15512         CImg<floatT> hist = get_histogram(nblevels,vmin,vmax);
 15513         float cumul = 0;
 15514         cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
 15515         cimg_for(*this,ptr,T) {
 15516           const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
 15517           if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
 15520       return *this;
 15523     CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
 15524       return (+*this).equalize(nblevels,val_min,val_max);
 15527     //! Get a label map of disconnected regions with same intensities.
 15528     CImg<T>& label_regions() {
 15529       return get_label_regions().transfer_to(*this);
 15532     CImg<uintT> get_label_regions() const {
 15533 #define _cimg_get_label_test(p,q) { \
 15534   flag = true; \
 15535   const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
 15536   for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
 15538       if (depth>1)
 15539         throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
 15540       CImg<uintT> res(width,height,depth,1,0);
 15541       unsigned int label = 1;
 15542       const unsigned int wh = width*height, siz = width*height*dim;
 15543       const int W1 = dimx()-1, H1 = dimy()-1;
 15544       bool flag;
 15545       cimg_forXY(*this,x,y) {
 15546         bool done = false;
 15547         if (y) {
 15548           _cimg_get_label_test(x,y-1);
 15549           if (flag) {
 15550             const unsigned int lab = (res(x,y) = res(x,y-1));
 15551             done = true;
 15552             if (x && res(x-1,y)!=lab) {
 15553               _cimg_get_label_test(x-1,y);
 15554               if (flag) {
 15555                 const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
 15556                 for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
 15561         if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
 15562         if (!done) res(x,y) = label++;
 15564       { for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
 15565         bool done = false;
 15566         if (y<H1) {
 15567           _cimg_get_label_test(x,y+1);
 15568           if (flag) {
 15569             const unsigned int lab = (res(x,y) = res(x,y+1));
 15570             done = true;
 15571             if (x<W1 && res(x+1,y)!=lab) {
 15572               _cimg_get_label_test(x+1,y);
 15573               if (flag) {
 15574                 const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
 15575                 for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
 15580         if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
 15581       }}
 15582       const unsigned int lab0 = res.max()+1;
 15583       label = lab0;
 15584       cimg_foroff(res,off) { // Relabel regions
 15585         const unsigned int lab = res[off];
 15586         if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
 15588       return (res-=lab0);
 15591     //! Compute the scalar image of vector norms.
 15592     /**
 15593        When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
 15594        vector-valued pixel.
 15595        \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
 15596        \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
 15597        of the corresponding pixels in the original vector-valued image.
 15598     **/
 15599     CImg<T>& pointwise_norm(int norm_type=2) {
 15600       return get_pointwise_norm(norm_type).transfer_to(*this);
 15603     CImg<Tfloat> get_pointwise_norm(int norm_type=2) const {
 15604       if (is_empty()) return *this;
 15605       if (dim==1) return get_abs();
 15606       CImg<Tfloat> res(width,height,depth);
 15607       switch (norm_type) {
 15608       case -1 : {             // Linf norm
 15609         cimg_forXYZ(*this,x,y,z) {
 15610           Tfloat n = 0; cimg_forV(*this,v) {
 15611             const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
 15612             if (tmp>n) n=tmp; res(x,y,z) = n;
 15615       } break;
 15616       case 1 : {              // L1 norm
 15617         cimg_forXYZ(*this,x,y,z) {
 15618           Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
 15620       } break;
 15621       default : {             // L2 norm
 15622         cimg_forXYZ(*this,x,y,z) {
 15623           Tfloat n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (Tfloat)cimg_std::sqrt((double)n);
 15627       return res;
 15630     //! Compute the image of normalized vectors.
 15631     /**
 15632        When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
 15633        (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
 15634        \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
 15635     **/
 15636     CImg<T>& pointwise_orientation() {
 15637       cimg_forXYZ(*this,x,y,z) {
 15638         float n = 0;
 15639         cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
 15640         n = (float)cimg_std::sqrt(n);
 15641         if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
 15642         else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
 15644       return *this;
 15647     CImg<Tfloat> get_pointwise_orientation() const {
 15648       if (is_empty()) return *this;
 15649       return CImg<Tfloat>(*this,false).pointwise_orientation();
 15652     //! Split image into a list.
 15653     CImgList<T> get_split(const char axis, const unsigned int nb=0) const {
 15654       if (is_empty()) return CImgList<T>();
 15655       CImgList<T> res;
 15656       switch (cimg::uncase(axis)) {
 15657       case 'x' : {
 15658         if (nb>width)
 15659           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.",
 15660                                       pixel_type(),width,height,depth,dim,data,nb);
 15661         res.assign(nb?nb:width);
 15662         const unsigned int delta = (unsigned int)cimg::round((float)width/res.size,1);
 15663         unsigned int l, x;
 15664         for (l = 0, x = 0; l<res.size-1; ++l, x+=delta) res[l] = get_crop(x,0,0,0,x+delta-1,height-1,depth-1,dim-1);
 15665         res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1);
 15666       } break;
 15667       case 'y' : {
 15668         if (nb>height)
 15669           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.",
 15670                                       pixel_type(),width,height,depth,dim,data,nb);
 15671         res.assign(nb?nb:height);
 15672         const unsigned int delta = (unsigned int)cimg::round((float)height/res.size,1);
 15673         unsigned int l, y;
 15674         for (l = 0, y = 0; l<res.size-1; ++l, y+=delta) res[l] = get_crop(0,y,0,0,width-1,y+delta-1,depth-1,dim-1);
 15675         res[res.size-1] = get_crop(0,y,0,0,width-1,height-1,depth-1,dim-1);
 15676       } break;
 15677       case 'z' : {
 15678         if (nb>depth)
 15679           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.",
 15680                                       pixel_type(),width,height,depth,dim,data,nb);
 15681         res.assign(nb?nb:depth);
 15682         const unsigned int delta = (unsigned int)cimg::round((float)depth/res.size,1);
 15683         unsigned int l, z;
 15684         for (l = 0, z = 0; l<res.size-1; ++l, z+=delta) res[l] = get_crop(0,0,z,0,width-1,height-1,z+delta-1,dim-1);
 15685         res[res.size-1] = get_crop(0,0,z,0,width-1,height-1,depth-1,dim-1);
 15686       } break;
 15687       case 'v' : {
 15688         if (nb>dim)
 15689           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.",
 15690                                       pixel_type(),width,height,depth,dim,data,nb);
 15691         res.assign(nb?nb:dim);
 15692         const unsigned int delta = (unsigned int)cimg::round((float)dim/res.size,1);
 15693         unsigned int l, v;
 15694         for (l = 0, v = 0; l<res.size-1; ++l, v+=delta) res[l] = get_crop(0,0,0,v,width-1,height-1,depth-1,v+delta-1);
 15695         res[res.size-1] = get_crop(0,0,0,v,width-1,height-1,depth-1,dim-1);
 15696       } break;
 15697       default :
 15698         throw CImgArgumentException("CImg<%s>::get_split() : Unknow axis '%c', must be 'x','y','z' or 'v'",
 15699                                     pixel_type(),axis);
 15701       return res;
 15704     // Split image into a list of vectors, according to a given splitting value.
 15705     CImgList<T> get_split(const T value, const bool keep_values, const bool shared) const {
 15706       CImgList<T> res;
 15707       const T *ptr0 = data, *const ptr_end = data + size();
 15708       while (ptr0<ptr_end) {
 15709         const T *ptr1 = ptr0;
 15710         while (ptr1<ptr_end && *ptr1==value) ++ptr1;
 15711         const unsigned int siz0 = ptr1 - ptr0;
 15712         if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
 15713         ptr0 = ptr1;
 15714         while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
 15715         const unsigned int siz1 = ptr1 - ptr0;
 15716         if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
 15717         ptr0 = ptr1;
 15719       return res;
 15722     //! Append an image to another one.
 15723     CImg<T>& append(const CImg<T>& img, const char axis, const char align='p') {
 15724       if (!img) return *this;
 15725       if (is_empty()) return (*this=img);
 15726       return get_append(img,axis,align).transfer_to(*this);
 15729     CImg<T> get_append(const CImg<T>& img, const char axis, const char align='p') const {
 15730       if (!img) return *this;
 15731       if (is_empty()) return img;
 15732       CImgList<T> temp(2);
 15733       temp[0].width = width; temp[0].height = height; temp[0].depth = depth;
 15734       temp[0].dim = dim; temp[0].data = data;
 15735       temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth;
 15736       temp[1].dim = img.dim; temp[1].data = img.data;
 15737       const CImg<T> res = temp.get_append(axis,align);
 15738       temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0;
 15739       temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0;
 15740       return res;
 15743     //! Compute the list of images, corresponding to the XY-gradients of an image.
 15744     /**
 15745        \param scheme = Numerical scheme used for the gradient computation :
 15746        - -1 = Backward finite differences
 15747        - 0 = Centered finite differences
 15748        - 1 = Forward finite differences
 15749        - 2 = Using Sobel masks
 15750        - 3 = Using rotation invariant masks
 15751        - 4 = Using Deriche recusrsive filter.
 15752     **/
 15753     CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
 15754       CImgList<Tfloat> grad(2,width,height,depth,dim);
 15755       bool threed = false;
 15756       if (axes) {
 15757         for (unsigned int a = 0; axes[a]; ++a) {
 15758           const char axis = cimg::uncase(axes[a]);
 15759           switch (axis) {
 15760           case 'x' : case 'y' : break;
 15761           case 'z' : threed = true; break;
 15762           default :
 15763             throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
 15764                                         pixel_type(),axis);
 15767       } else threed = (depth>1);
 15768       if (threed) {
 15769         grad.insert(1); grad[2].assign(width,height,depth,dim);
 15770         switch (scheme) { // Compute 3D gradient
 15771         case -1 : { // backward finite differences
 15772           CImg_3x3x3(I,T);
 15773           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 15774             grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
 15775             grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
 15776             grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
 15778         } break;
 15779         case 1 : { // forward finite differences
 15780           CImg_2x2x2(I,T);
 15781           cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
 15782             grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
 15783             grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
 15784             grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
 15786         } break;
 15787         case 4 : { // using Deriche filter with low standard variation
 15788           grad[0] = get_deriche(0,1,'x');
 15789           grad[1] = get_deriche(0,1,'y');
 15790           grad[2] = get_deriche(0,1,'z');
 15791         } break;
 15792         default : { // central finite differences
 15793           CImg_3x3x3(I,T);
 15794           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 15795             grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
 15796             grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
 15797             grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
 15801       } else switch (scheme) { // Compute 2D-gradient
 15802       case -1 : { // backward finite differences
 15803         CImg_3x3(I,T);
 15804         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 15805           grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
 15806           grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
 15808       } break;
 15809       case 1 : { // forward finite differences
 15810         CImg_2x2(I,T);
 15811         cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
 15812           grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
 15813           grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
 15815       } break;
 15816       case 2 : { // using Sobel mask
 15817         CImg_3x3(I,T);
 15818         const Tfloat a = 1, b = 2;
 15819         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 15820           grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
 15821           grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
 15823       } break;
 15824       case 3 : { // using rotation invariant mask
 15825         CImg_3x3(I,T);
 15826         const Tfloat a = (Tfloat)(0.25f*(2-cimg_std::sqrt(2.0f))), b = (Tfloat)(0.5f*(cimg_std::sqrt(2.0f)-1));
 15827         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 15828           grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
 15829           grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
 15831       } break;
 15832       case 4 : { // using Deriche filter with low standard variation
 15833         grad[0] = get_deriche(0,1,'x');
 15834         grad[1] = get_deriche(0,1,'y');
 15835       } break;
 15836       default : { // central finite differences
 15837         CImg_3x3(I,T);
 15838         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 15839           grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
 15840           grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
 15844       if (!axes) return grad;
 15845       CImgList<Tfloat> res;
 15846       for (unsigned int l = 0; axes[l]; ++l) {
 15847         const char axis = cimg::uncase(axes[l]);
 15848         switch (axis) {
 15849         case 'x' : res.insert(grad[0]); break;
 15850         case 'y' : res.insert(grad[1]); break;
 15851         case 'z' : res.insert(grad[2]); break;
 15854       grad.assign();
 15855       return res;
 15858     //! Compute the structure tensor field of an image.
 15859     CImg<T>& structure_tensor(const bool central_scheme=false) {
 15860       return get_structure_tensor(central_scheme).transfer_to(*this);
 15863     CImg<Tfloat> get_structure_tensor(const bool central_scheme=false) const {
 15864       if (is_empty()) return *this;
 15865       CImg<Tfloat> res;
 15866       if (depth>1) { // 3D version
 15867         res.assign(width,height,depth,6,0);
 15868         CImg_3x3x3(I,T);
 15869         if (central_scheme) cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // classical central finite differences
 15870           const Tfloat
 15871             ix = 0.5f*((Tfloat)Incc - Ipcc),
 15872             iy = 0.5f*((Tfloat)Icnc - Icpc),
 15873             iz = 0.5f*((Tfloat)Iccn - Iccp);
 15874           res(x,y,z,0)+=ix*ix;
 15875           res(x,y,z,1)+=ix*iy;
 15876           res(x,y,z,2)+=ix*iz;
 15877           res(x,y,z,3)+=iy*iy;
 15878           res(x,y,z,4)+=iy*iz;
 15879           res(x,y,z,5)+=iz*iz;
 15880         } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // Precise forward/backward finite differences
 15881           const Tfloat
 15882             ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
 15883             iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
 15884             izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
 15885           res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
 15886           res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
 15887           res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
 15888           res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
 15889           res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
 15890           res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
 15892       } else { // 2D version
 15893         res.assign(width,height,depth,3,0);
 15894         CImg_3x3(I,T);
 15895         if (central_scheme) cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // classical central finite differences
 15896           const Tfloat
 15897             ix = 0.5f*((Tfloat)Inc - Ipc),
 15898             iy = 0.5f*((Tfloat)Icn - Icp);
 15899           res(x,y,0,0)+=ix*ix;
 15900           res(x,y,0,1)+=ix*iy;
 15901           res(x,y,0,2)+=iy*iy;
 15902         } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // Precise forward/backward finite differences
 15903           const Tfloat
 15904             ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
 15905             iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
 15906           res(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
 15907           res(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
 15908           res(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
 15911       return res;
 15914     //! Get components of the Hessian matrix of an image.
 15915     CImgList<Tfloat> get_hessian(const char *const axes=0) const {
 15916       const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
 15917       if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
 15918       CImgList<Tfloat> res;
 15919       const int lmax = cimg::strlen(naxes);
 15920       if (lmax%2)
 15921         throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
 15922                                     pixel_type(),naxes);
 15923       res.assign(lmax/2,width,height,depth,dim);
 15924       if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
 15925         CImg_3x3x3(I,T);
 15926         cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 15927           res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc;              // Ixx
 15928           res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
 15929           res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
 15930           res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc;              // Iyy
 15931           res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
 15932           res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;              // Izz
 15934       } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
 15935         CImg_3x3(I,T);
 15936         cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 15937           res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc;             // Ixx
 15938           res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
 15939           res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc;             // Iyy
 15941       } else for (int l = 0; l<lmax; ) { // Version with custom axes.
 15942           const int l2 = l/2;
 15943           char axis1 = naxes[l++], axis2 = naxes[l++];
 15944           if (axis1>axis2) cimg::swap(axis1,axis2);
 15945           bool valid_axis = false;
 15946           if (axis1=='x' && axis2=='x') { // Ixx
 15947             valid_axis = true; CImg_3x3(I,T);
 15948             cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
 15950           else if (axis1=='x' && axis2=='y') { // Ixy
 15951             valid_axis = true; CImg_3x3(I,T);
 15952             cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp);
 15954           else if (axis1=='x' && axis2=='z') { // Ixz
 15955             valid_axis = true; CImg_3x3x3(I,T);
 15956             cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp);
 15958           else if (axis1=='y' && axis2=='y') { // Iyy
 15959             valid_axis = true; CImg_3x3(I,T);
 15960             cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
 15962           else if (axis1=='y' && axis2=='z') { // Iyz
 15963             valid_axis = true; CImg_3x3x3(I,T);
 15964             cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp);
 15966           else if (axis1=='z' && axis2=='z') { // Izz
 15967             valid_axis = true; CImg_3x3x3(I,T);
 15968             cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
 15970           else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
 15971                                                             pixel_type(),naxes);
 15973       return res;
 15976     //! Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE.
 15977     CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
 15978       if (is_empty()) return *this;
 15979       CImg<Tfloat> veloc(*this);
 15980       for (unsigned int iter = 0; iter<nb_iter; ++iter) {
 15981         veloc.fill(0);
 15982         if (depth>1) { // 3D version
 15983           CImg_3x3x3(I,T);
 15984           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
 15985             const Tfloat
 15986               gx = 0.5f*((Tfloat)Incc - Ipcc),
 15987               gy = 0.5f*((Tfloat)Icnc - Icpc),
 15988               gz = 0.5f*((Tfloat)Iccn - Iccp),
 15989               sgn = -cimg::sign((Tfloat)Iccc),
 15990               ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
 15991               iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
 15992               iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
 15993               ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy + gz*gz),
 15994               ngx = gx/ng,
 15995               ngy = gy/ng,
 15996               ngz = gz/ng;
 15997             veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
 15999         } else { // 2D version
 16000           CImg_3x3(I,T);
 16001           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
 16002             const Tfloat
 16003               gx = 0.5f*((Tfloat)Inc - Ipc),
 16004               gy = 0.5f*((Tfloat)Icn - Icp),
 16005               sgn = -cimg::sign((Tfloat)Icc),
 16006               ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
 16007               iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
 16008               ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy),
 16009               ngx = gx/ng,
 16010               ngy = gy/ng;
 16011             veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
 16014         float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
 16015         *this+=(veloc*=xdt);
 16017       return *this;
 16020     CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
 16021       return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
 16024     //! Compute the Euclidean distance map to a shape of specified isovalue.
 16025     CImg<T>& distance(const T isovalue,
 16026                       const float sizex=1, const float sizey=1, const float sizez=1,
 16027                       const bool compute_sqrt=true) {
 16028       return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
 16031     CImg<floatT> get_distance(const T isovalue,
 16032                               const float sizex=1, const float sizey=1, const float sizez=1,
 16033                               const bool compute_sqrt=true) const {
 16034       if (is_empty()) return *this;
 16035       const int dx = dimx(), dy = dimy(), dz = dimz();
 16036       CImg<floatT> res(dx,dy,dz,dim);
 16037       const float maxdist = (float)cimg_std::sqrt((float)dx*dx + dy*dy + dz*dz);
 16038       cimg_forV(*this,k) {
 16039         bool is_isophote = false;
 16041         if (depth>1) { // 3D version
 16042           { cimg_forYZ(*this,y,z) {
 16043             if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
 16044             for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
 16045             else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
 16046             { for (int x = dx-2; x>=0; --x) if (res(x+1,y,z,k)<res(x,y,z,k)) res(x,y,z,k) = res(x+1,y,z,k) + sizex; }
 16047           }}
 16048           if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
 16049           CImg<floatT> tmp(cimg::max(dy,dz));
 16050           CImg<intT> s(tmp.width), t(s.width);
 16051           { cimg_forXZ(*this,x,z) {
 16052             { cimg_forY(*this,y) tmp[y] = res(x,y,z,k); }
 16053             int q = s[0] = t[0] = 0;
 16054             { for (int y = 1; y<dy; ++y) {
 16055               const float val = tmp[y], val2 = val*val;
 16056               while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
 16057               if (q<0) { q = 0; s[0] = y; }
 16058               else {
 16059                 const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
 16060                 if (w<dy) { s[++q] = y; t[q] = w; }
 16062             }}
 16063             { for (int y = dy - 1; y>=0; --y) {
 16064               res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
 16065               if (y==t[q]) --q;
 16066             }}
 16067           }}
 16068           { cimg_forXY(*this,x,y) {
 16069             { cimg_forZ(*this,z) tmp[z] = res(x,y,z,k); }
 16070             int q = s[0] = t[0] = 0;
 16071             { for (int z = 1; z<dz; ++z) {
 16072               const float val = tmp[z];
 16073               while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
 16074               if (q<0) { q = 0; s[0] = z; }
 16075               else {
 16076                 const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
 16077                 if (w<dz) { s[++q] = z; t[q] = w; }
 16079             }}
 16080             { for (int z = dz - 1; z>=0; --z) {
 16081               const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
 16082               res(x,y,z,k) = compute_sqrt?(float)cimg_std::sqrt(val):val;
 16083               if (z==t[q]) --q;
 16084             }}
 16085           }}
 16086         } else { // 2D version (with small optimizations)
 16087           cimg_forX(*this,x) {
 16088             const T *ptrs = ptr(x,0,0,k);
 16089             float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
 16090             for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
 16091             { for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }}
 16093           if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
 16094           CImg<floatT> tmp(dx);
 16095           CImg<intT> s(dx), t(dx);
 16096           cimg_forY(*this,y) {
 16097             float *ptmp = tmp.ptr();
 16098             cimg_std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
 16099             int q = s[0] = t[0] = 0;
 16100             for (int x = 1; x<dx; ++x) {
 16101               const float val = *(++ptmp), val2 = val*val;
 16102               while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
 16103               if (q<0) { q = 0; s[0] = x; }
 16104               else {
 16105                 const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
 16106                 if (w<dx) { q++; s[q] = x; t[q] = w; }
 16109             float *pres = res.ptr(0,y,0,k) + width;
 16110             { for (int x = dx - 1; x>=0; --x) {
 16111               const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
 16112               *(--pres) = compute_sqrt?(float)cimg_std::sqrt(val):val;
 16113               if (x==t[q]) --q;
 16114             }}
 16118       return res;
 16121     static float _distance_f(const int x, const int i, const float gi2, const float fact) {
 16122       const float xmi = fact*((float)x - i);
 16123       return xmi*xmi + gi2;
 16125     static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
 16126       const float fact2 = fact*fact;
 16127       return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
 16130     //! Compute minimal path in a graph, using the Dijkstra algorithm.
 16131     /**
 16132        \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
 16133        \param nb_nodes Number of graph nodes.
 16134        \param starting_node Indice of the starting node.
 16135        \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
 16136        \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 16137        \return Array of distances of each node to the starting node.
 16138     **/
 16139     template<typename tf, typename t>
 16140     static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
 16141                             const unsigned int starting_node, const unsigned int ending_node,
 16142                             CImg<t>& previous) {
 16144       CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
 16145       dist(starting_node) = 0;
 16146       previous.assign(1,nb_nodes,1,1,(t)-1);
 16147       previous(starting_node) = (t)starting_node;
 16148       CImg<uintT> Q(nb_nodes);
 16149       cimg_forX(Q,u) Q(u) = u;
 16150       cimg::swap(Q(starting_node),Q(0));
 16151       unsigned int sizeQ = nb_nodes;
 16152       while (sizeQ) {
 16153         // Update neighbors from minimal vertex
 16154         const unsigned int umin = Q(0);
 16155         if (umin==ending_node) sizeQ = 0;
 16156         else {
 16157           const T dmin = dist(umin);
 16158           const T infty = cimg::type<T>::max();
 16159           for (unsigned int q=1; q<sizeQ; ++q) {
 16160             const unsigned int v = Q(q);
 16161             const T d = (T)distance(v,umin);
 16162             if (d<infty) {
 16163               const T alt = dmin + d;
 16164               if (alt<dist(v)) {
 16165                 dist(v) = alt;
 16166                 previous(v) = (t)umin;
 16167                 const T distpos = dist(Q(q));
 16168                 for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
 16172           // Remove minimal vertex from queue
 16173           Q(0) = Q(--sizeQ);
 16174           const T distpos = dist(Q(0));
 16175           for (unsigned int pos = 0, left = 0, right = 0;
 16176                ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
 16177             if (right<sizeQ) {
 16178               if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
 16179               else { cimg::swap(Q(pos),Q(right)); pos = right; }
 16180             } else { cimg::swap(Q(pos),Q(left)); pos = left; }
 16184       return dist;
 16187     //! Return minimal path in a graph, using the Dijkstra algorithm.
 16188     template<typename tf, typename t>
 16189     static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
 16190                             const unsigned int starting_node, const unsigned int ending_node=~0U) {
 16191       CImg<uintT> foo;
 16192       return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
 16195     //! Return minimal path in a graph, using the Dijkstra algorithm.
 16196     /**
 16197        Instance image corresponds to the adjacency matrix of the graph.
 16198        \param starting_node Indice of the starting node.
 16199        \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 16200        \return Array of distances of each node to the starting node.
 16201     **/
 16202     template<typename t>
 16203     CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
 16204       return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
 16207     template<typename t>
 16208     CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
 16209       if (width!=height || depth!=1 || dim!=1)
 16210         throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
 16211                                     pixel_type(),width,height,depth,dim,data);
 16212       return dijkstra(*this,width,starting_node,ending_node,previous);
 16215     //! Return minimal path in a graph, using the Dijkstra algorithm.
 16216     CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
 16217       return get_dijkstra(starting_node,ending_node).transfer_to(*this);
 16220     CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
 16221       CImg<uintT> foo;
 16222       return get_dijkstra(starting_node,ending_node,foo);
 16225     //@}
 16226     //-------------------------------------
 16227     //
 16228     //! \name Meshes and Triangulations
 16229     //@{
 16230     //-------------------------------------
 16232     //! Return a 3D centered cube.
 16233     template<typename tf>
 16234     static CImg<floatT> cube3d(CImgList<tf>& primitives, const float size=100) {
 16235       const double s = size/2.0;
 16236       primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
 16237       return CImg<floatT>(8,3,1,1,
 16238                           -s,s,s,-s,-s,s,s,-s,
 16239                           -s,-s,s,s,-s,-s,s,s,
 16240                           -s,-s,-s,-s,s,s,s,s);
 16243     //! Return a 3D centered cuboid.
 16244     template<typename tf>
 16245     static CImg<floatT> cuboid3d(CImgList<tf>& primitives, const float sizex=200,
 16246                                  const float sizey=100, const float sizez=100) {
 16247       const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
 16248       primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
 16249       return CImg<floatT>(8,3,1,1,
 16250                           -sx,sx,sx,-sx,-sx,sx,sx,-sx,
 16251                           -sy,-sy,sy,sy,-sy,-sy,sy,sy,
 16252                           -sz,-sz,-sz,-sz,sz,sz,sz,sz);
 16255     //! Return a 3D centered cone.
 16256     template<typename tf>
 16257     static CImg<floatT> cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 16258                                const unsigned int subdivisions=24, const bool symetrize=false) {
 16259       primitives.assign();
 16260       if (!subdivisions) return CImg<floatT>();
 16261       const double r = (double)radius, h = (double)height/2;
 16262       CImgList<floatT> points(2,1,3,1,1,
 16263                               0.0,0.0,h,
 16264                               0.0,0.0,-h);
 16265       const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
 16266       for (float angle = 0; angle<360; angle+=delta) {
 16267         const float a = (float)(angle*cimg::valuePI/180);
 16268         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),nh));
 16270       const unsigned int nbr = points.size-2;
 16271       for (unsigned int p = 0; p<nbr; ++p) {
 16272         const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
 16273         primitives.insert(CImg<tf>::vector(1,next,curr)).
 16274           insert(CImg<tf>::vector(0,curr,next));
 16276       return points.get_append('x');
 16279     //! Return a 3D centered cylinder.
 16280     template<typename tf>
 16281     static CImg<floatT> cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 16282                                    const unsigned int subdivisions=24) {
 16283       primitives.assign();
 16284       if (!subdivisions) return CImg<floatT>();
 16285       const double r = (double)radius, h = (double)height/2;
 16286       CImgList<floatT> points(2,1,3,1,1,
 16287                               0.0,0.0,-h,
 16288                               0.0,0.0,h);
 16290       const float delta = 360.0f/subdivisions;
 16291       for (float angle = 0; angle<360; angle+=delta) {
 16292         const float a = (float)(angle*cimg::valuePI/180);
 16293         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),-(float)h));
 16294         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),(float)h));
 16296       const unsigned int nbr = (points.size-2)/2;
 16297       for (unsigned int p = 0; p<nbr; ++p) {
 16298         const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
 16299         primitives.insert(CImg<tf>::vector(0,next,curr)).
 16300           insert(CImg<tf>::vector(1,curr+1,next+1)).
 16301           insert(CImg<tf>::vector(curr,next,next+1,curr+1));
 16303       return points.get_append('x');
 16306     //! Return a 3D centered torus.
 16307     template<typename tf>
 16308     static CImg<floatT> torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
 16309                                 const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
 16310       primitives.assign();
 16311       if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
 16312       CImgList<floatT> points;
 16313       for (unsigned int v = 0; v<subdivisions1; ++v) {
 16314         const float
 16315           beta = (float)(v*2*cimg::valuePI/subdivisions1),
 16316           xc = radius1*(float)cimg_std::cos(beta),
 16317           yc = radius1*(float)cimg_std::sin(beta);
 16318         for (unsigned int u=0; u<subdivisions2; ++u) {
 16319           const float
 16320             alpha = (float)(u*2*cimg::valuePI/subdivisions2),
 16321             x = xc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::cos(beta)),
 16322             y = yc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::sin(beta)),
 16323             z = radius2*(float)cimg_std::sin(alpha);
 16324           points.insert(CImg<floatT>::vector(x,y,z));
 16327       for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
 16328         const unsigned int nv = (vv+1)%subdivisions1;
 16329         for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
 16330           const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
 16331           primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
 16332           primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
 16335       return points.get_append('x');
 16338     //! Return a 3D centered XY plane.
 16339     template<typename tf>
 16340     static CImg<floatT> plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
 16341                                 const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
 16342                                 const bool double_sided=false) {
 16343       primitives.assign();
 16344       if (!subdivisionsx || !subdivisionsy) return CImg<floatT>();
 16345       CImgList<floatT> points;
 16346       const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
 16347       const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
 16348       for (unsigned int yy = 0; yy<h; ++yy)
 16349         for (unsigned int xx = 0; xx<w; ++xx)
 16350           points.insert(CImg<floatT>::vector(fx*(xx-w2),fy*(yy-h2),0));
 16351       for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
 16352         const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
 16353         primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
 16354         if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
 16356       return points.get_append('x');
 16359     //! Return a 3D centered sphere.
 16360     template<typename tf>
 16361     static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
 16363       // Create initial icosahedron
 16364       primitives.assign();
 16365       if (!subdivisions) return CImg<floatT>();
 16366       const double tmp = (1+cimg_std::sqrt(5.0f))/2, a = 1.0/cimg_std::sqrt(1+tmp*tmp), b = tmp*a;
 16367       CImgList<floatT> points(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b,
 16368                               -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
 16369       primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6,
 16370                         8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
 16371                         5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
 16373       // Recurse subdivisions
 16374       for (unsigned int i = 0; i<subdivisions; ++i) {
 16375         const unsigned int L = primitives.size;
 16376         for (unsigned int l = 0; l<L; ++l) {
 16377           const unsigned int
 16378             p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
 16379           const float
 16380             x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
 16381             x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
 16382             x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
 16383             tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)cimg_std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
 16384             tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)cimg_std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
 16385             tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)cimg_std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
 16386             nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
 16387             nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
 16388             nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
 16389           int i0 = -1, i1 = -1, i2 = -1;
 16390           cimglist_for(points,p) {
 16391             const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
 16392             if (x==nx0 && y==ny0 && z==nz0) i0 = p;
 16393             if (x==nx1 && y==ny1 && z==nz1) i1 = p;
 16394             if (x==nx2 && y==ny2 && z==nz2) i2 = p;
 16396           if (i0<0) { points.insert(CImg<floatT>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
 16397           if (i1<0) { points.insert(CImg<floatT>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
 16398           if (i2<0) { points.insert(CImg<floatT>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
 16399           primitives.remove(0);
 16400           primitives.insert(CImg<tf>::vector(p0,i0,i1)).
 16401             insert(CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2)).
 16402             insert(CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2)).
 16403             insert(CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2));
 16406       return points.get_append('x')*=radius;
 16409     //! Return a 3D centered ellipsoid.
 16410     template<typename tf, typename t>
 16411     static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor,
 16412                                     const unsigned int subdivisions=3) {
 16413       primitives.assign();
 16414       if (!subdivisions) return CImg<floatT>();
 16415       typedef typename cimg::superset<t,float>::type tfloat;
 16416       CImg<tfloat> S,V;
 16417       tensor.symmetric_eigen(S,V);
 16418       const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
 16419       CImg<floatT> points = sphere(primitives,subdivisions);
 16420       cimg_forX(points,p) {
 16421         points(p,0) = (float)(points(p,0)*l0);
 16422         points(p,1) = (float)(points(p,1)*l1);
 16423         points(p,2) = (float)(points(p,2)*l2);
 16425       V.transpose();
 16426       points = V*points;
 16427       return points;
 16430     //! Return a 3D elevation object of the instance image.
 16431     template<typename tf, typename tc, typename te>
 16432     CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
 16433       primitives.assign();
 16434       colors.assign();
 16435       if (is_empty()) return *this;
 16436       if (depth>1)
 16437         throw CImgInstanceException("CImg<%s>::get_elevation3d() : Instance image (%u,%u,%u,%u,%p) is not a 2D image.",
 16438                                     pixel_type(),width,height,depth,dim,data);
 16439       if (!is_sameXY(elevation))
 16440         throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
 16441                                     "have different sizes.",pixel_type(),
 16442                                     elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
 16443                                     width,height,depth,dim,data,pixel_type());
 16444       float m, M = (float)maxmin(m);
 16445       if (M==m) ++M;
 16446       const unsigned int w = width + 1, h = height + 1;
 16447       CImg<floatT> points(w*h,3);
 16448       cimg_forXY(*this,x,y) {
 16449         const int yw = y*w, xpyw = x + yw, xpyww = xpyw + w;
 16450         points(xpyw,0) = points(xpyw+1,0) = points(xpyww+1,0) = points(xpyww,0) = (float)x;
 16451         points(xpyw,1) = points(xpyw+1,1) = points(xpyww+1,1) = points(xpyww,1) = (float)y;
 16452         points(xpyw,2) = points(xpyw+1,2) = points(xpyww+1,2) = points(xpyww,2) = (float)elevation(x,y);
 16453         primitives.insert(CImg<tf>::vector(xpyw,xpyw+1,xpyww+1,xpyww));
 16454         const unsigned char
 16455           r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
 16456           g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
 16457           b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
 16458         colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
 16460       return points;
 16463     // Inner routine used by the Marching square algorithm.
 16464     template<typename t>
 16465     static int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
 16466                                         const unsigned int x, const unsigned int nx) {
 16467       switch (edge) {
 16468       case 0 : return (int)indices1(x,0);
 16469       case 1 : return (int)indices1(nx,1);
 16470       case 2 : return (int)indices2(x,0);
 16471       case 3 : return (int)indices1(x,1);
 16473       return 0;
 16476     //! Polygonize an implicit 2D function by the marching squares algorithm.
 16477     template<typename tf, typename tfunc>
 16478     static CImg<floatT> marching_squares(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
 16479                                          const float x0, const float y0,
 16480                                          const float x1, const float y1,
 16481                                          const float resx, const float resy) {
 16482       static unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
 16483       static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
 16484                                      { 1,2,-1,-1 },   { 0,1,2,3 },   { 0,2,-1,-1 }, { 2,3,-1,-1 },
 16485                                      { 2,3,-1,-1 },   { 0,2,-1,-1},  { 0,3,1,2 },   { 1,2,-1,-1 },
 16486                                      { 1,3,-1,-1 },   { 0,1,-1,-1},  { 0,3,-1,-1},  { -1,-1,-1,-1 } };
 16487       const unsigned int
 16488         nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
 16489         ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1;
 16490       if (!nxm1 || !nym1) return CImg<floatT>();
 16492       primitives.assign();
 16493       CImgList<floatT> points;
 16494       CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
 16495       CImg<floatT> values1(nx), values2(nx);
 16496       float X = 0, Y = 0, nX = 0, nY = 0;
 16498       // Fill first line with values
 16499       cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; }
 16501       // Run the marching squares algorithm
 16502       Y = y0; nY = Y + resy;
 16503       for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) {
 16504         X = x0; nX = X + resx;
 16505         indices2.fill(-1);
 16506         for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) {
 16508           // Determine cube configuration
 16509           const float
 16510             val0 = values1(xi), val1 = values1(nxi),
 16511             val2 = values2(nxi) = (float)func(nX,nY),
 16512             val3 = values2(xi) = (float)func(X,nY);
 16514           const unsigned int configuration = (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0),
 16515             edge = edges[configuration];
 16517           // Compute intersection points
 16518           if (edge) {
 16519             if ((edge&1) && indices1(xi,0)<0) {
 16520               const float Xi = X + (isovalue-val0)*resx/(val1-val0);
 16521               indices1(xi,0) = points.size;
 16522               points.insert(CImg<floatT>::vector(Xi,Y));
 16524             if ((edge&2) && indices1(nxi,1)<0) {
 16525               const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
 16526               indices1(nxi,1) = points.size;
 16527               points.insert(CImg<floatT>::vector(nX,Yi));
 16529             if ((edge&4) && indices2(xi,0)<0) {
 16530               const float Xi = X + (isovalue-val3)*resx/(val2-val3);
 16531               indices2(xi,0) = points.size;
 16532               points.insert(CImg<floatT>::vector(Xi,nY));
 16534             if ((edge&8) && indices1(xi,1)<0) {
 16535               const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
 16536               indices1(xi,1) = points.size;
 16537               points.insert(CImg<floatT>::vector(X,Yi));
 16540             // Create segments
 16541             for (int *segment = segments[configuration]; *segment!=-1; ) {
 16542               const unsigned int p0 = *(segment++), p1 = *(segment++);
 16543               const tf
 16544                 i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)),
 16545                 i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi));
 16546               primitives.insert(CImg<tf>::vector(i0,i1));
 16550         values1.swap(values2);
 16551         indices1.swap(indices2);
 16553       return points.get_append('x');
 16556     // Inner routine used by the Marching cube algorithm.
 16557     template<typename t>
 16558     static int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
 16559                                       const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
 16560       switch (edge) {
 16561       case 0 : return indices1(x,y,0);
 16562       case 1 : return indices1(nx,y,1);
 16563       case 2 : return indices1(x,ny,0);
 16564       case 3 : return indices1(x,y,1);
 16565       case 4 : return indices2(x,y,0);
 16566       case 5 : return indices2(nx,y,1);
 16567       case 6 : return indices2(x,ny,0);
 16568       case 7 : return indices2(x,y,1);
 16569       case 8 : return indices1(x,y,2);
 16570       case 9 : return indices1(nx,y,2);
 16571       case 10 : return indices1(nx,ny,2);
 16572       case 11 : return indices1(x,ny,2);
 16574       return 0;
 16577     //! Polygonize an implicit function
 16578     // This function uses the Marching Cubes Tables published on the web page :
 16579     // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
 16580     template<typename tf, typename tfunc>
 16581     static CImg<floatT> marching_cubes(CImgList<tf>& primitives,
 16582                                        const tfunc& func, const float isovalue,
 16583                                        const float x0, const float y0, const float z0,
 16584                                        const float x1, const float y1, const float z1,
 16585                                        const float resx, const float resy, const float resz,
 16586                                        const bool invert_faces=false) {
 16588       static unsigned int edges[256] = {
 16589         0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
 16590         0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
 16591         0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
 16592         0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
 16593         0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
 16594         0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
 16595         0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
 16596         0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
 16597         0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
 16598         0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
 16599         0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
 16600         0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
 16601         0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
 16602         0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
 16603         0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
 16604         0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
 16606       static int triangles[256][16] =
 16607         {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16608          { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16609          { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16610          { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
 16611          { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16612          { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
 16613          { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
 16614          { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16615          { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16616          { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
 16617          { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
 16618          { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
 16619          { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
 16620          { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
 16621          { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
 16622          { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
 16623          { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16624          { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
 16625          { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
 16626          { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
 16627          { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
 16628          { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
 16629          { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
 16630          { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
 16631          { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
 16632          { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16633          { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
 16634          { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
 16635          { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
 16636          { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
 16637          { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
 16638          { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16639          { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16640          { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
 16641          { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
 16642          { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
 16643          { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
 16644          { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
 16645          { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
 16646          { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
 16647          { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
 16648          { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
 16649          { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
 16650          { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
 16651          { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
 16652          { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
 16653          { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
 16654          { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
 16655          { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
 16656          { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
 16657          { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
 16658          { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
 16659          { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
 16660          { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
 16661          { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
 16662          { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16663          { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
 16664          { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
 16665          { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
 16666          { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16667          { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
 16668          { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
 16669          { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16670          { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16671          { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16672          { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
 16673          { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
 16674          { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
 16675          { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
 16676          { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
 16677          { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
 16678          { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
 16679          { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
 16680          { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
 16681          { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
 16682          { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
 16683          { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16684          { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
 16685          { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
 16686          { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16687          { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
 16688          { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
 16689          { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
 16690          { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
 16691          { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
 16692          { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
 16693          { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
 16694          { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
 16695          { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
 16696          { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
 16697          { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
 16698          { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
 16699          { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
 16700          { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16701          { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
 16702          { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16703          { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
 16704          { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
 16705          { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
 16706          { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
 16707          { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
 16708          { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
 16709          { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
 16710          { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16711          { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
 16712          { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
 16713          { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
 16714          { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16715          { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
 16716          { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
 16717          { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16718          { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16719          { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
 16720          { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
 16721          { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
 16722          { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
 16723          { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
 16724          { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16725          { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
 16726          { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16727          { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
 16728          { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16729          { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
 16730          { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16731          { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16732          { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16733          { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 16734          { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }};
 16736       const unsigned int
 16737         nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
 16738         ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1,
 16739         nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1;
 16740       if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
 16742       primitives.assign();
 16743       CImgList<floatT> points;
 16744       CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
 16745       CImg<floatT> values1(nx,ny), values2(nx,ny);
 16746       float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
 16748       // Fill the first plane with function values
 16749       Y = y0;
 16750       cimg_forY(values1,y) {
 16751         X = x0;
 16752         cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; }
 16753         Y+=resy;
 16756       // Run Marching Cubes algorithm
 16757       Z = z0; nZ = Z + resz;
 16758       for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=resz) {
 16759         Y = y0; nY = Y + resy;
 16760         indices2.fill(-1);
 16761         for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=resy) {
 16762           X = x0; nX = X + resx;
 16763           for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=resx) {
 16765             // Determine cube configuration
 16766             const float
 16767               val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi),
 16768               val4 = values2(xi,yi) = (float)func(X,Y,nZ),
 16769               val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
 16770               val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
 16771               val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
 16773             const unsigned int configuration =
 16774               (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0) |
 16775               (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
 16776               edge = edges[configuration];
 16778             // Compute intersection points
 16779             if (edge) {
 16780               if ((edge&1) && indices1(xi,yi,0)<0) {
 16781                 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
 16782                 indices1(xi,yi,0) = points.size;
 16783                 points.insert(CImg<floatT>::vector(Xi,Y,Z));
 16785               if ((edge&2) && indices1(nxi,yi,1)<0) {
 16786                 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
 16787                 indices1(nxi,yi,1) = points.size;
 16788                 points.insert(CImg<floatT>::vector(nX,Yi,Z));
 16790               if ((edge&4) && indices1(xi,nyi,0)<0) {
 16791                 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
 16792                 indices1(xi,nyi,0) = points.size;
 16793                 points.insert(CImg<floatT>::vector(Xi,nY,Z));
 16795               if ((edge&8) && indices1(xi,yi,1)<0) {
 16796                 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
 16797                 indices1(xi,yi,1) = points.size;
 16798                 points.insert(CImg<floatT>::vector(X,Yi,Z));
 16800               if ((edge&16) && indices2(xi,yi,0)<0) {
 16801                 const float Xi = X + (isovalue-val4)*resx/(val5-val4);
 16802                 indices2(xi,yi,0) = points.size;
 16803                 points.insert(CImg<floatT>::vector(Xi,Y,nZ));
 16805               if ((edge&32) && indices2(nxi,yi,1)<0) {
 16806                 const float Yi = Y + (isovalue-val5)*resy/(val6-val5);
 16807                 indices2(nxi,yi,1) = points.size;
 16808                 points.insert(CImg<floatT>::vector(nX,Yi,nZ));
 16810               if ((edge&64) && indices2(xi,nyi,0)<0) {
 16811                 const float Xi = X + (isovalue-val7)*resx/(val6-val7);
 16812                 indices2(xi,nyi,0) = points.size;
 16813                 points.insert(CImg<floatT>::vector(Xi,nY,nZ));
 16815               if ((edge&128) && indices2(xi,yi,1)<0)  {
 16816                 const float Yi = Y + (isovalue-val4)*resy/(val7-val4);
 16817                 indices2(xi,yi,1) = points.size;
 16818                 points.insert(CImg<floatT>::vector(X,Yi,nZ));
 16820               if ((edge&256) && indices1(xi,yi,2)<0) {
 16821                 const float Zi = Z+ (isovalue-val0)*resz/(val4-val0);
 16822                 indices1(xi,yi,2) = points.size;
 16823                 points.insert(CImg<floatT>::vector(X,Y,Zi));
 16825               if ((edge&512) && indices1(nxi,yi,2)<0)  {
 16826                 const float Zi = Z + (isovalue-val1)*resz/(val5-val1);
 16827                 indices1(nxi,yi,2) = points.size;
 16828                 points.insert(CImg<floatT>::vector(nX,Y,Zi));
 16830               if ((edge&1024) && indices1(nxi,nyi,2)<0) {
 16831                 const float Zi = Z + (isovalue-val2)*resz/(val6-val2);
 16832                 indices1(nxi,nyi,2) = points.size;
 16833                 points.insert(CImg<floatT>::vector(nX,nY,Zi));
 16835               if ((edge&2048) && indices1(xi,nyi,2)<0) {
 16836                 const float Zi = Z + (isovalue-val3)*resz/(val7-val3);
 16837                 indices1(xi,nyi,2) = points.size;
 16838                 points.insert(CImg<floatT>::vector(X,nY,Zi));
 16841               // Create triangles
 16842               for (int *triangle = triangles[configuration]; *triangle!=-1; ) {
 16843                 const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
 16844                 const tf
 16845                   i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
 16846                   i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
 16847                   i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
 16848                 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
 16849                 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
 16854         cimg::swap(values1,values2);
 16855         cimg::swap(indices1,indices2);
 16857       return points.get_append('x');
 16860     struct _marching_squares_func {
 16861       const CImg<T>& ref;
 16862       _marching_squares_func(const CImg<T>& pref):ref(pref) {}
 16863       float operator()(const float x, const float y) const {
 16864         return (float)ref((int)x,(int)y);
 16866     };
 16868     struct _marching_cubes_func {
 16869       const CImg<T>& ref;
 16870       _marching_cubes_func(const CImg<T>& pref):ref(pref) {}
 16871       float operator()(const float x, const float y, const float z) const {
 16872         return (float)ref((int)x,(int)y,(int)z);
 16874     };
 16876     struct _marching_squares_func_float {
 16877       const CImg<T>& ref;
 16878       _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
 16879       float operator()(const float x, const float y) const {
 16880         return (float)ref._linear_atXY(x,y);
 16882     };
 16884     struct _marching_cubes_func_float {
 16885       const CImg<T>& ref;
 16886       _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
 16887       float operator()(const float x, const float y, const float z) const {
 16888         return (float)ref._linear_atXYZ(x,y,z);
 16890     };
 16892     //! Compute a vectorization of an implicit function.
 16893     template<typename tf>
 16894     CImg<floatT> get_isovalue3d(CImgList<tf>& primitives, const float isovalue,
 16895                                 const float resx=1, const float resy=1, const float resz=1,
 16896                                 const bool invert_faces=false) const {
 16897       primitives.assign();
 16898       if (is_empty()) return *this;
 16899       if (dim>1)
 16900         throw CImgInstanceException("CImg<%s>::get_isovalue3d() : Instance image (%u,%u,%u,%u,%p) is not a scalar image.",
 16901                                     pixel_type(),width,height,depth,dim,data);
 16902       CImg<floatT> points;
 16903       if (depth>1) {
 16904         if (resx==1 && resy==1 && resz==1) {
 16905           const _marching_cubes_func func(*this);
 16906           points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
 16907         } else {
 16908           const _marching_cubes_func_float func(*this);
 16909           points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
 16911       } else {
 16912         if (resx==1 && resy==1) {
 16913           const _marching_squares_func func(*this);
 16914           points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
 16915         } else {
 16916           const _marching_squares_func_float func(*this);
 16917           points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
 16919         if (points) points.resize(-100,3,1,1,0);
 16921       return points;
 16924     //! Translate a 3D object.
 16925     CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
 16926       get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
 16927       return *this;
 16930     CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
 16931       return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
 16934     //! Translate a 3D object so that it becomes centered.
 16935     CImg<T>& translate_object3d() {
 16936       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 16937       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 16938       xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
 16939       return *this;
 16942     CImg<Tfloat> get_translate_object3d() const {
 16943       return CImg<Tfloat>(*this,false).translate_object3d();
 16946     //! Resize a 3D object.
 16947     CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
 16948       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 16949       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 16950       if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
 16951       if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
 16952       if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
 16953       return *this;
 16956     CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
 16957       return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
 16960     // Resize a 3D object so that its max dimension if one.
 16961     CImg<T> resize_object3d() const {
 16962       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 16963       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 16964       const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
 16965       if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
 16966       return *this;
 16969     CImg<Tfloat> get_resize_object3d() const {
 16970       return CImg<Tfloat>(*this,false).resize_object3d();
 16973     //! Append a 3D object to another one.
 16974     template<typename tf, typename tp, typename tff>
 16975     CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
 16976       const unsigned int P = width;
 16977       append(obj_points,'x');
 16978       const unsigned int N = primitives.size;
 16979       primitives.insert(obj_primitives);
 16980       for (unsigned int i = N; i<primitives.size; ++i) {
 16981         CImg<tf> &p = primitives[i];
 16982         if (p.size()!=5) p+=P;
 16983         else { p[0]+=P; if (p[2]==0) p[1]+=P; }
 16985       return *this;
 16988     //@}
 16989     //----------------------------
 16990     //
 16991     //! \name Color bases
 16992     //@{
 16993     //----------------------------
 16995     //! Return a default indexed color palette with 256 (R,G,B) entries.
 16996     /**
 16997        The default color palette is used by %CImg when displaying images on 256 colors displays.
 16998        It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
 16999        (i.e 8 levels for the Red and Green and 4 levels for the Blue).
 17000        \return a 1x256x1x3 color image defining the palette entries.
 17001     **/
 17002     static CImg<Tuchar> default_LUT8() {
 17003       static CImg<Tuchar> palette;
 17004       if (!palette) {
 17005         palette.assign(1,256,1,3);
 17006         for (unsigned int index = 0, r = 16; r<256; r+=32)
 17007           for (unsigned int g = 16; g<256; g+=32)
 17008             for (unsigned int b = 32; b<256; b+=64) {
 17009               palette(0,index,0) = (Tuchar)r;
 17010               palette(0,index,1) = (Tuchar)g;
 17011               palette(0,index++,2) = (Tuchar)b;
 17014       return palette;
 17017     //! Return a rainbow color palette with 256 (R,G,B) entries.
 17018     static CImg<Tuchar> rainbow_LUT8() {
 17019       static CImg<Tuchar> palette;
 17020       if (!palette) {
 17021         CImg<Tint> tmp(1,256,1,3,1);
 17022         tmp.get_shared_channel(0).sequence(0,359);
 17023         palette = tmp.HSVtoRGB();
 17025       return palette;
 17028     //! Return a contrasted color palette with 256 (R,G,B) entries.
 17029     static CImg<Tuchar> contrast_LUT8() {
 17030       static const unsigned char pal[] = {
 17031         217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226,
 17032         17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119,
 17033         238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20,
 17034         233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74,
 17035         81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219,
 17036         1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12,
 17037         87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0,
 17038         223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32,
 17039         233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4,
 17040         137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224,
 17041         4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247,
 17042         11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246,
 17043         0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10,
 17044         141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143,
 17045         116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244,
 17046         255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0,
 17047         235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251,
 17048         129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30,
 17049         243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215,
 17050         95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3,
 17051         141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174,
 17052         154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87,
 17053         33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21,
 17054         23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
 17055       static const CImg<Tuchar> palette(pal,1,256,1,3,false);
 17056       return palette;
 17059     //! Convert (R,G,B) color image to indexed color image.
 17060     template<typename t>
 17061     CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
 17062       return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
 17065     template<typename t>
 17066     CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
 17067       if (is_empty()) return CImg<t>();
 17068       if (dim!=3)
 17069         throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
 17070                                     "should be a (R,G,B) image.",
 17071                                     pixel_type(),dim);
 17072       if (palette.data && palette.dim!=3)
 17073         throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
 17074                                     "should be a (R,G,B) palette",
 17075                                     pixel_type(),palette.dim);
 17076       CImg<t> res(width,height,depth,indexing?1:3);
 17077       float *line1 = new float[3*width], *line2 = new float[3*width];
 17078       t *pRd = res.ptr(0,0,0,0), *pGd = indexing?pRd:res.ptr(0,0,0,1), *pBd = indexing?pRd:res.ptr(0,0,0,2);
 17079       cimg_forZ(*this,z) {
 17080         const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
 17081         float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
 17082         cimg_forY(*this,y) {
 17083           cimg::swap(line1,line2);
 17084           if (y<dimy()-1) {
 17085             const int ny = y + 1;
 17086             const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
 17087             float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
 17089           float *ptr1 = line1, *ptr2 = line2;
 17090           cimg_forX(*this,x) {
 17091             float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
 17092             R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
 17093             t Rbest = 0, Gbest = 0, Bbest = 0;
 17094             int best_index = 0;
 17095             if (palette) { // find best match in given color palette
 17096               const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
 17097               const unsigned int Npal = palette.width*palette.height*palette.depth;
 17098               float min = cimg::type<float>::max();
 17099               for (unsigned int off = 0; off<Npal; ++off) {
 17100                 const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
 17101                 const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
 17102                 if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
 17104             } else {
 17105               Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
 17106               best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
 17108             if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
 17109             if (dithering) { // apply dithering to neighborhood pixels if needed
 17110               const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
 17111               if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
 17112               if (y<dimy()-1) {
 17113                 *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2;
 17114                 if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; }
 17115                 if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; }
 17118             ptr2+=3;
 17122       delete[] line1; delete[] line2;
 17123       return res;
 17126     //! Convert color pixels from (R,G,B) to match the default palette.
 17127     CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
 17128       return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
 17131     CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
 17132       static const CImg<Tuchar> empty;
 17133       return get_RGBtoLUT(empty,dithering,indexing);
 17136     //! Convert an indexed image to a (R,G,B) image using the specified color palette.
 17137     CImg<T>& LUTtoRGB(const CImg<T>& palette) {
 17138       return get_LUTtoRGB(palette).transfer_to(*this);
 17141     template<typename t>
 17142     CImg<t> get_LUTtoRGB(const CImg<t>& palette) const {
 17143       if (is_empty()) return CImg<t>();
 17144       if (dim!=1)
 17145         throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, "
 17146                                     "should be a LUT image",
 17147                                     pixel_type(),dim);
 17148       if (palette.data && palette.dim!=3)
 17149         throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
 17150                                     "should be a (R,G,B) palette",
 17151                                     pixel_type(),palette.dim);
 17152       const CImg<t> pal = palette.data?palette:CImg<t>(default_LUT8());
 17153       CImg<t> res(width,height,depth,3);
 17154       const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
 17155       t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
 17156       const unsigned int Npal = palette.width*palette.height*palette.depth;
 17157       cimg_for(*this,ptr,T) {
 17158         const unsigned int index = ((unsigned int)*ptr)%Npal;
 17159         *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
 17161       return res;
 17164     //! Convert an indexed image (with the default palette) to a (R,G,B) image.
 17165     CImg<T>& LUTtoRGB() {
 17166       return get_LUTtoRGB().transfer_to(*this);
 17169     CImg<Tuchar> get_LUTtoRGB() const {
 17170       static const CImg<Tuchar> empty;
 17171       return get_LUTtoRGB(empty);
 17174     //! Convert color pixels from (R,G,B) to (H,S,V).
 17175     CImg<T>& RGBtoHSV() {
 17176       if (is_empty()) return *this;
 17177       if (dim!=3)
 17178         throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
 17179                                     "should be a (R,G,B) image.",
 17180                                     pixel_type(),dim);
 17181       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17182       for (unsigned long N = width*height*depth; N; --N) {
 17183         const Tfloat
 17184           R = (Tfloat)*p1,
 17185           G = (Tfloat)*p2,
 17186           B = (Tfloat)*p3,
 17187           nR = (R<0?0:(R>255?255:R))/255,
 17188           nG = (G<0?0:(G>255?255:G))/255,
 17189           nB = (B<0?0:(B>255?255:B))/255,
 17190           m = cimg::min(nR,nG,nB),
 17191           M = cimg::max(nR,nG,nB);
 17192         Tfloat H = 0, S = 0;
 17193         if (M!=m) {
 17194           const Tfloat
 17195             f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 17196             i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
 17197           H = (i-f/(M-m));
 17198           if (H>=6) H-=6;
 17199           H*=60;
 17200           S = (M-m)/M;
 17202         *(p1++) = (T)H;
 17203         *(p2++) = (T)S;
 17204         *(p3++) = (T)M;
 17206       return *this;
 17209     CImg<Tfloat> get_RGBtoHSV() const {
 17210       return CImg<Tfloat>(*this,false).RGBtoHSV();
 17213     //! Convert color pixels from (H,S,V) to (R,G,B).
 17214     CImg<T>& HSVtoRGB() {
 17215     if (is_empty()) return *this;
 17216     if (dim!=3)
 17217       throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
 17218                                   "should be a (H,S,V) image",
 17219                                   pixel_type(),dim);
 17220     T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17221     for (unsigned long N = width*height*depth; N; --N) {
 17222       Tfloat
 17223         H = (Tfloat)*p1,
 17224         S = (Tfloat)*p2,
 17225         V = (Tfloat)*p3,
 17226         R = 0, G = 0, B = 0;
 17227       if (H==0 && S==0) R = G = B = V;
 17228       else {
 17229         H/=60;
 17230         const int i = (int)cimg_std::floor(H);
 17231         const Tfloat
 17232           f = (i&1)?(H-i):(1-H+i),
 17233           m = V*(1-S),
 17234           n = V*(1-S*f);
 17235         switch (i) {
 17236         case 6 :
 17237         case 0 : R = V; G = n; B = m; break;
 17238         case 1 : R = n; G = V; B = m; break;
 17239         case 2 : R = m; G = V; B = n; break;
 17240         case 3 : R = m; G = n; B = V; break;
 17241         case 4 : R = n; G = m; B = V; break;
 17242         case 5 : R = V; G = m; B = n; break;
 17245       R*=255; G*=255; B*=255;
 17246       *(p1++) = (T)(R<0?0:(R>255?255:R));
 17247       *(p2++) = (T)(G<0?0:(G>255?255:G));
 17248       *(p3++) = (T)(B<0?0:(B>255?255:B));
 17250     return *this;
 17253     CImg<Tuchar> get_HSVtoRGB() const {
 17254       return CImg<Tuchar>(*this,false).HSVtoRGB();
 17257     //! Convert color pixels from (R,G,B) to (H,S,L).
 17258     CImg<T>& RGBtoHSL() {
 17259       if (is_empty()) return *this;
 17260       if (dim!=3)
 17261         throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
 17262                                     "should be a (R,G,B) image.",
 17263                                     pixel_type(),dim);
 17264       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17265       for (unsigned long N = width*height*depth; N; --N) {
 17266         const Tfloat
 17267           R = (Tfloat)*p1,
 17268           G = (Tfloat)*p2,
 17269           B = (Tfloat)*p3,
 17270           nR = (R<0?0:(R>255?255:R))/255,
 17271           nG = (G<0?0:(G>255?255:G))/255,
 17272           nB = (B<0?0:(B>255?255:B))/255,
 17273           m = cimg::min(nR,nG,nB),
 17274           M = cimg::max(nR,nG,nB),
 17275           L = (m+M)/2;
 17276         Tfloat H = 0, S = 0;
 17277         if (M==m) H = S = 0;
 17278         else {
 17279           const Tfloat
 17280             f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 17281             i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
 17282           H = (i-f/(M-m));
 17283           if (H>=6) H-=6;
 17284           H*=60;
 17285           S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
 17287         *(p1++) = (T)H;
 17288         *(p2++) = (T)S;
 17289         *(p3++) = (T)L;
 17291       return *this;
 17294     CImg<Tfloat> get_RGBtoHSL() const {
 17295       return CImg< Tfloat>(*this,false).RGBtoHSL();
 17298     //! Convert color pixels from (H,S,L) to (R,G,B).
 17299     CImg<T>& HSLtoRGB() {
 17300       if (is_empty()) return *this;
 17301       if (dim!=3)
 17302         throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
 17303                                     "should be a (H,S,V) image",
 17304                                     pixel_type(),dim);
 17305       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17306       for (unsigned long N = width*height*depth; N; --N) {
 17307         const Tfloat
 17308           H = (Tfloat)*p1,
 17309           S = (Tfloat)*p2,
 17310           L = (Tfloat)*p3,
 17311           q = 2*L<1?L*(1+S):(L+S-L*S),
 17312           p = 2*L-q,
 17313           h = H/360,
 17314           tr = h + 1.0f/3,
 17315           tg = h,
 17316           tb = h - 1.0f/3,
 17317           ntr = tr<0?tr+1:(tr>1?tr-1:tr),
 17318           ntg = tg<0?tg+1:(tg>1?tg-1:tg),
 17319           ntb = tb<0?tb+1:(tb>1?tb-1:tb),
 17320           R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p))),
 17321           G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p))),
 17322           B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p)));
 17323         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17324         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17325         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17327       return *this;
 17330     CImg<Tuchar> get_HSLtoRGB() const {
 17331       return CImg<Tuchar>(*this,false).HSLtoRGB();
 17334     //! Convert color pixels from (R,G,B) to (H,S,I).
 17335     //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
 17336     CImg<T>& RGBtoHSI() {
 17337       if (is_empty()) return *this;
 17338       if (dim!=3)
 17339         throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
 17340                                     "should be a (R,G,B) image.",
 17341                                     pixel_type(),dim);
 17342       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17343       for (unsigned long N = width*height*depth; N; --N) {
 17344         const Tfloat
 17345           R = (Tfloat)*p1,
 17346           G = (Tfloat)*p2,
 17347           B = (Tfloat)*p3,
 17348           nR = (R<0?0:(R>255?255:R))/255,
 17349           nG = (G<0?0:(G>255?255:G))/255,
 17350           nB = (B<0?0:(B>255?255:B))/255,
 17351           m = cimg::min(nR,nG,nB),
 17352           theta = (Tfloat)(cimg_std::acos(0.5f*((nR-nG)+(nR-nB))/cimg_std::sqrt(cimg_std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::valuePI),
 17353           sum = nR + nG + nB;
 17354         Tfloat H = 0, S = 0, I = 0;
 17355         if (theta>0) H = (nB<=nG)?theta:360-theta;
 17356         if (sum>0) S = 1 - 3/sum*m;
 17357         I = sum/3;
 17358         *(p1++) = (T)H;
 17359         *(p2++) = (T)S;
 17360         *(p3++) = (T)I;
 17362       return *this;
 17365     CImg<Tfloat> get_RGBtoHSI() const {
 17366       return CImg<Tfloat>(*this,false).RGBtoHSI();
 17369     //! Convert color pixels from (H,S,I) to (R,G,B).
 17370     CImg<T>& HSItoRGB() {
 17371       if (is_empty()) return *this;
 17372       if (dim!=3)
 17373         throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
 17374                                     "should be a (H,S,I) image",
 17375                                     pixel_type(),dim);
 17376       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17377       for (unsigned long N = width*height*depth; N; --N) {
 17378         Tfloat
 17379           H = (Tfloat)*p1,
 17380           S = (Tfloat)*p2,
 17381           I = (Tfloat)*p3,
 17382           a = I*(1-S),
 17383           R = 0, G = 0, B = 0;
 17384         if (H<120) {
 17385           B = a;
 17386           R = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 17387           G = 3*I-(R+B);
 17388         } else if (H<240) {
 17389           H-=120;
 17390           R = a;
 17391           G = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 17392           B = 3*I-(R+G);
 17393         } else {
 17394           H-=240;
 17395           G = a;
 17396           B = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 17397           R = 3*I-(G+B);
 17399         R*=255; G*=255; B*=255;
 17400         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17401         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17402         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17404       return *this;
 17407     CImg<Tfloat> get_HSItoRGB() const {
 17408       return CImg< Tuchar>(*this,false).HSItoRGB();
 17411     //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 17412     CImg<T>& RGBtoYCbCr() {
 17413       if (is_empty()) return *this;
 17414       if (dim!=3)
 17415         throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
 17416                                     "should be a (R,G,B) image (dim=3)",
 17417                                     pixel_type(),dim);
 17418       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17419       for (unsigned long N = width*height*depth; N; --N) {
 17420         const Tfloat
 17421           R = (Tfloat)*p1,
 17422           G = (Tfloat)*p2,
 17423           B = (Tfloat)*p3,
 17424           Y = (66*R + 129*G + 25*B + 128)/256 + 16,
 17425           Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
 17426           Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
 17427         *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
 17428         *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
 17429         *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
 17431       return *this;
 17434     CImg<Tuchar> get_RGBtoYCbCr() const {
 17435       return CImg<Tuchar>(*this,false).RGBtoYCbCr();
 17438     //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 17439     CImg<T>& YCbCrtoRGB() {
 17440       if (is_empty()) return *this;
 17441       if (dim!=3)
 17442         throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
 17443                                     "should be a (Y,Cb,Cr)_8 image (dim=3)",
 17444                                     pixel_type(),dim);
 17445       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17446       for (unsigned long N = width*height*depth; N; --N) {
 17447         const Tfloat
 17448           Y = (Tfloat)*p1 - 16,
 17449           Cb = (Tfloat)*p2 - 128,
 17450           Cr = (Tfloat)*p3 - 128,
 17451           R = (298*Y + 409*Cr + 128)/256,
 17452           G = (298*Y - 100*Cb - 208*Cr + 128)/256,
 17453           B = (298*Y + 516*Cb + 128)/256;
 17454         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17455         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17456         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17458       return *this;
 17461     CImg<Tuchar> get_YCbCrtoRGB() const {
 17462       return CImg<Tuchar>(*this,false).YCbCrtoRGB();
 17465     //! Convert color pixels from (R,G,B) to (Y,U,V).
 17466     CImg<T>& RGBtoYUV() {
 17467       if (is_empty()) return *this;
 17468       if (dim!=3)
 17469         throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
 17470                                     "should be a (R,G,B) image (dim=3)",
 17471                                     pixel_type(),dim);
 17472       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17473       for (unsigned long N = width*height*depth; N; --N) {
 17474         const Tfloat
 17475           R = (Tfloat)*p1/255,
 17476           G = (Tfloat)*p2/255,
 17477           B = (Tfloat)*p3/255,
 17478           Y = 0.299f*R + 0.587f*G + 0.114f*B;
 17479         *(p1++) = (T)Y;
 17480         *(p2++) = (T)(0.492f*(B-Y));
 17481         *(p3++) = (T)(0.877*(R-Y));
 17483       return *this;
 17486     CImg<Tfloat> get_RGBtoYUV() const {
 17487       return CImg<Tfloat>(*this,false).RGBtoYUV();
 17490     //! Convert color pixels from (Y,U,V) to (R,G,B).
 17491     CImg<T>& YUVtoRGB() {
 17492       if (is_empty()) return *this;
 17493       if (dim!=3)
 17494         throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
 17495                                     "should be a (Y,U,V) image (dim=3)",
 17496                                     pixel_type(),dim);
 17497       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17498       for (unsigned long N = width*height*depth; N; --N) {
 17499         const Tfloat
 17500           Y = (Tfloat)*p1,
 17501           U = (Tfloat)*p2,
 17502           V = (Tfloat)*p3,
 17503           R = (Y + 1.140f*V)*255,
 17504           G = (Y - 0.395f*U - 0.581f*V)*255,
 17505           B = (Y + 2.032f*U)*255;
 17506         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17507         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17508         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17510       return *this;
 17513     CImg<Tuchar> get_YUVtoRGB() const {
 17514       return CImg< Tuchar>(*this,false).YUVtoRGB();
 17517     //! Convert color pixels from (R,G,B) to (C,M,Y).
 17518     CImg<T>& RGBtoCMY() {
 17519       if (is_empty()) return *this;
 17520       if (dim!=3)
 17521         throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
 17522                                     "should be a (R,G,B) image (dim=3)",
 17523                                     pixel_type(),dim);
 17524       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17525       for (unsigned long N = width*height*depth; N; --N) {
 17526         const Tfloat
 17527           R = (Tfloat)*p1/255,
 17528           G = (Tfloat)*p2/255,
 17529           B = (Tfloat)*p3/255;
 17530         *(p1++) = (T)(1 - R);
 17531         *(p2++) = (T)(1 - G);
 17532         *(p3++) = (T)(1 - B);
 17534       return *this;
 17537     CImg<Tfloat> get_RGBtoCMY() const {
 17538       return CImg<Tfloat>(*this,false).RGBtoCMY();
 17541     //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
 17542     CImg<T>& CMYtoRGB() {
 17543       if (is_empty()) return *this;
 17544       if (dim!=3)
 17545         throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
 17546                                     "should be a (C,M,Y) image (dim=3)",
 17547                                     pixel_type(),dim);
 17548       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17549       for (unsigned long N = width*height*depth; N; --N) {
 17550         const Tfloat
 17551           C = (Tfloat)*p1,
 17552           M = (Tfloat)*p2,
 17553           Y = (Tfloat)*p3,
 17554           R = 255*(1 - C),
 17555           G = 255*(1 - M),
 17556           B = 255*(1 - Y);
 17557         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17558         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17559         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17561       return *this;
 17564     CImg<Tuchar> get_CMYtoRGB() const {
 17565       return CImg<Tuchar>(*this,false).CMYtoRGB();
 17568     //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
 17569     CImg<T>& CMYtoCMYK() {
 17570       return get_CMYtoCMYK().transfer_to(*this);
 17573     CImg<Tfloat> get_CMYtoCMYK() const {
 17574       if (is_empty()) return *this;
 17575       if (dim!=3)
 17576         throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
 17577                                     "should be a (C,M,Y) image (dim=3)",
 17578                                     pixel_type(),dim);
 17579       CImg<Tfloat> res(width,height,depth,4);
 17580       const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
 17581       Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2), *pd4 = res.ptr(0,0,0,3);
 17582       for (unsigned long N = width*height*depth; N; --N) {
 17583         Tfloat
 17584           C = (Tfloat)*(ps1++),
 17585           M = (Tfloat)*(ps2++),
 17586           Y = (Tfloat)*(ps3++),
 17587           K = cimg::min(C,M,Y);
 17588         if (K==1) C = M = Y = 0;
 17589         else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
 17590         *(pd1++) = C;
 17591         *(pd2++) = M;
 17592         *(pd3++) = Y;
 17593         *(pd4++) = K;
 17595       return res;
 17598     //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
 17599     CImg<T>& CMYKtoCMY() {
 17600       return get_CMYKtoCMY().transfer_to(*this);
 17603     CImg<Tfloat> get_CMYKtoCMY() const {
 17604       if (is_empty()) return *this;
 17605       if (dim!=4)
 17606         throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
 17607                                     "should be a (C,M,Y,K) image (dim=4)",
 17608                                     pixel_type(),dim);
 17609       CImg<Tfloat> res(width,height,depth,3);
 17610       const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2), *ps4 = ptr(0,0,0,3);
 17611       Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
 17612       for (unsigned long N = width*height*depth; N; --N) {
 17613         const Tfloat
 17614           C = (Tfloat)*ps1,
 17615           M = (Tfloat)*ps2,
 17616           Y = (Tfloat)*ps3,
 17617           K = (Tfloat)*ps4,
 17618           K1 = 1 - K;
 17619         *(pd1++) = C*K1 + K;
 17620         *(pd2++) = M*K1 + K;
 17621         *(pd3++) = Y*K1 + K;
 17623       return res;
 17626     //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
 17627     CImg<T>& RGBtoXYZ() {
 17628       if (is_empty()) return *this;
 17629       if (dim!=3)
 17630         throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
 17631                                     "should be a (R,G,B) image (dim=3)",
 17632                                     pixel_type(),dim);
 17633       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17634       for (unsigned long N = width*height*depth; N; --N) {
 17635         const Tfloat
 17636           R = (Tfloat)*p1/255,
 17637           G = (Tfloat)*p2/255,
 17638           B = (Tfloat)*p3/255;
 17639         *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
 17640         *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
 17641         *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
 17643       return *this;
 17646     CImg<Tfloat> get_RGBtoXYZ() const {
 17647       return CImg<Tfloat>(*this,false).RGBtoXYZ();
 17650     //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
 17651     CImg<T>& XYZtoRGB() {
 17652       if (is_empty()) return *this;
 17653       if (dim!=3)
 17654         throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
 17655                                     "should be a (X,Y,Z) image (dim=3)",
 17656                                     pixel_type(),dim);
 17657       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17658       for (unsigned long N = width*height*depth; N; --N) {
 17659         const Tfloat
 17660           X = (Tfloat)*p1*255,
 17661           Y = (Tfloat)*p2*255,
 17662           Z = (Tfloat)*p3*255,
 17663           R = 3.240479f*X  - 1.537150f*Y - 0.498535f*Z,
 17664           G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
 17665           B = 0.055648f*X  - 0.204043f*Y + 1.057311f*Z;
 17666         *(p1++) = (T)(R<0?0:(R>255?255:R));
 17667         *(p2++) = (T)(G<0?0:(G>255?255:G));
 17668         *(p3++) = (T)(B<0?0:(B>255?255:B));
 17670       return *this;
 17673     CImg<Tuchar> get_XYZtoRGB() const {
 17674       return CImg<Tuchar>(*this,false).XYZtoRGB();
 17677     //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
 17678     CImg<T>& XYZtoLab() {
 17679 #define _cimg_Labf(x) ((x)>=0.008856f?(cimg_std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
 17680       if (is_empty()) return *this;
 17681       if (dim!=3)
 17682         throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
 17683                                     "should be a (X,Y,Z) image (dim=3)",
 17684                                     pixel_type(),dim);
 17685       const Tfloat
 17686         Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 17687         Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 17688         Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 17689       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17690       for (unsigned long N = width*height*depth; N; --N) {
 17691         const Tfloat
 17692           X = (Tfloat)*p1,
 17693           Y = (Tfloat)*p2,
 17694           Z = (Tfloat)*p3,
 17695           XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
 17696           fX = (Tfloat)_cimg_Labf(XXn),
 17697           fY = (Tfloat)_cimg_Labf(YYn),
 17698           fZ = (Tfloat)_cimg_Labf(ZZn);
 17699         *(p1++) = (T)(116*fY - 16);
 17700         *(p2++) = (T)(500*(fX - fY));
 17701         *(p3++) = (T)(200*(fY - fZ));
 17703       return *this;
 17706     CImg<Tfloat> get_XYZtoLab() const {
 17707       return CImg<Tfloat>(*this,false).XYZtoLab();
 17710     //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
 17711     CImg<T>& LabtoXYZ() {
 17712 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
 17713       if (is_empty()) return *this;
 17714       if (dim!=3)
 17715         throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
 17716                                     "should be a (X,Y,Z) image (dim=3)",
 17717                                     pixel_type(),dim);
 17718       const Tfloat
 17719         Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 17720         Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 17721         Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 17722       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17723       for (unsigned long N = width*height*depth; N; --N) {
 17724         const Tfloat
 17725           L = (Tfloat)*p1,
 17726           a = (Tfloat)*p2,
 17727           b = (Tfloat)*p3,
 17728           cY = (L + 16)/116,
 17729           Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
 17730           pY = (Tfloat)cimg_std::pow(Y/Yn,(Tfloat)1/3),
 17731           cX = a/500 + pY,
 17732           X = Xn*cX*cX*cX,
 17733           cZ = pY - b/200,
 17734           Z = Zn*cZ*cZ*cZ;
 17735         *(p1++) = (T)(X);
 17736         *(p2++) = (T)(Y);
 17737         *(p3++) = (T)(Z);
 17739       return *this;
 17742     CImg<Tfloat> get_LabtoXYZ() const {
 17743       return CImg<Tfloat>(*this,false).LabtoXYZ();
 17746     //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
 17747     CImg<T>& XYZtoxyY() {
 17748       if (is_empty()) return *this;
 17749       if (dim!=3)
 17750         throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
 17751                                     "should be a (X,Y,Z) image (dim=3)",
 17752                                     pixel_type(),dim);
 17753       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17754       for (unsigned long N = width*height*depth; N; --N) {
 17755         const Tfloat
 17756           X = (Tfloat)*p1,
 17757           Y = (Tfloat)*p2,
 17758           Z = (Tfloat)*p3,
 17759           sum = (X+Y+Z),
 17760           nsum = sum>0?sum:1;
 17761         *(p1++) = (T)(X/nsum);
 17762         *(p2++) = (T)(Y/nsum);
 17763         *(p3++) = (T)Y;
 17765       return *this;
 17768     CImg<Tfloat> get_XYZtoxyY() const {
 17769       return CImg<Tfloat>(*this,false).XYZtoxyY();
 17772     //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
 17773     CImg<T>& xyYtoXYZ() {
 17774       if (is_empty()) return *this;
 17775       if (dim!=3)
 17776         throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
 17777                                     "should be a (x,y,Y) image (dim=3)",
 17778                                     pixel_type(),dim);
 17779       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 17780       for (unsigned long N = width*height*depth; N; --N) {
 17781         const Tfloat
 17782          px = (Tfloat)*p1,
 17783          py = (Tfloat)*p2,
 17784          Y = (Tfloat)*p3,
 17785          ny = py>0?py:1;
 17786         *(p1++) = (T)(px*Y/ny);
 17787         *(p2++) = (T)Y;
 17788         *(p3++) = (T)((1-px-py)*Y/ny);
 17790       return *this;
 17793     CImg<Tfloat> get_xyYtoXYZ() const {
 17794       return CImg<Tfloat>(*this,false).xyYtoXYZ();
 17797     //! Convert a (R,G,B) image to a (L,a,b) one.
 17798     CImg<T>& RGBtoLab() {
 17799       return RGBtoXYZ().XYZtoLab();
 17802     CImg<Tfloat> get_RGBtoLab() const {
 17803       return CImg<Tfloat>(*this,false).RGBtoLab();
 17806     //! Convert a (L,a,b) image to a (R,G,B) one.
 17807     CImg<T>& LabtoRGB() {
 17808       return LabtoXYZ().XYZtoRGB();
 17811     CImg<Tuchar> get_LabtoRGB() const {
 17812       return CImg<Tuchar>(*this,false).LabtoRGB();
 17815     //! Convert a (R,G,B) image to a (x,y,Y) one.
 17816     CImg<T>& RGBtoxyY() {
 17817       return RGBtoXYZ().XYZtoxyY();
 17820     CImg<Tfloat> get_RGBtoxyY() const {
 17821       return CImg<Tfloat>(*this,false).RGBtoxyY();
 17824     //! Convert a (x,y,Y) image to a (R,G,B) one.
 17825     CImg<T>& xyYtoRGB() {
 17826       return xyYtoXYZ().XYZtoRGB();
 17829     CImg<Tuchar> get_xyYtoRGB() const {
 17830       return CImg<Tuchar>(*this,false).xyYtoRGB();
 17833     //! Convert a (R,G,B) image to a (C,M,Y,K) one.
 17834     CImg<T>& RGBtoCMYK() {
 17835       return RGBtoCMY().CMYtoCMYK();
 17838     CImg<Tfloat> get_RGBtoCMYK() const {
 17839       return CImg<Tfloat>(*this,false).RGBtoCMYK();
 17842     //! Convert a (C,M,Y,K) image to a (R,G,B) one.
 17843     CImg<T>& CMYKtoRGB() {
 17844       return CMYKtoCMY().CMYtoRGB();
 17847     CImg<Tuchar> get_CMYKtoRGB() const {
 17848       return CImg<Tuchar>(*this,false).CMYKtoRGB();
 17851     //! Convert a (R,G,B) image to a Bayer-coded representation.
 17852     /**
 17853        \note First (upper-left) pixel if the red component of the pixel color.
 17854     **/
 17855     CImg<T>& RGBtoBayer() {
 17856       return get_RGBtoBayer().transfer_to(*this);
 17859     CImg<T> get_RGBtoBayer() const {
 17860       if (is_empty()) return *this;
 17861       if (dim!=3)
 17862         throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
 17863                                     "should be a (R,G,B) image (dim=3)",
 17864                                     pixel_type(),dim);
 17865       CImg<T> res(width,height,depth,1);
 17866       const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
 17867       T *ptrd = res.data;
 17868       cimg_forXYZ(*this,x,y,z) {
 17869         if (y%2) {
 17870           if (x%2) *(ptrd++) = *pB;
 17871           else *(ptrd++) = *pG;
 17872         } else {
 17873           if (x%2) *(ptrd++) = *pG;
 17874           else *(ptrd++) = *pR;
 17876         ++pR; ++pG; ++pB;
 17878       return res;
 17881     //! Convert a Bayer-coded image to a (R,G,B) color image.
 17882     CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
 17883       return get_BayertoRGB(interpolation_type).transfer_to(*this);
 17886     CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
 17887       if (is_empty()) return *this;
 17888       if (dim!=1)
 17889         throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
 17890                                     "should be a Bayer image (dim=1)",
 17891                                     pixel_type(),dim);
 17892       CImg<Tuchar> res(width,height,depth,3);
 17893       CImg_3x3(I,T);
 17894       Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
 17895       switch (interpolation_type) {
 17896       case 3 : { // Edge-directed
 17897         CImg_3x3(R,T);
 17898         CImg_3x3(G,T);
 17899         CImg_3x3(B,T);
 17900         cimg_forXYZ(*this,x,y,z) {
 17901           const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
 17902           cimg_get3x3(*this,x,y,z,0,I);
 17903           if (y%2) {
 17904             if (x%2) {
 17905               const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 17906               *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 17907             } else *pG = (Tuchar)Icc;
 17908           } else {
 17909             if (x%2) *pG = (Tuchar)Icc;
 17910             else {
 17911               const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 17912               *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 17915           ++pG;
 17917         cimg_forXYZ(*this,x,y,z) {
 17918           const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
 17919           cimg_get3x3(*this,x,y,z,0,I);
 17920           cimg_get3x3(res,x,y,z,1,G);
 17921           if (y%2) {
 17922             if (x%2) *pB = (Tuchar)Icc;
 17923             else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
 17924           } else {
 17925             if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
 17926             else *pR = (Tuchar)Icc;
 17928           ++pR; ++pB;
 17930         pR = res.ptr(0,0,0,0);
 17931         pG = res.ptr(0,0,0,1);
 17932         pB = res.ptr(0,0,0,2);
 17933         cimg_forXYZ(*this,x,y,z) {
 17934           const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
 17935           cimg_get3x3(res,x,y,z,0,R);
 17936           cimg_get3x3(res,x,y,z,1,G);
 17937           cimg_get3x3(res,x,y,z,2,B);
 17938           if (y%2) {
 17939             if (x%2) {
 17940               const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 17941               *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
 17943           } else {
 17944             if (!(x%2)) {
 17945               const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 17946               *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
 17949           ++pR; ++pG; ++pB;
 17951       } break;
 17952       case 2 : { // Linear interpolation
 17953         cimg_forXYZ(*this,x,y,z) {
 17954           const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
 17955           cimg_get3x3(*this,x,y,z,0,I);
 17956           if (y%2) {
 17957             if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
 17958             else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
 17959           } else {
 17960             if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
 17961             else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
 17963           ++pR; ++pG; ++pB;
 17965       } break;
 17966       case 1 : { // Nearest neighbor interpolation
 17967         cimg_forXYZ(*this,x,y,z) {
 17968           const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
 17969           cimg_get3x3(*this,x,y,z,0,I);
 17970           if (y%2) {
 17971             if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
 17972             else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
 17973           } else {
 17974             if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
 17975             else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
 17977           ++pR; ++pG; ++pB;
 17979       } break;
 17980       default : { // 0-filling interpolation
 17981         const T *ptrs = data;
 17982         res.fill(0);
 17983         cimg_forXYZ(*this,x,y,z) {
 17984           const T val = *(ptrs++);
 17985           if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
 17986           ++pR; ++pG; ++pB;
 17990       return res;
 17993     //@}
 17994     //-------------------
 17995     //
 17996     //! \name Drawing
 17997     //@{
 17998     //-------------------
 18000     // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
 18001     // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
 18002     template<typename tc>
 18003     CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
 18004                             const tc *const color, const float opacity=1,
 18005                             const float brightness=1, const bool init=false) {
 18006       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 18007       static float nopacity = 0, copacity = 0;
 18008       static unsigned int whz = 0;
 18009       static const tc *col = 0;
 18010       if (init) {
 18011         nopacity = cimg::abs(opacity);
 18012         copacity = 1 - cimg::max(opacity,0);
 18013         whz = width*height*depth;
 18014       } else {
 18015         const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
 18016         if (dx>=0) {
 18017           col = color;
 18018           const unsigned int off = whz-dx-1;
 18019           T *ptrd = ptr(nx0,y);
 18020           if (opacity>=1) { // ** Opaque drawing **
 18021             if (brightness==1) { // Brightness==1
 18022               if (sizeof(T)!=1) cimg_forV(*this,k) {
 18023                 const T val = (T)*(col++);
 18024                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
 18025                 ptrd+=off;
 18026               } else cimg_forV(*this,k) {
 18027                 const T val = (T)*(col++);
 18028                 cimg_std::memset(ptrd,(int)val,dx+1);
 18029                 ptrd+=whz;
 18031             } else if (brightness<1) { // Brightness<1
 18032               if (sizeof(T)!=1) cimg_forV(*this,k) {
 18033                 const T val = (T)(*(col++)*brightness);
 18034                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
 18035                 ptrd+=off;
 18036               } else cimg_forV(*this,k) {
 18037                 const T val = (T)(*(col++)*brightness);
 18038                 cimg_std::memset(ptrd,(int)val,dx+1);
 18039                 ptrd+=whz;
 18041             } else { // Brightness>1
 18042               if (sizeof(T)!=1) cimg_forV(*this,k) {
 18043                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 18044                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
 18045                 ptrd+=off;
 18046               } else cimg_forV(*this,k) {
 18047                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 18048                 cimg_std::memset(ptrd,(int)val,dx+1);
 18049                 ptrd+=whz;
 18052           } else { // ** Transparent drawing **
 18053             if (brightness==1) { // Brightness==1
 18054               cimg_forV(*this,k) {
 18055                 const T val = (T)*(col++);
 18056                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 18057                 ptrd+=off;
 18059             } else if (brightness<=1) { // Brightness<1
 18060               cimg_forV(*this,k) {
 18061                 const T val = (T)(*(col++)*brightness);
 18062                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 18063                 ptrd+=off;
 18065             } else { // Brightness>1
 18066               cimg_forV(*this,k) {
 18067                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 18068                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 18069                 ptrd+=off;
 18075       return *this;
 18078     template<typename tc>
 18079     CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
 18080       return _draw_scanline(0,0,0,color,opacity,0,true);
 18083     //! Draw a 2D colored point (pixel).
 18084     /**
 18085        \param x0 X-coordinate of the point.
 18086        \param y0 Y-coordinate of the point.
 18087        \param color Pointer to \c dimv() consecutive values, defining the color values.
 18088        \param opacity Drawing opacity (optional).
 18089        \note
 18090        - Clipping is supported.
 18091        - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.
 18092        \par Example:
 18093        \code
 18094        CImg<unsigned char> img(100,100,1,3,0);
 18095        const unsigned char color[] = { 255,128,64 };
 18096        img.draw_point(50,50,color);
 18097        \endcode
 18098     **/
 18099     template<typename tc>
 18100     CImg<T>& draw_point(const int x0, const int y0,
 18101                         const tc *const color, const float opacity=1) {
 18102       return draw_point(x0,y0,0,color,opacity);
 18105     //! Draw a 2D colored point (pixel).
 18106     template<typename tc>
 18107     CImg<T>& draw_point(const int x0, const int y0,
 18108                         const CImg<tc>& color, const float opacity=1) {
 18109       return draw_point(x0,y0,color.data,opacity);
 18112     //! Draw a 3D colored point (voxel).
 18113     template<typename tc>
 18114     CImg<T>& draw_point(const int x0, const int y0, const int z0,
 18115                         const tc *const color, const float opacity=1) {
 18116       if (is_empty()) return *this;
 18117       if (!color)
 18118         throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
 18119                                     pixel_type());
 18120       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
 18121         const unsigned int whz = width*height*depth;
 18122         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18123         T *ptrd = ptr(x0,y0,z0,0);
 18124         const tc *col = color;
 18125         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 18126         else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
 18128       return *this;
 18131     //! Draw a 3D colored point (voxel).
 18132     template<typename tc>
 18133     CImg<T>& draw_point(const int x0, const int y0, const int z0,
 18134                         const CImg<tc>& color, const float opacity=1) {
 18135       return draw_point(x0,y0,z0,color.data,opacity);
 18138     // Draw a cloud of colored point (internal).
 18139     template<typename t, typename tc>
 18140     CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
 18141                          const tc *const color, const float opacity) {
 18142       if (is_empty() || !points || !W) return *this;
 18143       switch (H) {
 18144       case 0 : case 1 :
 18145         throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
 18146                                     pixel_type());
 18147       case 2 : {
 18148         for (unsigned int i = 0; i<W; ++i) {
 18149           const int x = (int)points(i,0), y = (int)points(i,1);
 18150           draw_point(x,y,color,opacity);
 18152       } break;
 18153       default : {
 18154         for (unsigned int i = 0; i<W; ++i) {
 18155           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 18156           draw_point(x,y,z,color,opacity);
 18160       return *this;
 18163     //! Draw a cloud of colored points.
 18164     /**
 18165        \param points Coordinates of vertices, stored as a list of vectors.
 18166        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 18167        \param opacity Drawing opacity (optional).
 18168        \note
 18169        - This function uses several call to the single CImg::draw_point() procedure,
 18170        depending on the vectors size in \p points.
 18171        \par Example:
 18172        \code
 18173        CImg<unsigned char> img(100,100,1,3,0);
 18174        const unsigned char color[] = { 255,128,64 };
 18175        CImgList<int> points;
 18176        points.insert(CImg<int>::vector(0,0)).
 18177              .insert(CImg<int>::vector(70,10)).
 18178              .insert(CImg<int>::vector(80,60)).
 18179              .insert(CImg<int>::vector(10,90));
 18180        img.draw_point(points,color);
 18181        \endcode
 18182     **/
 18183     template<typename t, typename tc>
 18184     CImg<T>& draw_point(const CImgList<t>& points,
 18185                         const tc *const color, const float opacity=1) {
 18186       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 18187       return _draw_point(points,points.size,H,color,opacity);
 18190     //! Draw a cloud of colored points.
 18191     template<typename t, typename tc>
 18192     CImg<T>& draw_point(const CImgList<t>& points,
 18193                         const CImg<tc>& color, const float opacity=1) {
 18194       return draw_point(points,color.data,opacity);
 18197     //! Draw a cloud of colored points.
 18198     /**
 18199        \note
 18200        - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
 18201        (sequence of vectors aligned along the x-axis).
 18202     **/
 18203     template<typename t, typename tc>
 18204     CImg<T>& draw_point(const CImg<t>& points,
 18205                         const tc *const color, const float opacity=1) {
 18206       return _draw_point(points,points.width,points.height,color,opacity);
 18209     //! Draw a cloud of colored points.
 18210     template<typename t, typename tc>
 18211     CImg<T>& draw_point(const CImg<t>& points,
 18212                         const CImg<tc>& color, const float opacity=1) {
 18213       return draw_point(points,color.data,opacity);
 18216     //! Draw a 2D colored line.
 18217     /**
 18218        \param x0 X-coordinate of the starting line point.
 18219        \param y0 Y-coordinate of the starting line point.
 18220        \param x1 X-coordinate of the ending line point.
 18221        \param y1 Y-coordinate of the ending line point.
 18222        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 18223        \param opacity Drawing opacity (optional).
 18224        \param pattern An integer whose bits describe the line pattern (optional).
 18225        \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional).
 18226        \note
 18227        - Clipping is supported.
 18228        - Line routine uses Bresenham's algorithm.
 18229        - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.
 18230        \par Example:
 18231        \code
 18232        CImg<unsigned char> img(100,100,1,3,0);
 18233        const unsigned char color[] = { 255,128,64 };
 18234         img.draw_line(40,40,80,70,color);
 18235        \endcode
 18236     **/
 18237     template<typename tc>
 18238     CImg<T>& draw_line(const int x0, const int y0,
 18239                        const int x1, const int y1,
 18240                        const tc *const color, const float opacity=1,
 18241                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18242       if (is_empty()) return *this;
 18243       if (!color)
 18244         throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
 18245                                     pixel_type());
 18246       static unsigned int hatch = ~0U - (~0U>>1);
 18247       if (init_hatch) hatch = ~0U - (~0U>>1);
 18248       const bool xdir = x0<x1, ydir = y0<y1;
 18249       int
 18250         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 18251         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 18252         &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 18253         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 18254         &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 18255       if (xright<0 || xleft>=dimx()) return *this;
 18256       if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
 18257       if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
 18258       if (ydown<0 || yup>=dimy()) return *this;
 18259       if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
 18260       if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
 18261       T *ptrd0 = ptr(nx0,ny0);
 18262       int dx = xright - xleft, dy = ydown - yup;
 18263       const bool steep = dy>dx;
 18264       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 18265       const int
 18266         offx = (nx0<nx1?1:-1)*(steep?width:1),
 18267         offy = (ny0<ny1?1:-1)*(steep?1:width),
 18268         wh = width*height;
 18269       if (opacity>=1) {
 18270         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18271           if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
 18272           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18273           ptrd0+=offx;
 18274           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18275         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18276           T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 18277           ptrd0+=offx;
 18278           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18280       } else {
 18281         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18282         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18283           if (pattern&hatch) {
 18284             T *ptrd = ptrd0; const tc* col = color;
 18285             cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 18287           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18288           ptrd0+=offx;
 18289           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18290         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18291           T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 18292           ptrd0+=offx;
 18293           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18296       return *this;
 18299     //! Draw a 2D colored line.
 18300     template<typename tc>
 18301     CImg<T>& draw_line(const int x0, const int y0,
 18302                        const int x1, const int y1,
 18303                        const CImg<tc>& color, const float opacity=1,
 18304                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18305       return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
 18308     //! Draw a 2D colored line, with z-buffering.
 18309     template<typename tc>
 18310     CImg<T>& draw_line(float *const zbuffer,
 18311                        const int x0, const int y0, const float z0,
 18312                        const int x1, const int y1, const float z1,
 18313                        const tc *const color, const float opacity=1,
 18314                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18315       if (!is_empty() && z0>0 && z1>0) {
 18316         if (!color)
 18317           throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
 18318                                       pixel_type());
 18319         static unsigned int hatch = ~0U - (~0U>>1);
 18320         if (init_hatch) hatch = ~0U - (~0U>>1);
 18321         const bool xdir = x0<x1, ydir = y0<y1;
 18322         int
 18323           nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 18324           &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 18325           &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 18326           &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 18327           &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 18328         float
 18329           Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
 18330           &zleft = xdir?nz0:nz1,
 18331           &zright = xdir?nz1:nz0,
 18332           &zup = ydir?nz0:nz1,
 18333           &zdown = ydir?nz1:nz0;
 18334         if (xright<0 || xleft>=dimx()) return *this;
 18335         if (xleft<0) {
 18336           const int D = xright - xleft;
 18337           yleft-=xleft*(yright - yleft)/D;
 18338           zleft-=xleft*(zright - zleft)/D;
 18339           xleft = 0;
 18341         if (xright>=dimx()) {
 18342           const int d = xright - dimx(), D = xright - xleft;
 18343           yright-=d*(yright - yleft)/D;
 18344           zright-=d*(zright - zleft)/D;
 18345           xright = dimx()-1;
 18347         if (ydown<0 || yup>=dimy()) return *this;
 18348         if (yup<0) {
 18349           const int D = ydown - yup;
 18350           xup-=yup*(xdown - xup)/D;
 18351           zup-=yup*(zdown - zup)/D;
 18352           yup = 0;
 18354         if (ydown>=dimy()) {
 18355           const int d = ydown - dimy(), D = ydown - yup;
 18356           xdown-=d*(xdown - xup)/D;
 18357           zdown-=d*(zdown - zup)/D;
 18358           ydown = dimy()-1;
 18360         T *ptrd0 = ptr(nx0,ny0);
 18361         float *ptrz = zbuffer + nx0 + ny0*width;
 18362         int dx = xright - xleft, dy = ydown - yup;
 18363         const bool steep = dy>dx;
 18364         if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 18365         const int
 18366           offx = (nx0<nx1?1:-1)*(steep?width:1),
 18367           offy = (ny0<ny1?1:-1)*(steep?1:width),
 18368           wh = width*height,
 18369           ndx = dx>0?dx:1;
 18370         if (opacity>=1) {
 18371           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18372             const float z = Z0 + x*dz/ndx;
 18373             if (z>*ptrz && pattern&hatch) {
 18374               *ptrz = z;
 18375               T *ptrd = ptrd0; const tc *col = color;
 18376               cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 18378             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18379             ptrd0+=offx; ptrz+=offx;
 18380             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18381           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18382             const float z = Z0 + x*dz/ndx;
 18383             if (z>*ptrz) {
 18384               *ptrz = z;
 18385               T *ptrd = ptrd0; const tc *col = color;
 18386               cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 18388             ptrd0+=offx; ptrz+=offx;
 18389             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18391         } else {
 18392           const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18393           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18394             const float z = Z0 + x*dz/ndx;
 18395             if (z>*ptrz && pattern&hatch) {
 18396               *ptrz = z;
 18397               T *ptrd = ptrd0; const tc *col = color;
 18398               cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 18400             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18401             ptrd0+=offx; ptrz+=offx;
 18402             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18403           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18404             const float z = Z0 + x*dz/ndx;
 18405             if (z>*ptrz) {
 18406               *ptrz = z;
 18407               T *ptrd = ptrd0; const tc *col = color;
 18408               cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 18410             ptrd0+=offx; ptrz+=offx;
 18411             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18415       return *this;
 18418     //! Draw a 2D colored line, with z-buffering.
 18419     template<typename tc>
 18420     CImg<T>& draw_line(float *const zbuffer,
 18421                        const int x0, const int y0, const float z0,
 18422                        const int x1, const int y1, const float z1,
 18423                        const CImg<tc>& color, const float opacity=1,
 18424                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18425       return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
 18428     //! Draw a 3D colored line.
 18429     template<typename tc>
 18430     CImg<T>& draw_line(const int x0, const int y0, const int z0,
 18431                        const int x1, const int y1, const int z1,
 18432                        const tc *const color, const float opacity=1,
 18433                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18434       if (is_empty()) return *this;
 18435       if (!color)
 18436         throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
 18437                                     pixel_type());
 18438       static unsigned int hatch = ~0U - (~0U>>1);
 18439       if (init_hatch) hatch = ~0U - (~0U>>1);
 18440       int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
 18441       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 18442       if (nx1<0 || nx0>=dimx()) return *this;
 18443       if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
 18444       if (nx1>=dimx()) { const int d = nx1-dimx(), D = 1 + nx1 - nx0; ny1+=d*(1 + ny0 - ny1)/D; nz1+=d*(1 + nz0 - nz1)/D; nx1 = dimx()-1; }
 18445       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 18446       if (ny1<0 || ny0>=dimy()) return *this;
 18447       if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
 18448       if (ny1>=dimy()) { const int d = ny1-dimy(), D = 1 + ny1 - ny0; nx1+=d*(1 + nx0 - nx1)/D; nz1+=d*(1 + nz0 - nz1)/D; ny1 = dimy()-1; }
 18449       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 18450       if (nz1<0 || nz0>=dimz()) return *this;
 18451       if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
 18452       if (nz1>=dimz()) { const int d = nz1-dimz(), D = 1 + nz1 - nz0; nx1+=d*(1 + nx0 - nx1)/D; ny1+=d*(1 + ny0 - ny1)/D; nz1 = dimz()-1; }
 18453       const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
 18454       const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
 18455       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
 18456       if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
 18457         if (!(~pattern) || (~pattern && pattern&hatch)) {
 18458           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
 18459           const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 18461         x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
 18462       } else {
 18463         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18464         for (unsigned int t = 0; t<=dmax; ++t) {
 18465           if (!(~pattern) || (~pattern && pattern&hatch)) {
 18466             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
 18467             const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
 18469           x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
 18472       return *this;
 18475     //! Draw a 3D colored line.
 18476     template<typename tc>
 18477     CImg<T>& draw_line(const int x0, const int y0, const int z0,
 18478                        const int x1, const int y1, const int z1,
 18479                        const CImg<tc>& color, const float opacity=1,
 18480                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18481       return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
 18484     //! Draw a 2D textured line.
 18485     /**
 18486        \param x0 X-coordinate of the starting line point.
 18487        \param y0 Y-coordinate of the starting line point.
 18488        \param x1 X-coordinate of the ending line point.
 18489        \param y1 Y-coordinate of the ending line point.
 18490        \param texture Texture image defining the pixel colors.
 18491        \param tx0 X-coordinate of the starting texture point.
 18492        \param ty0 Y-coordinate of the starting texture point.
 18493        \param tx1 X-coordinate of the ending texture point.
 18494        \param ty1 Y-coordinate of the ending texture point.
 18495        \param opacity Drawing opacity (optional).
 18496        \param pattern An integer whose bits describe the line pattern (optional).
 18497        \param init_hatch Flag telling if the hash variable must be reinitialized (optional).
 18498        \note
 18499        - Clipping is supported but not for texture coordinates.
 18500        - Line routine uses the well known Bresenham's algorithm.
 18501        \par Example:
 18502        \code
 18503        CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm");
 18504        const unsigned char color[] = { 255,128,64 };
 18505        img.draw_line(40,40,80,70,texture,0,0,255,255);
 18506        \endcode
 18507     **/
 18508     template<typename tc>
 18509     CImg<T>& draw_line(const int x0, const int y0,
 18510                        const int x1, const int y1,
 18511                        const CImg<tc>& texture,
 18512                        const int tx0, const int ty0,
 18513                        const int tx1, const int ty1,
 18514                        const float opacity=1,
 18515                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18516       if (is_empty()) return *this;
 18517       if (!texture || texture.dim<dim)
 18518         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 18519                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 18520       if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 18521       static unsigned int hatch = ~0U - (~0U>>1);
 18522       if (init_hatch) hatch = ~0U - (~0U>>1);
 18523       const bool xdir = x0<x1, ydir = y0<y1;
 18524       int
 18525         dtx = tx1-tx0, dty = ty1-ty0,
 18526         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 18527         tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
 18528         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 18529         &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 18530         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
 18531         &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 18532       if (xright<0 || xleft>=dimx()) return *this;
 18533       if (xleft<0) {
 18534         const int D = xright - xleft;
 18535         yleft-=xleft*(yright - yleft)/D;
 18536         txleft-=xleft*(txright - txleft)/D;
 18537         tyleft-=xleft*(tyright - tyleft)/D;
 18538         xleft = 0;
 18540       if (xright>=dimx()) {
 18541         const int d = xright - dimx(), D = xright - xleft;
 18542         yright-=d*(yright - yleft)/D;
 18543         txright-=d*(txright - txleft)/D;
 18544         tyright-=d*(tyright - tyleft)/D;
 18545         xright = dimx()-1;
 18547       if (ydown<0 || yup>=dimy()) return *this;
 18548       if (yup<0) {
 18549         const int D = ydown - yup;
 18550         xup-=yup*(xdown - xup)/D;
 18551         txup-=yup*(txdown - txup)/D;
 18552         tyup-=yup*(tydown - tyup)/D;
 18553         yup = 0;
 18555       if (ydown>=dimy()) {
 18556         const int d = ydown - dimy(), D = ydown - yup;
 18557         xdown-=d*(xdown - xup)/D;
 18558         txdown-=d*(txdown - txup)/D;
 18559         tydown-=d*(tydown - tyup)/D;
 18560         ydown = dimy()-1;
 18562       T *ptrd0 = ptr(nx0,ny0);
 18563       int dx = xright - xleft, dy = ydown - yup;
 18564       const bool steep = dy>dx;
 18565       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 18566       const int
 18567         offx = (nx0<nx1?1:-1)*(steep?width:1),
 18568         offy = (ny0<ny1?1:-1)*(steep?1:width),
 18569         wh = width*height,
 18570         ndx = dx>0?dx:1;
 18571       if (opacity>=1) {
 18572         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18573           if (pattern&hatch) {
 18574             T *ptrd = ptrd0;
 18575             const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 18576             cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
 18578           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18579           ptrd0+=offx;
 18580           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18581         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18582           T *ptrd = ptrd0;
 18583           const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 18584           cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
 18585           ptrd0+=offx;
 18586           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18588       } else {
 18589         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18590         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18591           T *ptrd = ptrd0;
 18592           if (pattern&hatch) {
 18593             const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 18594             cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
 18596           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18597           ptrd0+=offx;
 18598           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18599         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18600           T *ptrd = ptrd0;
 18601           const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 18602           cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
 18603           ptrd0+=offx;
 18604           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18607       return *this;
 18610     //! Draw a 2D textured line, with perspective correction.
 18611     template<typename tc>
 18612     CImg<T>& draw_line(const int x0, const int y0, const float z0,
 18613                        const int x1, const int y1, const float z1,
 18614                        const CImg<tc>& texture,
 18615                        const int tx0, const int ty0,
 18616                        const int tx1, const int ty1,
 18617                        const float opacity=1,
 18618                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18619       if (is_empty() && z0<=0 && z1<=0) return *this;
 18620       if (!texture || texture.dim<dim)
 18621         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 18622                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 18623       if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 18624       static unsigned int hatch = ~0U - (~0U>>1);
 18625       if (init_hatch) hatch = ~0U - (~0U>>1);
 18626       const bool xdir = x0<x1, ydir = y0<y1;
 18627       int
 18628         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 18629         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 18630         &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 18631         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 18632         &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 18633       float
 18634         Tx0 = tx0/z0, Tx1 = tx1/z1,
 18635         Ty0 = ty0/z0, Ty1 = ty1/z1,
 18636         Z0 = 1/z0, Z1 = 1/z1,
 18637         dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
 18638         tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
 18639         &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
 18640         &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 18641         &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
 18642         &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 18643       if (xright<0 || xleft>=dimx()) return *this;
 18644       if (xleft<0) {
 18645         const int D = xright - xleft;
 18646         yleft-=xleft*(yright - yleft)/D;
 18647         zleft-=xleft*(zright - zleft)/D;
 18648         txleft-=xleft*(txright - txleft)/D;
 18649         tyleft-=xleft*(tyright - tyleft)/D;
 18650         xleft = 0;
 18652       if (xright>=dimx()) {
 18653         const int d = xright - dimx(), D = xright - xleft;
 18654         yright-=d*(yright - yleft)/D;
 18655         zright-=d*(zright - zleft)/D;
 18656         txright-=d*(txright - txleft)/D;
 18657         tyright-=d*(tyright - tyleft)/D;
 18658         xright = dimx()-1;
 18660       if (ydown<0 || yup>=dimy()) return *this;
 18661       if (yup<0) {
 18662         const int D = ydown - yup;
 18663         xup-=yup*(xdown - xup)/D;
 18664         zup-=yup*(zdown - zup)/D;
 18665         txup-=yup*(txdown - txup)/D;
 18666         tyup-=yup*(tydown - tyup)/D;
 18667         yup = 0;
 18669       if (ydown>=dimy()) {
 18670         const int d = ydown - dimy(), D = ydown - yup;
 18671         xdown-=d*(xdown - xup)/D;
 18672         zdown-=d*(zdown - zup)/D;
 18673         txdown-=d*(txdown - txup)/D;
 18674         tydown-=d*(tydown - tyup)/D;
 18675         ydown = dimy()-1;
 18677       T *ptrd0 = ptr(nx0,ny0);
 18678       int dx = xright - xleft, dy = ydown - yup;
 18679       const bool steep = dy>dx;
 18680       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 18681       const int
 18682         offx = (nx0<nx1?1:-1)*(steep?width:1),
 18683         offy = (ny0<ny1?1:-1)*(steep?1:width),
 18684         wh = width*height,
 18685         ndx = dx>0?dx:1;
 18686       if (opacity>=1) {
 18687         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18688           if (pattern&hatch) {
 18689             const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18690             T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 18692           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18693           ptrd0+=offx;
 18694           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18695         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18696           const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18697           T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 18698           ptrd0+=offx;
 18699           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18701       } else {
 18702         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18703         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18704           if (pattern&hatch) {
 18705             const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18706             T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 18708           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18709           ptrd0+=offx;
 18710           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18711         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18712           const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18713           T *ptrd = ptrd0;
 18714           cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 18715           ptrd0+=offx;
 18716           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 18719       return *this;
 18722     //! Draw a 2D textured line, with z-buffering and perspective correction.
 18723     template<typename tc>
 18724     CImg<T>& draw_line(float *const zbuffer,
 18725                        const int x0, const int y0, const float z0,
 18726                        const int x1, const int y1, const float z1,
 18727                        const CImg<tc>& texture,
 18728                        const int tx0, const int ty0,
 18729                        const int tx1, const int ty1,
 18730                        const float opacity=1,
 18731                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18732       if (!is_empty() && z0>0 && z1>0) {
 18733         if (!texture || texture.dim<dim)
 18734           throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 18735                                       pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 18736         if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 18737         static unsigned int hatch = ~0U - (~0U>>1);
 18738         if (init_hatch) hatch = ~0U - (~0U>>1);
 18739         const bool xdir = x0<x1, ydir = y0<y1;
 18740         int
 18741           nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 18742           &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 18743           &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 18744           &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 18745           &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 18746         float
 18747           Tx0 = tx0/z0, Tx1 = tx1/z1,
 18748           Ty0 = ty0/z0, Ty1 = ty1/z1,
 18749           Z0 = 1/z0, Z1 = 1/z1,
 18750           dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
 18751           tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
 18752           &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
 18753           &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 18754           &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
 18755           &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 18756         if (xright<0 || xleft>=dimx()) return *this;
 18757         if (xleft<0) {
 18758           const int D = xright - xleft;
 18759           yleft-=xleft*(yright - yleft)/D;
 18760           zleft-=xleft*(zright - zleft)/D;
 18761           txleft-=xleft*(txright - txleft)/D;
 18762           tyleft-=xleft*(tyright - tyleft)/D;
 18763           xleft = 0;
 18765         if (xright>=dimx()) {
 18766           const int d = xright - dimx(), D = xright - xleft;
 18767           yright-=d*(yright - yleft)/D;
 18768           zright-=d*(zright - zleft)/D;
 18769           txright-=d*(txright - txleft)/D;
 18770           tyright-=d*(tyright - tyleft)/D;
 18771           xright = dimx()-1;
 18773         if (ydown<0 || yup>=dimy()) return *this;
 18774         if (yup<0) {
 18775           const int D = ydown - yup;
 18776           xup-=yup*(xdown - xup)/D;
 18777           zup-=yup*(zdown - zup)/D;
 18778           txup-=yup*(txdown - txup)/D;
 18779           tyup-=yup*(tydown - tyup)/D;
 18780           yup = 0;
 18782         if (ydown>=dimy()) {
 18783           const int d = ydown - dimy(), D = ydown - yup;
 18784           xdown-=d*(xdown - xup)/D;
 18785           zdown-=d*(zdown - zup)/D;
 18786           txdown-=d*(txdown - txup)/D;
 18787           tydown-=d*(tydown - tyup)/D;
 18788           ydown = dimy()-1;
 18790         T *ptrd0 = ptr(nx0,ny0);
 18791         float *ptrz = zbuffer + nx0 + ny0*width;
 18792         int dx = xright - xleft, dy = ydown - yup;
 18793         const bool steep = dy>dx;
 18794         if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 18795         const int
 18796           offx = (nx0<nx1?1:-1)*(steep?width:1),
 18797           offy = (ny0<ny1?1:-1)*(steep?1:width),
 18798           wh = width*height,
 18799           ndx = dx>0?dx:1;
 18800         if (opacity>=1) {
 18801           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18802             if (pattern&hatch) {
 18803               const float z = Z0 + x*dz/ndx;
 18804               if (z>*ptrz) {
 18805                 *ptrz = z;
 18806                 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18807                 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 18810             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18811             ptrd0+=offx; ptrz+=offx;
 18812             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18813           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18814             const float z = Z0 + x*dz/ndx;
 18815             if (z>*ptrz) {
 18816               *ptrz = z;
 18817               const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18818               T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 18820             ptrd0+=offx; ptrz+=offx;
 18821             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18823         } else {
 18824           const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 18825           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18826             if (pattern&hatch) {
 18827               const float z = Z0 + x*dz/ndx;
 18828               if (z>*ptrz) {
 18829                 *ptrz = z;
 18830                 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18831                 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 18834             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 18835             ptrd0+=offx; ptrz+=offx;
 18836             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 18837           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 18838             const float z = Z0 + x*dz/ndx;
 18839             if (z>*ptrz) {
 18840               *ptrz = z;
 18841               const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 18842               T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 18844             ptrd0+=offx; ptrz+=offx;
 18845             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
 18849       return *this;
 18852     // Inner routine for drawing set of consecutive lines with generic type for coordinates.
 18853     template<typename t, typename tc>
 18854     CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
 18855                         const tc *const color, const float opacity,
 18856                         const unsigned int pattern, const bool init_hatch) {
 18857       if (is_empty() || !points || W<2) return *this;
 18858       bool ninit_hatch = init_hatch;
 18859       switch (H) {
 18860       case 0 : case 1 :
 18861         throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
 18862                                     pixel_type());
 18863       case 2 : {
 18864         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 18865         int ox = x0, oy = y0;
 18866         for (unsigned int i = 1; i<W; ++i) {
 18867           const int x = (int)points(i,0), y = (int)points(i,1);
 18868           draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
 18869           ninit_hatch = false;
 18870           ox = x; oy = y;
 18872       } break;
 18873       default : {
 18874         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 18875         int ox = x0, oy = y0, oz = z0;
 18876         for (unsigned int i = 1; i<W; ++i) {
 18877           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 18878           draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
 18879           ninit_hatch = false;
 18880           ox = x; oy = y; oz = z;
 18884       return *this;
 18887     //! Draw a set of consecutive colored lines in the instance image.
 18888     /**
 18889        \param points Coordinates of vertices, stored as a list of vectors.
 18890        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 18891        \param opacity Drawing opacity (optional).
 18892        \param pattern An integer whose bits describe the line pattern (optional).
 18893        \param init_hatch If set to true, init hatch motif.
 18894        \note
 18895        - This function uses several call to the single CImg::draw_line() procedure,
 18896        depending on the vectors size in \p points.
 18897        \par Example:
 18898        \code
 18899        CImg<unsigned char> img(100,100,1,3,0);
 18900        const unsigned char color[] = { 255,128,64 };
 18901        CImgList<int> points;
 18902        points.insert(CImg<int>::vector(0,0)).
 18903              .insert(CImg<int>::vector(70,10)).
 18904              .insert(CImg<int>::vector(80,60)).
 18905              .insert(CImg<int>::vector(10,90));
 18906        img.draw_line(points,color);
 18907        \endcode
 18908     **/
 18909     template<typename t, typename tc>
 18910     CImg<T>& draw_line(const CImgList<t>& points,
 18911                        const tc *const color, const float opacity=1,
 18912                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18913       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 18914       return _draw_line(points,points.size,H,color,opacity,pattern,init_hatch);
 18917     //! Draw a set of consecutive colored lines in the instance image.
 18918     template<typename t, typename tc>
 18919     CImg<T>& draw_line(const CImgList<t>& points,
 18920                        const CImg<tc>& color, const float opacity=1,
 18921                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18922       return draw_line(points,color.data,opacity,pattern,init_hatch);
 18925     //! Draw a set of consecutive colored lines in the instance image.
 18926     /**
 18927        \note
 18928        - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
 18929        (sequence of vectors aligned along the x-axis).
 18930     **/
 18931     template<typename t, typename tc>
 18932     CImg<T>& draw_line(const CImg<t>& points,
 18933                        const tc *const color, const float opacity=1,
 18934                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18935       return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
 18938     //! Draw a set of consecutive colored lines in the instance image.
 18939     template<typename t, typename tc>
 18940     CImg<T>& draw_line(const CImg<t>& points,
 18941                        const CImg<tc>& color, const float opacity=1,
 18942                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 18943       return draw_line(points,color.data,opacity,pattern,init_hatch);
 18946     // Inner routine for a drawing filled polygon with generic type for coordinates.
 18947     template<typename t, typename tc>
 18948     CImg<T>& _draw_polygon(const t& points, const unsigned int N,
 18949                            const tc *const color, const float opacity) {
 18950       if (is_empty() || !points || N<3) return *this;
 18951       if (!color)
 18952         throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
 18953                                     pixel_type());
 18954       _draw_scanline(color,opacity);
 18955       int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
 18956       { for (unsigned int p = 0; p<N; ++p) {
 18957         const int x = (int)points(p,0), y = (int)points(p,1);
 18958         if (x<xmin) xmin = x;
 18959         if (x>xmax) xmax = x;
 18960         if (y<ymin) ymin = y;
 18961         if (y>ymax) ymax = y;
 18962       }}
 18963       if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
 18964       const unsigned int
 18965         nymin = ymin<0?0:(unsigned int)ymin,
 18966         nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
 18967         dy = 1 + nymax - nymin;
 18968       CImg<intT> X(1+2*N,dy,1,1,0), tmp;
 18969       int cx = (int)points(0,0), cy = (int)points(0,1);
 18970       for (unsigned int cp = 0, p = 0; p<N; ++p) {
 18971         const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
 18972         const int
 18973           nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
 18974           y0 = cy - nymin, y1 = ny - nymin;
 18975         if (y0!=y1) {
 18976           const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
 18977           for (int x = cx, y = y0, _sx = 1, _sy = 1,
 18978                  _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
 18979                  _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
 18980                  _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
 18981                  _err = _dx>>1,
 18982                  _rx = _dy?(nx-cx)/_dy:0;
 18983                _counter>=countermin;
 18984                --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
 18985             if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
 18986           cp = np; cx = nx; cy = ny;
 18987         } else {
 18988           const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
 18989           if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
 18990           if (cy!=ay) { cp = np; cx = nx; cy = ny; }
 18993       for (int y = 0; y<(int)dy; ++y) {
 18994         tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
 18995         for (int i = 1; i<=X(0,y); ) {
 18996           const int xb = X(i++,y), xe = X(i++,y);
 18997           _draw_scanline(xb,xe,nymin+y,color,opacity);
 19000       return *this;
 19003     //! Draw a filled polygon in the instance image.
 19004     template<typename t, typename tc>
 19005     CImg<T>& draw_polygon(const CImgList<t>& points,
 19006                           const tc *const color, const float opacity=1) {
 19007       if (!points.is_sameY(2))
 19008         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 19009                                     pixel_type());
 19010       return _draw_polygon(points,points.size,color,opacity);
 19013     //! Draw a filled polygon in the instance image.
 19014     template<typename t, typename tc>
 19015     CImg<T>& draw_polygon(const CImgList<t>& points,
 19016                           const CImg<tc>& color, const float opacity=1) {
 19017       return draw_polygon(points,color.data,opacity);
 19020     //! Draw a filled polygon in the instance image.
 19021     template<typename t, typename tc>
 19022     CImg<T>& draw_polygon(const CImg<t>& points,
 19023                           const tc *const color, const float opacity=1) {
 19024       if (points.height<2)
 19025         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 19026                                     pixel_type());
 19027       return _draw_polygon(points,points.width,color,opacity);
 19030     //! Draw a filled polygon in the instance image.
 19031     template<typename t, typename tc>
 19032     CImg<T>& draw_polygon(const CImg<t>& points,
 19033                           const CImg<tc>& color, const float opacity=1) {
 19034       return draw_polygon(points,color.data,opacity);
 19037     // Inner routine for drawing an outlined polygon with generic point coordinates.
 19038     template<typename t, typename tc>
 19039     CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
 19040                            const tc *const color, const float opacity,
 19041                            const unsigned int pattern) {
 19042       if (is_empty() || !points || W<3) return *this;
 19043       bool ninit_hatch = true;
 19044       switch (H) {
 19045       case 0 : case 1 :
 19046         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 19047                                     pixel_type());
 19048       case 2 : {
 19049         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 19050         int ox = x0, oy = y0;
 19051         for (unsigned int i = 1; i<W; ++i) {
 19052           const int x = (int)points(i,0), y = (int)points(i,1);
 19053           draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
 19054           ninit_hatch = false;
 19055           ox = x; oy = y;
 19057         draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
 19058       } break;
 19059       default : {
 19060         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 19061         int ox = x0, oy = y0, oz = z0;
 19062         for (unsigned int i = 1; i<W; ++i) {
 19063           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 19064           draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
 19065           ninit_hatch = false;
 19066           ox = x; oy = y; oz = z;
 19068         draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
 19071       return *this;
 19074     //! Draw a polygon outline.
 19075     template<typename t, typename tc>
 19076     CImg<T>& draw_polygon(const CImgList<t>& points,
 19077                           const tc *const color, const float opacity,
 19078                           const unsigned int pattern) {
 19079       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 19080       return _draw_polygon(points,points.size,H,color,opacity,pattern);
 19083     //! Draw a polygon outline.
 19084     template<typename t, typename tc>
 19085     CImg<T>& draw_polygon(const CImgList<t>& points,
 19086                           const CImg<tc>& color, const float opacity,
 19087                           const unsigned int pattern) {
 19088       return draw_polygon(points,color.data,opacity,pattern);
 19091     //! Draw a polygon outline.
 19092     template<typename t, typename tc>
 19093     CImg<T>& draw_polygon(const CImg<t>& points,
 19094                           const tc *const color, const float opacity,
 19095                           const unsigned int pattern) {
 19096       return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
 19099     //! Draw a polygon outline.
 19100     template<typename t, typename tc>
 19101     CImg<T>& draw_polygon(const CImg<t>& points,
 19102                           const CImg<tc>& color, const float opacity,
 19103                           const unsigned int pattern) {
 19104       return draw_polygon(points,color.data,opacity,pattern);
 19107     //! Draw a cubic spline curve in the instance image.
 19108     /**
 19109        \param x0 X-coordinate of the starting curve point
 19110        \param y0 Y-coordinate of the starting curve point
 19111        \param u0 X-coordinate of the starting velocity
 19112        \param v0 Y-coordinate of the starting velocity
 19113        \param x1 X-coordinate of the ending curve point
 19114        \param y1 Y-coordinate of the ending curve point
 19115        \param u1 X-coordinate of the ending velocity
 19116        \param v1 Y-coordinate of the ending velocity
 19117        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 19118        \param precision Curve drawing precision (optional).
 19119        \param opacity Drawing opacity (optional).
 19120        \param pattern An integer whose bits describe the line pattern (optional).
 19121        \param init_hatch If \c true, init hatch motif.
 19122        \note
 19123        - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
 19124        and corresponding velocity vectors.
 19125        - The spline is drawn as a serie of connected segments. The \p precision parameter sets the
 19126        average number of pixels in each drawn segment.
 19127        - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), (\p xb,\p yb), (\p x1,\p y1) }
 19128        where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point and (\p xa,\p ya), (\p xb,\p yb) are two
 19129        \e control points.
 19130        The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as
 19131        \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb).
 19132        \par Example:
 19133        \code
 19134        CImg<unsigned char> img(100,100,1,3,0);
 19135        const unsigned char color[] = { 255,255,255 };
 19136        img.draw_spline(30,30,0,100,90,40,0,-100,color);
 19137        \endcode
 19138     **/
 19139     template<typename tc>
 19140     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 19141                          const int x1, const int y1, const float u1, const float v1,
 19142                          const tc *const color, const float opacity=1,
 19143                          const float precision=4, const unsigned int pattern=~0U,
 19144                          const bool init_hatch=true) {
 19145       if (is_empty()) return *this;
 19146       if (!color)
 19147         throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
 19148                                     pixel_type());
 19149       bool ninit_hatch = init_hatch;
 19150       const float
 19151         dx = (float)(x1 - x0),
 19152         dy = (float)(y1 - y0),
 19153         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
 19154         ax = -2*dx + u0 + u1,
 19155         bx = 3*dx - 2*u0 - u1,
 19156         ay = -2*dy + v0 + v1,
 19157         by = 3*dy - 2*v0 - v1,
 19158         xprecision = dmax>0?precision/dmax:1.0f,
 19159         tmax = 1 + (dmax>0?xprecision:0.0f);
 19160       int ox = x0, oy = y0;
 19161       for (float t = 0; t<tmax; t+=xprecision) {
 19162         const float
 19163           t2 = t*t,
 19164           t3 = t2*t;
 19165         const int
 19166           nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
 19167           ny = (int)(ay*t3 + by*t2 + v0*t + y0);
 19168         draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
 19169         ninit_hatch = false;
 19170         ox = nx; oy = ny;
 19172       return *this;
 19175     //! Draw a cubic spline curve in the instance image.
 19176     template<typename tc>
 19177     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 19178                          const int x1, const int y1, const float u1, const float v1,
 19179                          const CImg<tc>& color, const float opacity=1,
 19180                          const float precision=4, const unsigned int pattern=~0U,
 19181                          const bool init_hatch=true) {
 19182       return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
 19185     //! Draw a cubic spline curve in the instance image (for volumetric images).
 19186     /**
 19187        \note
 19188        - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
 19189     **/
 19190     template<typename tc>
 19191     CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 19192                          const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 19193                          const tc *const color, const float opacity=1,
 19194                          const float precision=4, const unsigned int pattern=~0U,
 19195                          const bool init_hatch=true) {
 19196       if (is_empty()) return *this;
 19197       if (!color)
 19198         throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
 19199                                     pixel_type());
 19200       bool ninit_hatch = init_hatch;
 19201       const float
 19202         dx = (float)(x1 - x0),
 19203         dy = (float)(y1 - y0),
 19204         dz = (float)(z1 - z0),
 19205         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
 19206         ax = -2*dx + u0 + u1,
 19207         bx = 3*dx - 2*u0 - u1,
 19208         ay = -2*dy + v0 + v1,
 19209         by = 3*dy - 2*v0 - v1,
 19210         az = -2*dz + w0 + w1,
 19211         bz = 3*dz - 2*w0 - w1,
 19212         xprecision = dmax>0?precision/dmax:1.0f,
 19213         tmax = 1 + (dmax>0?xprecision:0.0f);
 19214       int ox = x0, oy = y0, oz = z0;
 19215       for (float t = 0; t<tmax; t+=xprecision) {
 19216         const float
 19217           t2 = t*t,
 19218           t3 = t2*t;
 19219         const int
 19220           nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
 19221           ny = (int)(ay*t3 + by*t2 + v0*t + y0),
 19222           nz = (int)(az*t3 + bz*t2 + w0*t + z0);
 19223         draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
 19224         ninit_hatch = false;
 19225         ox = nx; oy = ny; oz = nz;
 19227       return *this;
 19230     //! Draw a cubic spline curve in the instance image (for volumetric images).
 19231     template<typename tc>
 19232     CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 19233                          const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 19234                          const CImg<tc>& color, const float opacity=1,
 19235                          const float precision=4, const unsigned int pattern=~0U,
 19236                          const bool init_hatch=true) {
 19237       return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
 19240     //! Draw a cubic spline curve in the instance image.
 19241     /**
 19242        \param x0 X-coordinate of the starting curve point
 19243        \param y0 Y-coordinate of the starting curve point
 19244        \param u0 X-coordinate of the starting velocity
 19245        \param v0 Y-coordinate of the starting velocity
 19246        \param x1 X-coordinate of the ending curve point
 19247        \param y1 Y-coordinate of the ending curve point
 19248        \param u1 X-coordinate of the ending velocity
 19249        \param v1 Y-coordinate of the ending velocity
 19250        \param texture Texture image defining line pixel colors.
 19251        \param tx0 X-coordinate of the starting texture point.
 19252        \param ty0 Y-coordinate of the starting texture point.
 19253        \param tx1 X-coordinate of the ending texture point.
 19254        \param ty1 Y-coordinate of the ending texture point.
 19255        \param precision Curve drawing precision (optional).
 19256        \param opacity Drawing opacity (optional).
 19257        \param pattern An integer whose bits describe the line pattern (optional).
 19258        \param init_hatch if \c true, reinit hatch motif.
 19259     **/
 19260     template<typename t>
 19261     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 19262                          const int x1, const int y1, const float u1, const float v1,
 19263                          const CImg<t>& texture,
 19264                          const int tx0, const int ty0, const int tx1, const int ty1,
 19265                          const float opacity=1,
 19266                          const float precision=4, const unsigned int pattern=~0U,
 19267                          const bool init_hatch=true) {
 19268       if (is_empty()) return *this;
 19269       if (!texture || texture.dim<dim)
 19270         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 19271                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 19272       if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);
 19273       bool ninit_hatch = true;
 19274       const float
 19275         dx = (float)(x1 - x0),
 19276         dy = (float)(y1 - y0),
 19277         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
 19278         ax = -2*dx + u0 + u1,
 19279         bx = 3*dx - 2*u0 - u1,
 19280         ay = -2*dy + v0 + v1,
 19281         by = 3*dy - 2*v0 - v1,
 19282         xprecision = dmax>0?precision/dmax:1.0f,
 19283         tmax = 1 + (dmax>0?xprecision:0.0f);
 19284       int ox = x0, oy = y0, otx = tx0, oty = ty0;
 19285       for (float t1 = 0; t1<tmax; t1+=xprecision) {
 19286         const float
 19287           t2 = t1*t1,
 19288           t3 = t2*t1;
 19289         const int
 19290           nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
 19291           ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
 19292           ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
 19293           nty = ty0 + (int)((ty1-ty0)*t1/tmax);
 19294         draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
 19295         ninit_hatch = false;
 19296         ox = nx; oy = ny; otx = ntx; oty = nty;
 19298       return *this;
 19301     // Draw a set of connected spline curves in the instance image (internal).
 19302     template<typename tp, typename tt, typename tc>
 19303     CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
 19304                           const tc *const color, const float opacity,
 19305                           const bool close_set, const float precision,
 19306                           const unsigned int pattern, const bool init_hatch) {
 19307       if (is_empty() || !points || !tangents || W<2) return *this;
 19308       bool ninit_hatch = init_hatch;
 19309       switch (H) {
 19310       case 0 : case 1 :
 19311         throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
 19312                                     pixel_type());
 19313       case 2 : {
 19314         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 19315         const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
 19316         int ox = x0, oy = y0;
 19317         float ou = u0, ov = v0;
 19318         for (unsigned int i = 1; i<W; ++i) {
 19319           const int x = (int)points(i,0), y = (int)points(i,1);
 19320           const float u = (float)tangents(i,0), v = (float)tangents(i,1);
 19321           draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
 19322           ninit_hatch = false;
 19323           ox = x; oy = y; ou = u; ov = v;
 19325         if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
 19326       } break;
 19327       default : {
 19328         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 19329         const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
 19330         int ox = x0, oy = y0, oz = z0;
 19331         float ou = u0, ov = v0, ow = w0;
 19332         for (unsigned int i = 1; i<W; ++i) {
 19333           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 19334           const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
 19335           draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
 19336           ninit_hatch = false;
 19337           ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
 19339         if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
 19342       return *this;
 19345     // Draw a set of connected spline curves in the instance image (internal).
 19346     template<typename tp, typename tc>
 19347     CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
 19348                           const tc *const color, const float opacity,
 19349                           const bool close_set, const float precision,
 19350                           const unsigned int pattern, const bool init_hatch) {
 19351       if (is_empty() || !points || W<2) return *this;
 19352       CImg<Tfloat> tangents;
 19353       switch (H) {
 19354       case 0 : case 1 :
 19355         throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
 19356                                     pixel_type());
 19357       case 2 : {
 19358         tangents.assign(W,H);
 19359         for (unsigned int p = 0; p<W; ++p) {
 19360           const unsigned int
 19361             p0 = close_set?(p+W-1)%W:(p?p-1:0),
 19362             p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
 19363           const float
 19364             x = (float)points(p,0),
 19365             y = (float)points(p,1),
 19366             x0 = (float)points(p0,0),
 19367             y0 = (float)points(p0,1),
 19368             x1 = (float)points(p1,0),
 19369             y1 = (float)points(p1,1),
 19370             u0 = x - x0,
 19371             v0 = y - y0,
 19372             n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0),
 19373             u1 = x1 - x,
 19374             v1 = y1 - y,
 19375             n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1),
 19376             u = u0/n0 + u1/n1,
 19377             v = v0/n0 + v1/n1,
 19378             n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v),
 19379             fact = 0.5f*(n0 + n1);
 19380           tangents(p,0) = (Tfloat)(fact*u/n);
 19381           tangents(p,1) = (Tfloat)(fact*v/n);
 19383       } break;
 19384       default : {
 19385         tangents.assign(W,H);
 19386         for (unsigned int p = 0; p<W; ++p) {
 19387           const unsigned int
 19388             p0 = close_set?(p+W-1)%W:(p?p-1:0),
 19389             p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
 19390           const float
 19391             x = (float)points(p,0),
 19392             y = (float)points(p,1),
 19393             z = (float)points(p,2),
 19394             x0 = (float)points(p0,0),
 19395             y0 = (float)points(p0,1),
 19396             z0 = (float)points(p0,2),
 19397             x1 = (float)points(p1,0),
 19398             y1 = (float)points(p1,1),
 19399             z1 = (float)points(p1,2),
 19400             u0 = x - x0,
 19401             v0 = y - y0,
 19402             w0 = z - z0,
 19403             n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0 + w0*w0),
 19404             u1 = x1 - x,
 19405             v1 = y1 - y,
 19406             w1 = z1 - z,
 19407             n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1 + w1*w1),
 19408             u = u0/n0 + u1/n1,
 19409             v = v0/n0 + v1/n1,
 19410             w = w0/n0 + w1/n1,
 19411             n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v + w*w),
 19412             fact = 0.5f*(n0 + n1);
 19413           tangents(p,0) = (Tfloat)(fact*u/n);
 19414           tangents(p,1) = (Tfloat)(fact*v/n);
 19415           tangents(p,2) = (Tfloat)(fact*w/n);
 19419       return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
 19422     //! Draw a set of consecutive colored splines in the instance image.
 19423     template<typename tp, typename tt, typename tc>
 19424     CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 19425                          const tc *const color, const float opacity=1,
 19426                          const bool close_set=false, const float precision=4,
 19427                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19428       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
 19429       return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
 19432     //! Draw a set of consecutive colored splines in the instance image.
 19433     template<typename tp, typename tt, typename tc>
 19434     CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 19435                          const CImg<tc>& color, const float opacity=1,
 19436                          const bool close_set=false, const float precision=4,
 19437                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19438       return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
 19441     //! Draw a set of consecutive colored splines in the instance image.
 19442     template<typename tp, typename tt, typename tc>
 19443     CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 19444                          const tc *const color, const float opacity=1,
 19445                          const bool close_set=false, const float precision=4,
 19446                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19447       return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
 19450     //! Draw a set of consecutive colored splines in the instance image.
 19451     template<typename tp, typename tt, typename tc>
 19452     CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 19453                          const CImg<tc>& color, const float opacity=1,
 19454                          const bool close_set=false, const float precision=4,
 19455                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19456       return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
 19459     //! Draw a set of consecutive colored splines in the instance image.
 19460     template<typename t, typename tc>
 19461     CImg<T>& draw_spline(const CImgList<t>& points,
 19462                          const tc *const color, const float opacity=1,
 19463                          const bool close_set=false, const float precision=4,
 19464                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19465       unsigned int H = ~0U;
 19466       cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
 19467       return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
 19470     //! Draw a set of consecutive colored splines in the instance image.
 19471     template<typename t, typename tc>
 19472     CImg<T>& draw_spline(const CImgList<t>& points,
 19473                          CImg<tc>& color, const float opacity=1,
 19474                          const bool close_set=false, const float precision=4,
 19475                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19476       return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
 19479     //! Draw a set of consecutive colored lines in the instance image.
 19480     template<typename t, typename tc>
 19481     CImg<T>& draw_spline(const CImg<t>& points,
 19482                          const tc *const color, const float opacity=1,
 19483                          const bool close_set=false, const float precision=4,
 19484                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19485       return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
 19488     //! Draw a set of consecutive colored lines in the instance image.
 19489     template<typename t, typename tc>
 19490     CImg<T>& draw_spline(const CImg<t>& points,
 19491                          const CImg<tc>& color, const float opacity=1,
 19492                          const bool close_set=false, const float precision=4,
 19493                          const unsigned int pattern=~0U, const bool init_hatch=true) {
 19494       return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
 19497     //! Draw a colored arrow in the instance image.
 19498     /**
 19499        \param x0 X-coordinate of the starting arrow point (tail).
 19500        \param y0 Y-coordinate of the starting arrow point (tail).
 19501        \param x1 X-coordinate of the ending arrow point (head).
 19502        \param y1 Y-coordinate of the ending arrow point (head).
 19503        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 19504        \param angle Aperture angle of the arrow head (optional).
 19505        \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional).
 19506        \param opacity Drawing opacity (optional).
 19507        \param pattern An integer whose bits describe the line pattern (optional).
 19508        \note
 19509        - Clipping is supported.
 19510     **/
 19511     template<typename tc>
 19512     CImg<T>& draw_arrow(const int x0, const int y0,
 19513                         const int x1, const int y1,
 19514                         const tc *const color, const float opacity=1,
 19515                         const float angle=30, const float length=-10,
 19516                         const unsigned int pattern=~0U) {
 19517       if (is_empty()) return *this;
 19518       const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
 19519         deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)cimg_std::atan2(v,u):0.0f,
 19520         l = (length>=0)?length:-length*(float)cimg_std::sqrt(sq)/100;
 19521       if (sq>0) {
 19522         const float
 19523             cl = (float)cimg_std::cos(ang - deg), sl = (float)cimg_std::sin(ang - deg),
 19524             cr = (float)cimg_std::cos(ang + deg), sr = (float)cimg_std::sin(ang + deg);
 19525         const int
 19526           xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
 19527           xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
 19528           xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
 19529         draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
 19530       } else draw_point(x0,y0,color,opacity);
 19531       return *this;
 19534     //! Draw a colored arrow in the instance image.
 19535     template<typename tc>
 19536     CImg<T>& draw_arrow(const int x0, const int y0,
 19537                         const int x1, const int y1,
 19538                         const CImg<tc>& color, const float opacity=1,
 19539                         const float angle=30, const float length=-10,
 19540                         const unsigned int pattern=~0U) {
 19541       return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
 19544     //! Draw an image.
 19545     /**
 19546        \param sprite Sprite image.
 19547        \param x0 X-coordinate of the sprite position.
 19548        \param y0 Y-coordinate of the sprite position.
 19549        \param z0 Z-coordinate of the sprite position.
 19550        \param v0 V-coordinate of the sprite position.
 19551        \param opacity Drawing opacity (optional).
 19552        \note
 19553        - Clipping is supported.
 19554     **/
 19555     template<typename t>
 19556     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 19557                         const CImg<t>& sprite, const float opacity=1) {
 19558       if (is_empty()) return *this;
 19559       if (!sprite)
 19560         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 19561                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 19562       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
 19563       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 19564       const int
 19565         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 19566         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 19567         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 19568         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 19569       const t
 19570         *ptrs = sprite.data -
 19571         (bx?x0:0) -
 19572         (by?y0*sprite.dimx():0) -
 19573         (bz?z0*sprite.dimx()*sprite.dimy():0) -
 19574         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
 19575       const unsigned int
 19576         offX = width - lX,                soffX = sprite.width - lX,
 19577         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 19578         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
 19579       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 19580       if (lX>0 && lY>0 && lZ>0 && lV>0) {
 19581         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 19582         for (int v = 0; v<lV; ++v) {
 19583           for (int z = 0; z<lZ; ++z) {
 19584             for (int y = 0; y<lY; ++y) {
 19585               if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
 19586               else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
 19587               ptrd+=offX; ptrs+=soffX;
 19589             ptrd+=offY; ptrs+=soffY;
 19591           ptrd+=offZ; ptrs+=soffZ;
 19594       return *this;
 19597 #ifndef cimg_use_visualcpp6
 19598     // Otimized version (internal).
 19599     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 19600                         const CImg<T>& sprite, const float opacity=1) {
 19601       if (is_empty()) return *this;
 19602       if (!sprite)
 19603         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 19604                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 19605       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
 19606       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 19607       const int
 19608         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 19609         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 19610         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 19611         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 19612       const T
 19613         *ptrs = sprite.data -
 19614         (bx?x0:0) -
 19615         (by?y0*sprite.dimx():0) -
 19616         (bz?z0*sprite.dimx()*sprite.dimy():0) -
 19617         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
 19618       const unsigned int
 19619         offX = width - lX,                soffX = sprite.width - lX,
 19620         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 19621         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
 19622         slX = lX*sizeof(T);
 19623       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 19624       if (lX>0 && lY>0 && lZ>0 && lV>0) {
 19625         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 19626         for (int v = 0; v<lV; ++v) {
 19627           for (int z = 0; z<lZ; ++z) {
 19628             if (opacity>=1) for (int y = 0; y<lY; ++y) { cimg_std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
 19629             else for (int y = 0; y<lY; ++y) {
 19630               for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
 19631               ptrd+=offX; ptrs+=soffX;
 19633             ptrd+=offY; ptrs+=soffY;
 19635           ptrd+=offZ; ptrs+=soffZ;
 19638       return *this;
 19640 #endif
 19642     //! Draw an image.
 19643     template<typename t>
 19644     CImg<T>& draw_image(const int x0, const int y0, const int z0,
 19645                         const CImg<t>& sprite, const float opacity=1) {
 19646       return draw_image(x0,y0,z0,0,sprite,opacity);
 19649     //! Draw an image.
 19650     template<typename t>
 19651     CImg<T>& draw_image(const int x0, const int y0,
 19652                         const CImg<t>& sprite, const float opacity=1) {
 19653       return draw_image(x0,y0,0,sprite,opacity);
 19656     //! Draw an image.
 19657     template<typename t>
 19658     CImg<T>& draw_image(const int x0,
 19659                         const CImg<t>& sprite, const float opacity=1) {
 19660       return draw_image(x0,0,sprite,opacity);
 19663     //! Draw an image.
 19664     template<typename t>
 19665     CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
 19666       return draw_image(0,sprite,opacity);
 19669     //! Draw a sprite image in the instance image (masked version).
 19670     /**
 19671        \param sprite Sprite image.
 19672        \param mask Mask image.
 19673        \param x0 X-coordinate of the sprite position in the instance image.
 19674        \param y0 Y-coordinate of the sprite position in the instance image.
 19675        \param z0 Z-coordinate of the sprite position in the instance image.
 19676        \param v0 V-coordinate of the sprite position in the instance image.
 19677        \param mask_valmax Maximum pixel value of the mask image \c mask (optional).
 19678        \param opacity Drawing opacity.
 19679        \note
 19680        - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
 19681        - Clipping is supported.
 19682        - Dimensions along x,y and z of \p sprite and \p mask must be the same.
 19683     **/
 19684     template<typename ti, typename tm>
 19685     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 19686                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 19687                         const float mask_valmax=1) {
 19688       if (is_empty()) return *this;
 19689       if (!sprite)
 19690         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 19691                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 19692       if (!mask)
 19693         throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
 19694                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 19695       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
 19696       if (is_overlapped(mask))   return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
 19697       if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
 19698         throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
 19699                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
 19700       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 19701       const int
 19702         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 19703         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 19704         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 19705         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 19706       const int
 19707         coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-(bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
 19708         ssize = mask.dimx()*mask.dimy()*mask.dimz();
 19709       const ti *ptrs = sprite.data + coff;
 19710       const tm *ptrm = mask.data   + coff;
 19711       const unsigned int
 19712         offX = width - lX,                soffX = sprite.width - lX,
 19713         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 19714         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
 19715       if (lX>0 && lY>0 && lZ>0 && lV>0) {
 19716         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 19717         for (int v = 0; v<lV; ++v) {
 19718           ptrm = mask.data + (ptrm - mask.data)%ssize;
 19719           for (int z = 0; z<lZ; ++z) {
 19720             for (int y = 0; y<lY; ++y) {
 19721               for (int x=0; x<lX; ++x) {
 19722                 const float mopacity = (float)(*(ptrm++)*opacity),
 19723                   nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
 19724                 *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
 19725                 ++ptrd;
 19727               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
 19729             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
 19731           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
 19734       return *this;
 19737     //! Draw an image.
 19738     template<typename ti, typename tm>
 19739     CImg<T>& draw_image(const int x0, const int y0, const int z0,
 19740                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 19741                         const float mask_valmax=1) {
 19742       return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
 19745     //! Draw an image.
 19746     template<typename ti, typename tm>
 19747     CImg<T>& draw_image(const int x0, const int y0,
 19748                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 19749                         const float mask_valmax=1) {
 19750       return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
 19753     //! Draw an image.
 19754     template<typename ti, typename tm>
 19755     CImg<T>& draw_image(const int x0,
 19756                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 19757                         const float mask_valmax=1) {
 19758       return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
 19761     //! Draw an image.
 19762     template<typename ti, typename tm>
 19763     CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 19764                         const float mask_valmax=1) {
 19765       return draw_image(0,sprite,mask,opacity,mask_valmax);
 19768     //! Draw a 4D filled rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0)-(\c x1,\c y1,\c z1,\c v1).
 19769     /**
 19770        \param x0 X-coordinate of the upper-left rectangle corner.
 19771        \param y0 Y-coordinate of the upper-left rectangle corner.
 19772        \param z0 Z-coordinate of the upper-left rectangle corner.
 19773        \param v0 V-coordinate of the upper-left rectangle corner.
 19774        \param x1 X-coordinate of the lower-right rectangle corner.
 19775        \param y1 Y-coordinate of the lower-right rectangle corner.
 19776        \param z1 Z-coordinate of the lower-right rectangle corner.
 19777        \param v1 V-coordinate of the lower-right rectangle corner.
 19778        \param val Scalar value used to fill the rectangle area.
 19779        \param opacity Drawing opacity (optional).
 19780        \note
 19781        - Clipping is supported.
 19782     **/
 19783     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
 19784                             const int x1, const int y1, const int z1, const int v1,
 19785                             const T val, const float opacity=1) {
 19786       if (is_empty()) return *this;
 19787       const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
 19788       const int
 19789         nx0 = bx?x0:x1, nx1 = bx?x1:x0,
 19790         ny0 = by?y0:y1, ny1 = by?y1:y0,
 19791         nz0 = bz?z0:z1, nz1 = bz?z1:z0,
 19792         nv0 = bv?v0:v1, nv1 = bv?v1:v0;
 19793       const int
 19794         lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
 19795         lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
 19796         lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
 19797         lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
 19798       const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
 19799       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 19800       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
 19801       if (lX>0 && lY>0 && lZ>0 && lV>0)
 19802         for (int v = 0; v<lV; ++v) {
 19803           for (int z = 0; z<lZ; ++z) {
 19804             for (int y = 0; y<lY; ++y) {
 19805               if (opacity>=1) {
 19806                 if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
 19807                 else { cimg_std::memset(ptrd,(int)val,lX); ptrd+=width; }
 19808               } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
 19810             ptrd+=offY;
 19812           ptrd+=offZ;
 19814       return *this;
 19817     //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
 19818     /**
 19819        \param x0 X-coordinate of the upper-left rectangle corner.
 19820        \param y0 Y-coordinate of the upper-left rectangle corner.
 19821        \param z0 Z-coordinate of the upper-left rectangle corner.
 19822        \param x1 X-coordinate of the lower-right rectangle corner.
 19823        \param y1 Y-coordinate of the lower-right rectangle corner.
 19824        \param z1 Z-coordinate of the lower-right rectangle corner.
 19825        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 19826        \param opacity Drawing opacity (optional).
 19827        \note
 19828        - Clipping is supported.
 19829     **/
 19830     template<typename tc>
 19831     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 19832                             const int x1, const int y1, const int z1,
 19833                             const tc *const color, const float opacity=1) {
 19834       if (!color)
 19835         throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
 19836                                     pixel_type());
 19837       cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
 19838       return *this;
 19841     //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
 19842     template<typename tc>
 19843     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 19844                             const int x1, const int y1, const int z1,
 19845                             const CImg<tc>& color, const float opacity=1) {
 19846       return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
 19849     //! Draw a 3D outlined colored rectangle in the instance image.
 19850     template<typename tc>
 19851     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 19852                             const int x1, const int y1, const int z1,
 19853                             const tc *const color, const float opacity,
 19854                             const unsigned int pattern) {
 19855       return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
 19856         draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
 19857         draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
 19858         draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
 19859         draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
 19860         draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
 19861         draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
 19862         draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
 19863         draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
 19864         draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
 19865         draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
 19866         draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
 19869     //! Draw a 3D outlined colored rectangle in the instance image.
 19870     template<typename tc>
 19871     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 19872                             const int x1, const int y1, const int z1,
 19873                             const CImg<tc>& color, const float opacity,
 19874                             const unsigned int pattern) {
 19875       return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
 19878     //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
 19879     /**
 19880        \param x0 X-coordinate of the upper-left rectangle corner.
 19881        \param y0 Y-coordinate of the upper-left rectangle corner.
 19882        \param x1 X-coordinate of the lower-right rectangle corner.
 19883        \param y1 Y-coordinate of the lower-right rectangle corner.
 19884        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 19885        \param opacity Drawing opacity (optional).
 19886        \note
 19887        - Clipping is supported.
 19888     **/
 19889     template<typename tc>
 19890     CImg<T>& draw_rectangle(const int x0, const int y0,
 19891                             const int x1, const int y1,
 19892                             const tc *const color, const float opacity=1) {
 19893       return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
 19896     //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
 19897     template<typename tc>
 19898     CImg<T>& draw_rectangle(const int x0, const int y0,
 19899                             const int x1, const int y1,
 19900                             const CImg<tc>& color, const float opacity=1) {
 19901       return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
 19904     //! Draw a 2D outlined colored rectangle.
 19905     template<typename tc>
 19906     CImg<T>& draw_rectangle(const int x0, const int y0,
 19907                             const int x1, const int y1,
 19908                             const tc *const color, const float opacity,
 19909                             const unsigned int pattern) {
 19910       if (is_empty()) return *this;
 19911       if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
 19912       if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
 19913       const bool bx = (x0<x1), by = (y0<y1);
 19914       const int
 19915         nx0 = bx?x0:x1, nx1 = bx?x1:x0,
 19916         ny0 = by?y0:y1, ny1 = by?y1:y0;
 19917       if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
 19918                       draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
 19919       return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
 19920         draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
 19921         draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
 19922         draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
 19925     //! Draw a 2D outlined colored rectangle.
 19926     template<typename tc>
 19927     CImg<T>& draw_rectangle(const int x0, const int y0,
 19928                             const int x1, const int y1,
 19929                             const CImg<tc>& color, const float opacity,
 19930                             const unsigned int pattern) {
 19931       return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
 19934     // Inner macro for drawing triangles.
 19935 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
 19936         for (int y = y0<0?0:y0, \
 19937                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 19938                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 19939                _sxn=1, \
 19940                _sxr=1, \
 19941                _sxl=1, \
 19942                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 19943                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 19944                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 19945                _dyn = y2-y1, \
 19946                _dyr = y2-y0, \
 19947                _dyl = y1-y0, \
 19948                _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 19949                            _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 19950                            _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 19951                            cimg::min((int)(img).height-y-1,y2-y)), \
 19952                _errn = _dyn/2, \
 19953                _errr = _dyr/2, \
 19954                _errl = _dyl/2, \
 19955                _rxn = _dyn?(x2-x1)/_dyn:0, \
 19956                _rxr = _dyr?(x2-x0)/_dyr:0, \
 19957                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 19958                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
 19959              _counter>=0; --_counter, ++y, \
 19960                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 19961                xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
 19962                            (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 19964 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
 19965         for (int y = y0<0?0:y0, \
 19966                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 19967                cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
 19968                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 19969                cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
 19970                _sxn=1, _scn=1, \
 19971                _sxr=1, _scr=1, \
 19972                _sxl=1, _scl=1, \
 19973                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 19974                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 19975                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 19976                _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
 19977                _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
 19978                _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
 19979                _dyn = y2-y1, \
 19980                _dyr = y2-y0, \
 19981                _dyl = y1-y0, \
 19982                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 19983                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 19984                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 19985                           _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
 19986                           _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
 19987                           _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
 19988                           cimg::min((int)(img).height-y-1,y2-y)), \
 19989                _errn = _dyn/2, _errcn = _errn, \
 19990                _errr = _dyr/2, _errcr = _errr, \
 19991                _errl = _dyl/2, _errcl = _errl, \
 19992                _rxn = _dyn?(x2-x1)/_dyn:0, \
 19993                _rcn = _dyn?(c2-c1)/_dyn:0, \
 19994                _rxr = _dyr?(x2-x0)/_dyr:0, \
 19995                _rcr = _dyr?(c2-c0)/_dyr:0, \
 19996                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 19997                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 19998                _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
 19999                                        (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
 20000              _counter>=0; --_counter, ++y, \
 20001                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 20002                cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
 20003                xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
 20004                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 20005                (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
 20006                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 20008 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
 20009         for (int y = y0<0?0:y0, \
 20010                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 20011                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 20012                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 20013                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 20014                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 20015                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 20016                _sxn=1, _stxn=1, _styn=1, \
 20017                _sxr=1, _stxr=1, _styr=1, \
 20018                _sxl=1, _stxl=1, _styl=1, \
 20019                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 20020                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 20021                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 20022                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 20023                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 20024                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 20025                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 20026                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 20027                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 20028                _dyn = y2-y1, \
 20029                _dyr = y2-y0, \
 20030                _dyl = y1-y0, \
 20031                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 20032                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 20033                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 20034                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 20035                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 20036                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 20037                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 20038                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 20039                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 20040                           cimg::min((int)(img).height-y-1,y2-y)), \
 20041                _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
 20042                _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
 20043                _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
 20044                _rxn = _dyn?(x2-x1)/_dyn:0, \
 20045                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 20046                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 20047                _rxr = _dyr?(x2-x0)/_dyr:0, \
 20048                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 20049                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 20050                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 20051                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 20052                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 20053                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 20054                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 20055                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
 20056              _counter>=0; --_counter, ++y, \
 20057                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 20058                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 20059                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 20060                xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 20061                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 20062                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 20063                (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 20064                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
 20065                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 20067 #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \
 20068         for (int y = y0<0?0:y0, \
 20069                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 20070                cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
 20071                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 20072                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 20073                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 20074                cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
 20075                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 20076                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 20077                _sxn=1, _scn=1, _stxn=1, _styn=1, \
 20078                _sxr=1, _scr=1, _stxr=1, _styr=1, \
 20079                _sxl=1, _scl=1, _stxl=1, _styl=1, \
 20080                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 20081                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 20082                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 20083                _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
 20084                _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
 20085                _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
 20086                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 20087                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 20088                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 20089                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 20090                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 20091                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 20092                _dyn = y2-y1, \
 20093                _dyr = y2-y0, \
 20094                _dyl = y1-y0, \
 20095                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 20096                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 20097                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 20098                           _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
 20099                           _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
 20100                           _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
 20101                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 20102                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 20103                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 20104                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 20105                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 20106                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 20107                           cimg::min((int)(img).height-y-1,y2-y)), \
 20108                _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
 20109                _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
 20110                _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
 20111                _rxn = _dyn?(x2-x1)/_dyn:0, \
 20112                _rcn = _dyn?(c2-c1)/_dyn:0, \
 20113                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 20114                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 20115                _rxr = _dyr?(x2-x0)/_dyr:0, \
 20116                _rcr = _dyr?(c2-c0)/_dyr:0, \
 20117                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 20118                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 20119                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 20120                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 20121                _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
 20122                                        (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
 20123                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 20124                                         (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 20125                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 20126                                         (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
 20127              _counter>=0; --_counter, ++y, \
 20128                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 20129                cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
 20130                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 20131                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 20132                xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
 20133                             txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 20134                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 20135                             _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 20136                (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
 20137                 _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 20138                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
 20139                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 20141 #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \
 20142         for (int y = y0<0?0:y0, \
 20143                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 20144                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 20145                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 20146                lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
 20147                lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
 20148                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 20149                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 20150                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 20151                lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
 20152                lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
 20153                _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
 20154                _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
 20155                _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
 20156                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
 20157                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
 20158                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
 20159                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 20160                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 20161                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 20162                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 20163                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 20164                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 20165                _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
 20166                _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
 20167                _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
 20168                _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
 20169                _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
 20170                _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
 20171                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 20172                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 20173                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 20174                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 20175                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 20176                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 20177                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 20178                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 20179                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 20180                           _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
 20181                           _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
 20182                           _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
 20183                           _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
 20184                           _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
 20185                           _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
 20186                           cimg::min((int)(img).height-y-1,y2-y)), \
 20187                _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
 20188                _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
 20189                _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
 20190                _rxn = _dyn?(x2-x1)/_dyn:0, \
 20191                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 20192                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 20193                _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
 20194                _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
 20195                _rxr = _dyr?(x2-x0)/_dyr:0, \
 20196                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 20197                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 20198                _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
 20199                _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
 20200                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 20201                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 20202                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 20203                                         (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 20204                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 20205                                         (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
 20206                _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
 20207                                         (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
 20208                _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
 20209                                         (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
 20210              _counter>=0; --_counter, ++y, \
 20211                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 20212                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 20213                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 20214                lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
 20215                lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
 20216                xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 20217                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 20218                             lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
 20219                             lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
 20220                             _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 20221                (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 20222                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
 20223                 _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
 20224                 _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
 20225                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 20227     // Draw a colored triangle (inner routine, uses bresenham's algorithm).
 20228     template<typename tc>
 20229     CImg<T>& _draw_triangle(const int x0, const int y0,
 20230                             const int x1, const int y1,
 20231                             const int x2, const int y2,
 20232                             const tc *const color, const float opacity,
 20233                             const float brightness) {
 20234       _draw_scanline(color,opacity);
 20235       const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
 20236       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 20237       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
 20238       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
 20239       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
 20240       if (ny0<dimy() && ny2>=0) {
 20241         if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
 20242           _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
 20243         else
 20244           _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
 20246       return *this;
 20249     //! Draw a 2D filled colored triangle.
 20250     template<typename tc>
 20251     CImg<T>& draw_triangle(const int x0, const int y0,
 20252                            const int x1, const int y1,
 20253                            const int x2, const int y2,
 20254                            const tc *const color, const float opacity=1) {
 20255       if (is_empty()) return *this;
 20256       if (!color)
 20257         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 20258                                     pixel_type());
 20259       _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
 20260       return *this;
 20263     //! Draw a 2D filled colored triangle.
 20264     template<typename tc>
 20265     CImg<T>& draw_triangle(const int x0, const int y0,
 20266                            const int x1, const int y1,
 20267                            const int x2, const int y2,
 20268                            const CImg<tc>& color, const float opacity=1) {
 20269       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
 20272     //! Draw a 2D outlined colored triangle.
 20273     template<typename tc>
 20274     CImg<T>& draw_triangle(const int x0, const int y0,
 20275                            const int x1, const int y1,
 20276                            const int x2, const int y2,
 20277                            const tc *const color, const float opacity,
 20278                            const unsigned int pattern) {
 20279       if (is_empty()) return *this;
 20280       if (!color)
 20281         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 20282                                     pixel_type());
 20283       draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
 20284         draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
 20285         draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
 20286       return *this;
 20289     //! Draw a 2D outlined colored triangle.
 20290     template<typename tc>
 20291     CImg<T>& draw_triangle(const int x0, const int y0,
 20292                            const int x1, const int y1,
 20293                            const int x2, const int y2,
 20294                            const CImg<tc>& color, const float opacity,
 20295                            const unsigned int pattern) {
 20296       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
 20299     //! Draw a 2D filled colored triangle, with z-buffering.
 20300     template<typename tc>
 20301     CImg<T>& draw_triangle(float *const zbuffer,
 20302                            const int x0, const int y0, const float z0,
 20303                            const int x1, const int y1, const float z1,
 20304                            const int x2, const int y2, const float z2,
 20305                            const tc *const color, const float opacity=1,
 20306                            const float brightness=1) {
 20307       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 20308       if (!color)
 20309         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 20310                                     pixel_type());
 20311       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20312       const float
 20313         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 20314         nbrightness = brightness<0?0:(brightness>2?2:brightness);
 20315       const int whz = width*height*depth, offx = dim*whz;
 20316       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 20317       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 20318       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 20319       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
 20320       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
 20321       if (ny0>=dimy() || ny2<0) return *this;
 20322       float
 20323         pzl = (nz1 - nz0)/(ny1 - ny0),
 20324         pzr = (nz2 - nz0)/(ny2 - ny0),
 20325         pzn = (nz2 - nz1)/(ny2 - ny1),
 20326         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 20327         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 20328       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 20329         if (y==ny1) { zl = nz1; pzl = pzn; }
 20330         int xleft = xleft0, xright = xright0;
 20331         float zleft = zl, zright = zr;
 20332         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
 20333         const int dx = xright - xleft;
 20334         const float pentez = (zright - zleft)/dx;
 20335         if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
 20336         if (xleft<0) xleft = 0;
 20337         if (xright>=dimx()-1) xright = dimx()-1;
 20338         T* ptrd = ptr(xleft,y,0,0);
 20339         float *ptrz = zbuffer + xleft + y*width;
 20340         if (opacity>=1) {
 20341           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20342             if (zleft>*ptrz) {
 20343               *ptrz = zleft;
 20344               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 20345               ptrd-=offx;
 20347             zleft+=pentez;
 20348           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20349             if (zleft>*ptrz) {
 20350               *ptrz = zleft;
 20351               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
 20352               ptrd-=offx;
 20354             zleft+=pentez;
 20355           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20356             if (zleft>*ptrz) {
 20357               *ptrz = zleft;
 20358               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
 20359               ptrd-=offx;
 20361             zleft+=pentez;
 20363         } else {
 20364           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20365             if (zleft>*ptrz) {
 20366               *ptrz = zleft;
 20367               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
 20368               ptrd-=offx;
 20370             zleft+=pentez;
 20371           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20372             if (zleft>*ptrz) {
 20373               *ptrz = zleft;
 20374               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
 20375               ptrd-=offx;
 20377             zleft+=pentez;
 20378           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20379             if (zleft>*ptrz) {
 20380               *ptrz = zleft;
 20381               const tc *col = color;
 20382               cimg_forV(*this,k) {
 20383                 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 20384                 *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20385                 ptrd+=whz;
 20387               ptrd-=offx;
 20389             zleft+=pentez;
 20392         zr+=pzr; zl+=pzl;
 20394       return *this;
 20397     //! Draw a 2D filled colored triangle, with z-buffering.
 20398     template<typename tc>
 20399     CImg<T>& draw_triangle(float *const zbuffer,
 20400                            const int x0, const int y0, const float z0,
 20401                            const int x1, const int y1, const float z1,
 20402                            const int x2, const int y2, const float z2,
 20403                            const CImg<tc>& color, const float opacity=1,
 20404                            const float brightness=1) {
 20405       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
 20408     //! Draw a 2D Gouraud-shaded colored triangle.
 20409     /**
 20410        \param x0 = X-coordinate of the first corner in the instance image.
 20411        \param y0 = Y-coordinate of the first corner in the instance image.
 20412        \param x1 = X-coordinate of the second corner in the instance image.
 20413        \param y1 = Y-coordinate of the second corner in the instance image.
 20414        \param x2 = X-coordinate of the third corner in the instance image.
 20415        \param y2 = Y-coordinate of the third corner in the instance image.
 20416        \param color = array of dimv() values of type \c T, defining the global drawing color.
 20417        \param brightness0 = brightness of the first corner (in [0,2]).
 20418        \param brightness1 = brightness of the second corner (in [0,2]).
 20419        \param brightness2 = brightness of the third corner (in [0,2]).
 20420        \param opacity = opacity of the drawing.
 20421        \note Clipping is supported.
 20422     **/
 20423     template<typename tc>
 20424     CImg<T>& draw_triangle(const int x0, const int y0,
 20425                            const int x1, const int y1,
 20426                            const int x2, const int y2,
 20427                            const tc *const color,
 20428                            const float brightness0,
 20429                            const float brightness1,
 20430                            const float brightness2,
 20431                            const float opacity=1) {
 20432       if (is_empty()) return *this;
 20433       if (!color)
 20434         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 20435                                     pixel_type());
 20436       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20437       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 20438       const int whz = width*height*depth, offx = dim*whz-1;
 20439       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 20440         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 20441         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 20442         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 20443       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
 20444       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
 20445       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
 20446       if (ny0>=dimy() || ny2<0) return *this;
 20447       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 20448         int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
 20449         if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
 20450         const int
 20451           dx = xright - xleft,
 20452           dc = cright>cleft?cright - cleft:cleft - cright,
 20453           rc = dx?(cright - cleft)/dx:0,
 20454           sc = cright>cleft?1:-1,
 20455           ndc = dc-(dx?dx*(dc/dx):0);
 20456         int errc = dx>>1;
 20457         if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
 20458         if (xleft<0) xleft = 0;
 20459         if (xright>=dimx()-1) xright = dimx()-1;
 20460         T* ptrd = ptr(xleft,y);
 20461         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 20462           const tc *col = color;
 20463           cimg_forV(*this,k) {
 20464             *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 20465             ptrd+=whz;
 20467           ptrd-=offx;
 20468           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 20469         } else for (int x = xleft; x<=xright; ++x) {
 20470           const tc *col = color;
 20471           cimg_forV(*this,k) {
 20472             const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 20473             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20474             ptrd+=whz;
 20476           ptrd-=offx;
 20477           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 20480       return *this;
 20483     //! Draw a 2D Gouraud-shaded colored triangle.
 20484     template<typename tc>
 20485     CImg<T>& draw_triangle(const int x0, const int y0,
 20486                            const int x1, const int y1,
 20487                            const int x2, const int y2,
 20488                            const CImg<tc>& color,
 20489                            const float brightness0,
 20490                            const float brightness1,
 20491                            const float brightness2,
 20492                            const float opacity=1) {
 20493       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
 20496     //! Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
 20497     template<typename tc>
 20498     CImg<T>& draw_triangle(float *const zbuffer,
 20499                            const int x0, const int y0, const float z0,
 20500                            const int x1, const int y1, const float z1,
 20501                            const int x2, const int y2, const float z2,
 20502                            const tc *const color,
 20503                            const float brightness0,
 20504                            const float brightness1,
 20505                            const float brightness2,
 20506                            const float opacity=1) {
 20507       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 20508       if (!color)
 20509         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 20510                                     pixel_type());
 20511       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20512       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 20513       const int whz = width*height*depth, offx = dim*whz;
 20514       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 20515         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 20516         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 20517         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 20518       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 20519       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
 20520       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
 20521       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
 20522       if (ny0>=dimy() || ny2<0) return *this;
 20523       float
 20524         pzl = (nz1 - nz0)/(ny1 - ny0),
 20525         pzr = (nz2 - nz0)/(ny2 - ny0),
 20526         pzn = (nz2 - nz1)/(ny2 - ny1),
 20527         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 20528         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 20529       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 20530         if (y==ny1) { zl = nz1; pzl = pzn; }
 20531         int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
 20532         float zleft = zl, zright = zr;
 20533         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
 20534         const int
 20535           dx = xright - xleft,
 20536           dc = cright>cleft?cright - cleft:cleft - cright,
 20537           rc = dx?(cright-cleft)/dx:0,
 20538           sc = cright>cleft?1:-1,
 20539           ndc = dc-(dx?dx*(dc/dx):0);
 20540         const float pentez = (zright - zleft)/dx;
 20541         int errc = dx>>1;
 20542         if (xleft<0 && dx) {
 20543           cleft-=xleft*(cright - cleft)/dx;
 20544           zleft-=xleft*(zright - zleft)/dx;
 20546         if (xleft<0) xleft = 0;
 20547         if (xright>=dimx()-1) xright = dimx()-1;
 20548         T *ptrd = ptr(xleft,y);
 20549         float *ptrz = zbuffer + xleft + y*width;
 20550         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 20551           if (zleft>*ptrz) {
 20552             *ptrz = zleft;
 20553             const tc *col = color;
 20554             cimg_forV(*this,k) {
 20555               *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 20556               ptrd+=whz;
 20558             ptrd-=offx;
 20560           zleft+=pentez;
 20561           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 20562         } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 20563           if (zleft>*ptrz) {
 20564             *ptrz = zleft;
 20565             const tc *col = color;
 20566             cimg_forV(*this,k) {
 20567               const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 20568               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20569               ptrd+=whz;
 20571             ptrd-=offx;
 20573           zleft+=pentez;
 20574           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 20576         zr+=pzr; zl+=pzl;
 20578       return *this;
 20581     //! Draw a Gouraud triangle with z-buffer consideration.
 20582     template<typename tc>
 20583     CImg<T>& draw_triangle(float *const zbuffer,
 20584                            const int x0, const int y0, const float z0,
 20585                            const int x1, const int y1, const float z1,
 20586                            const int x2, const int y2, const float z2,
 20587                            const CImg<tc>& color,
 20588                            const float brightness0,
 20589                            const float brightness1,
 20590                            const float brightness2,
 20591                            const float opacity=1) {
 20592       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
 20595     //! Draw a 2D textured triangle.
 20596     /**
 20597        \param x0 = X-coordinate of the first corner in the instance image.
 20598        \param y0 = Y-coordinate of the first corner in the instance image.
 20599        \param x1 = X-coordinate of the second corner in the instance image.
 20600        \param y1 = Y-coordinate of the second corner in the instance image.
 20601        \param x2 = X-coordinate of the third corner in the instance image.
 20602        \param y2 = Y-coordinate of the third corner in the instance image.
 20603        \param texture = texture image used to fill the triangle.
 20604        \param tx0 = X-coordinate of the first corner in the texture image.
 20605        \param ty0 = Y-coordinate of the first corner in the texture image.
 20606        \param tx1 = X-coordinate of the second corner in the texture image.
 20607        \param ty1 = Y-coordinate of the second corner in the texture image.
 20608        \param tx2 = X-coordinate of the third corner in the texture image.
 20609        \param ty2 = Y-coordinate of the third corner in the texture image.
 20610        \param opacity = opacity of the drawing.
 20611        \param brightness = brightness of the drawing (in [0,2]).
 20612        \note Clipping is supported, but texture coordinates do not support clipping.
 20613     **/
 20614     template<typename tc>
 20615     CImg<T>& draw_triangle(const int x0, const int y0,
 20616                            const int x1, const int y1,
 20617                            const int x2, const int y2,
 20618                            const CImg<tc>& texture,
 20619                            const int tx0, const int ty0,
 20620                            const int tx1, const int ty1,
 20621                            const int tx2, const int ty2,
 20622                            const float opacity=1,
 20623                            const float brightness=1) {
 20624       if (is_empty()) return *this;
 20625       if (!texture || texture.dim<dim)
 20626         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 20627                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 20628       if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 20629       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20630       const float
 20631         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 20632         nbrightness = brightness<0?0:(brightness>2?2:brightness);
 20633       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 20634       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 20635         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
 20636       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
 20637       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
 20638       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
 20639       if (ny0>=dimy() || ny2<0) return *this;
 20640       _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
 20641                           nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
 20642         int
 20643           xleft = xleft0, xright = xright0,
 20644           txleft = txleft0, txright = txright0,
 20645           tyleft = tyleft0, tyright = tyright0;
 20646         if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
 20647         const int
 20648           dx = xright - xleft,
 20649           dtx = txright>txleft?txright - txleft:txleft - txright,
 20650           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 20651           rtx = dx?(txright - txleft)/dx:0,
 20652           rty = dx?(tyright - tyleft)/dx:0,
 20653           stx = txright>txleft?1:-1,
 20654           sty = tyright>tyleft?1:-1,
 20655           ndtx = dtx - (dx?dx*(dtx/dx):0),
 20656           ndty = dty - (dx?dx*(dty/dx):0);
 20657         int errtx = dx>>1, errty = errtx;
 20658         if (xleft<0 && dx) {
 20659           txleft-=xleft*(txright - txleft)/dx;
 20660           tyleft-=xleft*(tyright - tyleft)/dx;
 20662         if (xleft<0) xleft = 0;
 20663         if (xright>=dimx()-1) xright = dimx()-1;
 20664         T* ptrd = ptr(xleft,y,0,0);
 20665         if (opacity>=1) {
 20666           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 20667             const tc *col = texture.ptr(txleft,tyleft);
 20668             cimg_forV(*this,k) {
 20669               *ptrd = (T)*col;
 20670               ptrd+=whz; col+=twhz;
 20672             ptrd-=offx;
 20673             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20674             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20675           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 20676             const tc *col = texture.ptr(txleft,tyleft);
 20677             cimg_forV(*this,k) {
 20678               *ptrd = (T)(nbrightness**col);
 20679               ptrd+=whz; col+=twhz;
 20681             ptrd-=offx;
 20682             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20683             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20684           } else for (int x = xleft; x<=xright; ++x) {
 20685             const tc *col = texture.ptr(txleft,tyleft);
 20686             cimg_forV(*this,k) {
 20687               *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 20688               ptrd+=whz; col+=twhz;
 20690             ptrd-=offx;
 20691             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20692             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20694         } else {
 20695           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 20696             const tc *col = texture.ptr(txleft,tyleft);
 20697             cimg_forV(*this,k) {
 20698               *ptrd = (T)(nopacity**col + *ptrd*copacity);
 20699               ptrd+=whz; col+=twhz;
 20701             ptrd-=offx;
 20702             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20703             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20704           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 20705             const tc *col = texture.ptr(txleft,tyleft);
 20706             cimg_forV(*this,k) {
 20707               *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 20708               ptrd+=whz; col+=twhz;
 20710             ptrd-=offx;
 20711             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20712             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20713           } else for (int x = xleft; x<=xright; ++x) {
 20714             const tc *col = texture.ptr(txleft,tyleft);
 20715             cimg_forV(*this,k) {
 20716               const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 20717               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20718               ptrd+=whz; col+=twhz;
 20720             ptrd-=offx;
 20721             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 20722             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 20726       return *this;
 20729     //! Draw a 2D textured triangle, with perspective correction.
 20730     template<typename tc>
 20731     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 20732                            const int x1, const int y1, const float z1,
 20733                            const int x2, const int y2, const float z2,
 20734                            const CImg<tc>& texture,
 20735                            const int tx0, const int ty0,
 20736                            const int tx1, const int ty1,
 20737                            const int tx2, const int ty2,
 20738                            const float opacity=1,
 20739                            const float brightness=1) {
 20740       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 20741       if (!texture || texture.dim<dim)
 20742         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 20743                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 20744       if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 20745       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20746       const float
 20747         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 20748         nbrightness = brightness<0?0:(brightness>2?2:brightness);
 20749       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 20750       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 20751       float
 20752         ntx0 = tx0/z0, nty0 = ty0/z0,
 20753         ntx1 = tx1/z1, nty1 = ty1/z1,
 20754         ntx2 = tx2/z2, nty2 = ty2/z2,
 20755         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 20756       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
 20757       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
 20758       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
 20759       if (ny0>=dimy() || ny2<0) return *this;
 20760       float
 20761         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 20762         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 20763         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 20764         ptyl = (nty1 - nty0)/(ny1 - ny0),
 20765         ptyr = (nty2 - nty0)/(ny2 - ny0),
 20766         ptyn = (nty2 - nty1)/(ny2 - ny1),
 20767         pzl = (nz1 - nz0)/(ny1 - ny0),
 20768         pzr = (nz2 - nz0)/(ny2 - ny0),
 20769         pzn = (nz2 - nz1)/(ny2 - ny1),
 20770         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 20771         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 20772         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 20773         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 20774         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 20775         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 20776       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 20777         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 20778         int xleft = xleft0, xright = xright0;
 20779         float
 20780           zleft = zl, zright = zr,
 20781           txleft = txl, txright = txr,
 20782           tyleft = tyl, tyright = tyr;
 20783         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
 20784         const int dx = xright - xleft;
 20785         const float
 20786           pentez = (zright - zleft)/dx,
 20787           pentetx = (txright - txleft)/dx,
 20788           pentety = (tyright - tyleft)/dx;
 20789         if (xleft<0 && dx) {
 20790           zleft-=xleft*(zright - zleft)/dx;
 20791           txleft-=xleft*(txright - txleft)/dx;
 20792           tyleft-=xleft*(tyright - tyleft)/dx;
 20794         if (xleft<0) xleft = 0;
 20795         if (xright>=dimx()-1) xright = dimx()-1;
 20796         T* ptrd = ptr(xleft,y,0,0);
 20797         if (opacity>=1) {
 20798           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 20799             const float invz = 1/zleft;
 20800             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20801             cimg_forV(*this,k) {
 20802               *ptrd = (T)*col;
 20803               ptrd+=whz; col+=twhz;
 20805             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20806           } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 20807             const float invz = 1/zleft;
 20808             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20809             cimg_forV(*this,k) {
 20810               *ptrd = (T)(nbrightness**col);
 20811               ptrd+=whz; col+=twhz;
 20813             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20814           } else for (int x = xleft; x<=xright; ++x) {
 20815             const float invz = 1/zleft;
 20816             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20817             cimg_forV(*this,k) {
 20818               *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 20819               ptrd+=whz; col+=twhz;
 20821             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20823         } else {
 20824           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 20825             const float invz = 1/zleft;
 20826             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20827             cimg_forV(*this,k) {
 20828               *ptrd = (T)(nopacity**col + *ptrd*copacity);
 20829               ptrd+=whz; col+=twhz;
 20831             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20832           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 20833             const float invz = 1/zleft;
 20834             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20835             cimg_forV(*this,k) {
 20836               *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 20837               ptrd+=whz; col+=twhz;
 20839             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20840           } else for (int x = xleft; x<=xright; ++x) {
 20841             const float invz = 1/zleft;
 20842             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20843             cimg_forV(*this,k) {
 20844               const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 20845               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20846               ptrd+=whz; col+=twhz;
 20848             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20851         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 20853       return *this;
 20856     //! Draw a 2D textured triangle, with z-buffering and perspective correction.
 20857     template<typename tc>
 20858     CImg<T>& draw_triangle(float *const zbuffer,
 20859                            const int x0, const int y0, const float z0,
 20860                            const int x1, const int y1, const float z1,
 20861                            const int x2, const int y2, const float z2,
 20862                            const CImg<tc>& texture,
 20863                            const int tx0, const int ty0,
 20864                            const int tx1, const int ty1,
 20865                            const int tx2, const int ty2,
 20866                            const float opacity=1,
 20867                            const float brightness=1) {
 20868       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 20869       if (!texture || texture.dim<dim)
 20870         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 20871                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 20872       if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 20873       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 20874       const float
 20875         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 20876         nbrightness = brightness<0?0:(brightness>2?2:brightness);
 20877       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 20878       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 20879       float
 20880         ntx0 = tx0/z0, nty0 = ty0/z0,
 20881         ntx1 = tx1/z1, nty1 = ty1/z1,
 20882         ntx2 = tx2/z2, nty2 = ty2/z2,
 20883         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 20884       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
 20885       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
 20886       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
 20887       if (ny0>=dimy() || ny2<0) return *this;
 20888       float
 20889         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 20890         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 20891         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 20892         ptyl = (nty1 - nty0)/(ny1 - ny0),
 20893         ptyr = (nty2 - nty0)/(ny2 - ny0),
 20894         ptyn = (nty2 - nty1)/(ny2 - ny1),
 20895         pzl = (nz1 - nz0)/(ny1 - ny0),
 20896         pzr = (nz2 - nz0)/(ny2 - ny0),
 20897         pzn = (nz2 - nz1)/(ny2 - ny1),
 20898         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 20899         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 20900         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 20901         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 20902         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 20903         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 20904       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 20905         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 20906         int xleft = xleft0, xright = xright0;
 20907         float
 20908           zleft = zl, zright = zr,
 20909           txleft = txl, txright = txr,
 20910           tyleft = tyl, tyright = tyr;
 20911         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
 20912         const int dx = xright - xleft;
 20913         const float
 20914           pentez = (zright - zleft)/dx,
 20915           pentetx = (txright - txleft)/dx,
 20916           pentety = (tyright - tyleft)/dx;
 20917         if (xleft<0 && dx) {
 20918           zleft-=xleft*(zright - zleft)/dx;
 20919           txleft-=xleft*(txright - txleft)/dx;
 20920           tyleft-=xleft*(tyright - tyleft)/dx;
 20922         if (xleft<0) xleft = 0;
 20923         if (xright>=dimx()-1) xright = dimx()-1;
 20924         T *ptrd = ptr(xleft,y,0,0);
 20925         float *ptrz = zbuffer + xleft + y*width;
 20926         if (opacity>=1) {
 20927           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20928             if (zleft>*ptrz) {
 20929               *ptrz = zleft;
 20930               const float invz = 1/zleft;
 20931               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20932               cimg_forV(*this,k) {
 20933                 *ptrd = (T)*col;
 20934                 ptrd+=whz; col+=twhz;
 20936               ptrd-=offx;
 20938             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20939           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20940             if (zleft>*ptrz) {
 20941               *ptrz = zleft;
 20942               const float invz = 1/zleft;
 20943               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20944               cimg_forV(*this,k) {
 20945                 *ptrd = (T)(nbrightness**col);
 20946                 ptrd+=whz; col+=twhz;
 20948               ptrd-=offx;
 20950             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20951           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20952             if (zleft>*ptrz) {
 20953               *ptrz = zleft;
 20954               const float invz = 1/zleft;
 20955               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20956               cimg_forV(*this,k) {
 20957                 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 20958                 ptrd+=whz; col+=twhz;
 20960               ptrd-=offx;
 20962             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20964         } else {
 20965           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20966             if (zleft>*ptrz) {
 20967               *ptrz = zleft;
 20968               const float invz = 1/zleft;
 20969               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20970               cimg_forV(*this,k) {
 20971                 *ptrd = (T)(nopacity**col + *ptrd*copacity);
 20972                 ptrd+=whz; col+=twhz;
 20974               ptrd-=offx;
 20976             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20977           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20978             if (zleft>*ptrz) {
 20979               *ptrz = zleft;
 20980               const float invz = 1/zleft;
 20981               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20982               cimg_forV(*this,k) {
 20983                 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 20984                 ptrd+=whz; col+=twhz;
 20986               ptrd-=offx;
 20988             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 20989           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 20990             if (zleft>*ptrz) {
 20991               *ptrz = zleft;
 20992               const float invz = 1/zleft;
 20993               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 20994               cimg_forV(*this,k) {
 20995                 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 20996                 *ptrd = (T)(nopacity*val + *ptrd*copacity);
 20997                 ptrd+=whz; col+=twhz;
 20999               ptrd-=offx;
 21001             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21004         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 21006       return *this;
 21009     //! Draw a 2D Pseudo-Phong-shaded triangle.
 21010     /**
 21011        \param x0 = X-coordinate of the first corner in the instance image.
 21012        \param y0 = Y-coordinate of the first corner in the instance image.
 21013        \param x1 = X-coordinate of the second corner in the instance image.
 21014        \param y1 = Y-coordinate of the second corner in the instance image.
 21015        \param x2 = X-coordinate of the third corner in the instance image.
 21016        \param y2 = Y-coordinate of the third corner in the instance image.
 21017        \param color = array of dimv() values of type \c T, defining the global drawing color.
 21018        \param light = light image.
 21019        \param lx0 = X-coordinate of the first corner in the light image.
 21020        \param ly0 = Y-coordinate of the first corner in the light image.
 21021        \param lx1 = X-coordinate of the second corner in the light image.
 21022        \param ly1 = Y-coordinate of the second corner in the light image.
 21023        \param lx2 = X-coordinate of the third corner in the light image.
 21024        \param ly2 = Y-coordinate of the third corner in the light image.
 21025        \param opacity = opacity of the drawing.
 21026        \note Clipping is supported, but texture coordinates do not support clipping.
 21027     **/
 21028     template<typename tc, typename tl>
 21029     CImg<T>& draw_triangle(const int x0, const int y0,
 21030                            const int x1, const int y1,
 21031                            const int x2, const int y2,
 21032                            const tc *const color,
 21033                            const CImg<tl>& light,
 21034                            const int lx0, const int ly0,
 21035                            const int lx1, const int ly1,
 21036                            const int lx2, const int ly2,
 21037                            const float opacity=1) {
 21038       if (is_empty()) return *this;
 21039       if (!color)
 21040         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 21041                                     pixel_type());
 21042       if (!light)
 21043         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 21044                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 21045       if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21046       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21047       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21048       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21049         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 21050       const int whz = width*height*depth, offx = dim*whz-1;
 21051       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
 21052       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
 21053       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
 21054       if (ny0>=dimy() || ny2<0) return *this;
 21055       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 21056                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 21057         int
 21058           xleft = xleft0, xright = xright0,
 21059           lxleft = lxleft0, lxright = lxright0,
 21060           lyleft = lyleft0, lyright = lyright0;
 21061         if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
 21062         const int
 21063           dx = xright - xleft,
 21064           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 21065           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 21066           rlx = dx?(lxright - lxleft)/dx:0,
 21067           rly = dx?(lyright - lyleft)/dx:0,
 21068           slx = lxright>lxleft?1:-1,
 21069           sly = lyright>lyleft?1:-1,
 21070           ndlx = dlx - (dx?dx*(dlx/dx):0),
 21071           ndly = dly - (dx?dx*(dly/dx):0);
 21072         int errlx = dx>>1, errly = errlx;
 21073         if (xleft<0 && dx) {
 21074           lxleft-=xleft*(lxright - lxleft)/dx;
 21075           lyleft-=xleft*(lyright - lyleft)/dx;
 21077         if (xleft<0) xleft = 0;
 21078         if (xright>=dimx()-1) xright = dimx()-1;
 21079         T* ptrd = ptr(xleft,y,0,0);
 21080         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 21081           const tl l = light(lxleft,lyleft);
 21082           const tc *col = color;
 21083           cimg_forV(*this,k) {
 21084             *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
 21085             ptrd+=whz;
 21087           ptrd-=offx;
 21088           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21089           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21090         } else  for (int x = xleft; x<=xright; ++x) {
 21091           const tl l = light(lxleft,lyleft);
 21092           const tc *col = color;
 21093           cimg_forV(*this,k) {
 21094             const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
 21095             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21096             ptrd+=whz;
 21098           ptrd-=offx;
 21099           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21100           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21103       return *this;
 21106     //! Draw a 2D Pseudo-Phong-shaded triangle.
 21107     template<typename tc, typename tl>
 21108     CImg<T>& draw_triangle(const int x0, const int y0,
 21109                            const int x1, const int y1,
 21110                            const int x2, const int y2,
 21111                            const CImg<tc>& color,
 21112                            const CImg<tl>& light,
 21113                            const int lx0, const int ly0,
 21114                            const int lx1, const int ly1,
 21115                            const int lx2, const int ly2,
 21116                            const float opacity=1) {
 21117       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21120     //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
 21121     template<typename tc, typename tl>
 21122     CImg<T>& draw_triangle(float *const zbuffer,
 21123                            const int x0, const int y0, const float z0,
 21124                            const int x1, const int y1, const float z1,
 21125                            const int x2, const int y2, const float z2,
 21126                            const tc *const color,
 21127                            const CImg<tl>& light,
 21128                            const int lx0, const int ly0,
 21129                            const int lx1, const int ly1,
 21130                            const int lx2, const int ly2,
 21131                            const float opacity=1) {
 21132       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 21133       if (!color)
 21134         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 21135                                     pixel_type());
 21136       if (!light)
 21137         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 21138                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 21139       if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
 21140                                                      +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21141       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21142       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21143       const int whz = width*height*depth, offx = dim*whz;
 21144       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21145         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 21146       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 21147       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 21148       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 21149       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 21150       if (ny0>=dimy() || ny2<0) return *this;
 21151       float
 21152         pzl = (nz1 - nz0)/(ny1 - ny0),
 21153         pzr = (nz2 - nz0)/(ny2 - ny0),
 21154         pzn = (nz2 - nz1)/(ny2 - ny1),
 21155         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 21156         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 21157       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 21158                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 21159         if (y==ny1) { zl = nz1; pzl = pzn; }
 21160         int
 21161           xleft = xleft0, xright = xright0,
 21162           lxleft = lxleft0, lxright = lxright0,
 21163           lyleft = lyleft0, lyright = lyright0;
 21164         float zleft = zl, zright = zr;
 21165         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
 21166         const int
 21167           dx = xright - xleft,
 21168           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 21169           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 21170           rlx = dx?(lxright - lxleft)/dx:0,
 21171           rly = dx?(lyright - lyleft)/dx:0,
 21172           slx = lxright>lxleft?1:-1,
 21173           sly = lyright>lyleft?1:-1,
 21174           ndlx = dlx - (dx?dx*(dlx/dx):0),
 21175           ndly = dly - (dx?dx*(dly/dx):0);
 21176         const float pentez = (zright - zleft)/dx;
 21177         int errlx = dx>>1, errly = errlx;
 21178         if (xleft<0 && dx) {
 21179           zleft-=xleft*(zright - zleft)/dx;
 21180           lxleft-=xleft*(lxright - lxleft)/dx;
 21181           lyleft-=xleft*(lyright - lyleft)/dx;
 21183         if (xleft<0) xleft = 0;
 21184         if (xright>=dimx()-1) xright = dimx()-1;
 21185         T *ptrd = ptr(xleft,y,0,0);
 21186         float *ptrz = zbuffer + xleft + y*width;
 21187         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 21188           if (zleft>*ptrz) {
 21189             *ptrz = zleft;
 21190             const tl l = light(lxleft,lyleft);
 21191             const tc *col = color;
 21192             cimg_forV(*this,k) {
 21193               const tc cval = *(col++);
 21194               *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
 21195               ptrd+=whz;
 21197             ptrd-=offx;
 21199           zleft+=pentez;
 21200           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21201           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21202         } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 21203           if (zleft>*ptrz) {
 21204             *ptrz = zleft;
 21205             const tl l = light(lxleft,lyleft);
 21206             const tc *col = color;
 21207             cimg_forV(*this,k) {
 21208               const tc cval = *(col++);
 21209               const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
 21210               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21211               ptrd+=whz;
 21213             ptrd-=offx;
 21215           zleft+=pentez;
 21216           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21217           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21219         zr+=pzr; zl+=pzl;
 21221       return *this;
 21224     //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
 21225     template<typename tc, typename tl>
 21226     CImg<T>& draw_triangle(float *const zbuffer,
 21227                            const int x0, const int y0, const float z0,
 21228                            const int x1, const int y1, const float z1,
 21229                            const int x2, const int y2, const float z2,
 21230                            const CImg<tc>& color,
 21231                            const CImg<tl>& light,
 21232                            const int lx0, const int ly0,
 21233                            const int lx1, const int ly1,
 21234                            const int lx2, const int ly2,
 21235                            const float opacity=1) {
 21236       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21239     //! Draw a 2D Gouraud-shaded textured triangle.
 21240     /**
 21241        \param x0 = X-coordinate of the first corner in the instance image.
 21242        \param y0 = Y-coordinate of the first corner in the instance image.
 21243        \param x1 = X-coordinate of the second corner in the instance image.
 21244        \param y1 = Y-coordinate of the second corner in the instance image.
 21245        \param x2 = X-coordinate of the third corner in the instance image.
 21246        \param y2 = Y-coordinate of the third corner in the instance image.
 21247        \param texture = texture image used to fill the triangle.
 21248        \param tx0 = X-coordinate of the first corner in the texture image.
 21249        \param ty0 = Y-coordinate of the first corner in the texture image.
 21250        \param tx1 = X-coordinate of the second corner in the texture image.
 21251        \param ty1 = Y-coordinate of the second corner in the texture image.
 21252        \param tx2 = X-coordinate of the third corner in the texture image.
 21253        \param ty2 = Y-coordinate of the third corner in the texture image.
 21254        \param brightness0 = brightness value of the first corner.
 21255        \param brightness1 = brightness value of the second corner.
 21256        \param brightness2 = brightness value of the third corner.
 21257        \param opacity = opacity of the drawing.
 21258        \note Clipping is supported, but texture coordinates do not support clipping.
 21259     **/
 21260     template<typename tc>
 21261     CImg<T>& draw_triangle(const int x0, const int y0,
 21262                            const int x1, const int y1,
 21263                            const int x2, const int y2,
 21264                            const CImg<tc>& texture,
 21265                            const int tx0, const int ty0,
 21266                            const int tx1, const int ty1,
 21267                            const int tx2, const int ty2,
 21268                            const float brightness0,
 21269                            const float brightness1,
 21270                            const float brightness2,
 21271                            const float opacity=1) {
 21272       if (is_empty()) return *this;
 21273       if (!texture || texture.dim<dim)
 21274         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21275                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21276       if (is_overlapped(texture))
 21277         return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
 21278       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21279       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21280       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 21281       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21282         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
 21283         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 21284         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 21285         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 21286       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
 21287       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
 21288       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
 21289       if (ny0>=dimy() || ny2<0) return *this;
 21290       _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
 21291                           nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
 21292         int
 21293           xleft = xleft0, xright = xright0,
 21294           cleft = cleft0, cright = cright0,
 21295           txleft = txleft0, txright = txright0,
 21296           tyleft = tyleft0, tyright = tyright0;
 21297         if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
 21298         const int
 21299           dx = xright - xleft,
 21300           dc = cright>cleft?cright - cleft:cleft - cright,
 21301           dtx = txright>txleft?txright - txleft:txleft - txright,
 21302           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 21303           rc = dx?(cright - cleft)/dx:0,
 21304           rtx = dx?(txright - txleft)/dx:0,
 21305           rty = dx?(tyright - tyleft)/dx:0,
 21306           sc = cright>cleft?1:-1,
 21307           stx = txright>txleft?1:-1,
 21308           sty = tyright>tyleft?1:-1,
 21309           ndc = dc - (dx?dx*(dc/dx):0),
 21310           ndtx = dtx - (dx?dx*(dtx/dx):0),
 21311           ndty = dty - (dx?dx*(dty/dx):0);
 21312         int errc = dx>>1, errtx = errc, errty = errc;
 21313         if (xleft<0 && dx) {
 21314           cleft-=xleft*(cright - cleft)/dx;
 21315           txleft-=xleft*(txright - txleft)/dx;
 21316           tyleft-=xleft*(tyright - tyleft)/dx;
 21318         if (xleft<0) xleft = 0;
 21319         if (xright>=dimx()-1) xright = dimx()-1;
 21320         T* ptrd = ptr(xleft,y,0,0);
 21321         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 21322           const tc *col = texture.ptr(txleft,tyleft);
 21323           cimg_forV(*this,k) {
 21324             *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21325             ptrd+=whz; col+=twhz;
 21327           ptrd-=offx;
 21328           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21329           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 21330           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 21331         } else for (int x = xleft; x<=xright; ++x) {
 21332           const tc *col = texture.ptr(txleft,tyleft);
 21333           cimg_forV(*this,k) {
 21334             const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21335             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21336             ptrd+=whz; col+=twhz;
 21338           ptrd-=offx;
 21339           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21340           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 21341           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 21344       return *this;
 21347     //! Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
 21348     template<typename tc>
 21349     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 21350                            const int x1, const int y1, const float z1,
 21351                            const int x2, const int y2, const float z2,
 21352                            const CImg<tc>& texture,
 21353                            const int tx0, const int ty0,
 21354                            const int tx1, const int ty1,
 21355                            const int tx2, const int ty2,
 21356                            const float brightness0,
 21357                            const float brightness1,
 21358                            const float brightness2,
 21359                            const float opacity=1) {
 21360       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 21361       if (!texture || texture.dim<dim)
 21362         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21363                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21364       if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
 21365                                                        brightness0,brightness1,brightness2,opacity);
 21366       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21367       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21368       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 21369       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21370         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 21371         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 21372         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 21373       float
 21374         ntx0 = tx0/z0, nty0 = ty0/z0,
 21375         ntx1 = tx1/z1, nty1 = ty1/z1,
 21376         ntx2 = tx2/z2, nty2 = ty2/z2,
 21377         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 21378       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
 21379       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
 21380       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
 21381       if (ny0>=dimy() || ny2<0) return *this;
 21382       float
 21383         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 21384         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 21385         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 21386         ptyl = (nty1 - nty0)/(ny1 - ny0),
 21387         ptyr = (nty2 - nty0)/(ny2 - ny0),
 21388         ptyn = (nty2 - nty1)/(ny2 - ny1),
 21389         pzl = (nz1 - nz0)/(ny1 - ny0),
 21390         pzr = (nz2 - nz0)/(ny2 - ny0),
 21391         pzn = (nz2 - nz1)/(ny2 - ny1),
 21392         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 21393         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 21394         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 21395         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 21396         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 21397         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 21398       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 21399         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 21400         int
 21401           xleft = xleft0, xright = xright0,
 21402           cleft = cleft0, cright = cright0;
 21403         float
 21404           zleft = zl, zright = zr,
 21405           txleft = txl, txright = txr,
 21406           tyleft = tyl, tyright = tyr;
 21407         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
 21408         const int
 21409           dx = xright - xleft,
 21410           dc = cright>cleft?cright - cleft:cleft - cright,
 21411           rc = dx?(cright - cleft)/dx:0,
 21412           sc = cright>cleft?1:-1,
 21413           ndc = dc - (dx?dx*(dc/dx):0);
 21414         const float
 21415           pentez = (zright - zleft)/dx,
 21416           pentetx = (txright - txleft)/dx,
 21417           pentety = (tyright - tyleft)/dx;
 21418         int errc = dx>>1;
 21419         if (xleft<0 && dx) {
 21420           cleft-=xleft*(cright - cleft)/dx;
 21421           zleft-=xleft*(zright - zleft)/dx;
 21422           txleft-=xleft*(txright - txleft)/dx;
 21423           tyleft-=xleft*(tyright - tyleft)/dx;
 21425         if (xleft<0) xleft = 0;
 21426         if (xright>=dimx()-1) xright = dimx()-1;
 21427         T* ptrd = ptr(xleft,y,0,0);
 21428         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 21429           const float invz = 1/zleft;
 21430           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21431           cimg_forV(*this,k) {
 21432             *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21433             ptrd+=whz; col+=twhz;
 21435           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21436           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21437         } else for (int x = xleft; x<=xright; ++x) {
 21438           const float invz = 1/zleft;
 21439           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21440           cimg_forV(*this,k) {
 21441             const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21442             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21443             ptrd+=whz; col+=twhz;
 21445           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21446           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21448         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 21450       return *this;
 21453     //! Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
 21454     template<typename tc>
 21455     CImg<T>& draw_triangle(float *const zbuffer,
 21456                            const int x0, const int y0, const float z0,
 21457                            const int x1, const int y1, const float z1,
 21458                            const int x2, const int y2, const float z2,
 21459                            const CImg<tc>& texture,
 21460                            const int tx0, const int ty0,
 21461                            const int tx1, const int ty1,
 21462                            const int tx2, const int ty2,
 21463                            const float brightness0,
 21464                            const float brightness1,
 21465                            const float brightness2,
 21466                            const float opacity=1) {
 21467       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 21468       if (!texture || texture.dim<dim)
 21469         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21470                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21471       if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
 21472                                                        brightness0,brightness1,brightness2,opacity);
 21473       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21474       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21475       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 21476       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21477         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 21478         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 21479         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 21480       float
 21481         ntx0 = tx0/z0, nty0 = ty0/z0,
 21482         ntx1 = tx1/z1, nty1 = ty1/z1,
 21483         ntx2 = tx2/z2, nty2 = ty2/z2,
 21484         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 21485       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
 21486       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
 21487       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
 21488       if (ny0>=dimy() || ny2<0) return *this;
 21489       float
 21490         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 21491         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 21492         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 21493         ptyl = (nty1 - nty0)/(ny1 - ny0),
 21494         ptyr = (nty2 - nty0)/(ny2 - ny0),
 21495         ptyn = (nty2 - nty1)/(ny2 - ny1),
 21496         pzl = (nz1 - nz0)/(ny1 - ny0),
 21497         pzr = (nz2 - nz0)/(ny2 - ny0),
 21498         pzn = (nz2 - nz1)/(ny2 - ny1),
 21499         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 21500         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 21501         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 21502         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 21503         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 21504         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 21505       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 21506         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 21507         int
 21508           xleft = xleft0, xright = xright0,
 21509           cleft = cleft0, cright = cright0;
 21510         float
 21511           zleft = zl, zright = zr,
 21512           txleft = txl, txright = txr,
 21513           tyleft = tyl, tyright = tyr;
 21514         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
 21515         const int
 21516           dx = xright - xleft,
 21517           dc = cright>cleft?cright - cleft:cleft - cright,
 21518           rc = dx?(cright - cleft)/dx:0,
 21519           sc = cright>cleft?1:-1,
 21520           ndc = dc - (dx?dx*(dc/dx):0);
 21521         const float
 21522           pentez = (zright - zleft)/dx,
 21523           pentetx = (txright - txleft)/dx,
 21524           pentety = (tyright - tyleft)/dx;
 21525         int errc = dx>>1;
 21526         if (xleft<0 && dx) {
 21527           cleft-=xleft*(cright - cleft)/dx;
 21528           zleft-=xleft*(zright - zleft)/dx;
 21529           txleft-=xleft*(txright - txleft)/dx;
 21530           tyleft-=xleft*(tyright - tyleft)/dx;
 21532         if (xleft<0) xleft = 0;
 21533         if (xright>=dimx()-1) xright = dimx()-1;
 21534         T* ptrd = ptr(xleft,y);
 21535         float *ptrz = zbuffer + xleft + y*width;
 21536         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 21537           if (zleft>*ptrz) {
 21538             *ptrz = zleft;
 21539             const float invz = 1/zleft;
 21540             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21541             cimg_forV(*this,k) {
 21542               *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21543               ptrd+=whz; col+=twhz;
 21545             ptrd-=offx;
 21547           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21548           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21549         } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 21550           if (zleft>*ptrz) {
 21551             *ptrz = zleft;
 21552             const float invz = 1/zleft;
 21553             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21554             cimg_forV(*this,k) {
 21555               const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 21556               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21557               ptrd+=whz; col+=twhz;
 21559             ptrd-=offx;
 21561           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21562           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 21564         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 21566       return *this;
 21569     //! Draw a 2D Pseudo-Phong-shaded textured triangle.
 21570     /**
 21571        \param x0 = X-coordinate of the first corner in the instance image.
 21572        \param y0 = Y-coordinate of the first corner in the instance image.
 21573        \param x1 = X-coordinate of the second corner in the instance image.
 21574        \param y1 = Y-coordinate of the second corner in the instance image.
 21575        \param x2 = X-coordinate of the third corner in the instance image.
 21576        \param y2 = Y-coordinate of the third corner in the instance image.
 21577        \param texture = texture image used to fill the triangle.
 21578        \param tx0 = X-coordinate of the first corner in the texture image.
 21579        \param ty0 = Y-coordinate of the first corner in the texture image.
 21580        \param tx1 = X-coordinate of the second corner in the texture image.
 21581        \param ty1 = Y-coordinate of the second corner in the texture image.
 21582        \param tx2 = X-coordinate of the third corner in the texture image.
 21583        \param ty2 = Y-coordinate of the third corner in the texture image.
 21584        \param light = light image.
 21585        \param lx0 = X-coordinate of the first corner in the light image.
 21586        \param ly0 = Y-coordinate of the first corner in the light image.
 21587        \param lx1 = X-coordinate of the second corner in the light image.
 21588        \param ly1 = Y-coordinate of the second corner in the light image.
 21589        \param lx2 = X-coordinate of the third corner in the light image.
 21590        \param ly2 = Y-coordinate of the third corner in the light image.
 21591        \param opacity = opacity of the drawing.
 21592        \note Clipping is supported, but texture coordinates do not support clipping.
 21593     **/
 21594     template<typename tc, typename tl>
 21595     CImg<T>& draw_triangle(const int x0, const int y0,
 21596                            const int x1, const int y1,
 21597                            const int x2, const int y2,
 21598                            const CImg<tc>& texture,
 21599                            const int tx0, const int ty0,
 21600                            const int tx1, const int ty1,
 21601                            const int tx2, const int ty2,
 21602                            const CImg<tl>& light,
 21603                            const int lx0, const int ly0,
 21604                            const int lx1, const int ly1,
 21605                            const int lx2, const int ly2,
 21606                            const float opacity=1) {
 21607       if (is_empty()) return *this;
 21608       if (!texture || texture.dim<dim)
 21609         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21610                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21611       if (!light)
 21612         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 21613                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 21614       if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21615       if (is_overlapped(light))   return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21616       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21617       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21618       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 21619       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21620         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
 21621         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 21622       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
 21623       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
 21624       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
 21625       if (ny0>=dimy() || ny2<0) return *this;
 21626       _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
 21627                           nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
 21628         int
 21629           xleft = xleft0, xright = xright0,
 21630           lxleft = lxleft0, lxright = lxright0,
 21631           lyleft = lyleft0, lyright = lyright0,
 21632           txleft = txleft0, txright = txright0,
 21633           tyleft = tyleft0, tyright = tyright0;
 21634         if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
 21635         const int
 21636           dx = xright - xleft,
 21637           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 21638           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 21639           dtx = txright>txleft?txright - txleft:txleft - txright,
 21640           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 21641           rlx = dx?(lxright - lxleft)/dx:0,
 21642           rly = dx?(lyright - lyleft)/dx:0,
 21643           rtx = dx?(txright - txleft)/dx:0,
 21644           rty = dx?(tyright - tyleft)/dx:0,
 21645           slx = lxright>lxleft?1:-1,
 21646           sly = lyright>lyleft?1:-1,
 21647           stx = txright>txleft?1:-1,
 21648           sty = tyright>tyleft?1:-1,
 21649           ndlx = dlx - (dx?dx*(dlx/dx):0),
 21650           ndly = dly - (dx?dx*(dly/dx):0),
 21651           ndtx = dtx - (dx?dx*(dtx/dx):0),
 21652           ndty = dty - (dx?dx*(dty/dx):0);
 21653         int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
 21654         if (xleft<0 && dx) {
 21655           lxleft-=xleft*(lxright - lxleft)/dx;
 21656           lyleft-=xleft*(lyright - lyleft)/dx;
 21657           txleft-=xleft*(txright - txleft)/dx;
 21658           tyleft-=xleft*(tyright - tyleft)/dx;
 21660         if (xleft<0) xleft = 0;
 21661         if (xright>=dimx()-1) xright = dimx()-1;
 21662         T* ptrd = ptr(xleft,y,0,0);
 21663         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 21664           const tl l = light(lxleft,lyleft);
 21665           const tc *col = texture.ptr(txleft,tyleft);
 21666           cimg_forV(*this,k) {
 21667             *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21668             ptrd+=whz; col+=twhz;
 21670           ptrd-=offx;
 21671           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21672           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21673           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 21674           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 21675         } else for (int x = xleft; x<=xright; ++x) {
 21676           const tl l = light(lxleft,lyleft);
 21677           const tc *col = texture.ptr(txleft,tyleft);
 21678           cimg_forV(*this,k) {
 21679             const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21680             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21681             ptrd+=whz; col+=twhz;
 21683           ptrd-=offx;
 21684           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21685           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21686           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 21687           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 21690       return *this;
 21693     //! Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
 21694     template<typename tc, typename tl>
 21695     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 21696                            const int x1, const int y1, const float z1,
 21697                            const int x2, const int y2, const float z2,
 21698                            const CImg<tc>& texture,
 21699                            const int tx0, const int ty0,
 21700                            const int tx1, const int ty1,
 21701                            const int tx2, const int ty2,
 21702                            const CImg<tl>& light,
 21703                            const int lx0, const int ly0,
 21704                            const int lx1, const int ly1,
 21705                            const int lx2, const int ly2,
 21706                            const float opacity=1) {
 21707       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 21708       if (!texture || texture.dim<dim)
 21709         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21710                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21711       if (!light)
 21712         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 21713                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 21714       if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21715       if (is_overlapped(light)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21716       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21717       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21718       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 21719       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21720         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 21721       float
 21722         ntx0 = tx0/z0, nty0 = ty0/z0,
 21723         ntx1 = tx1/z1, nty1 = ty1/z1,
 21724         ntx2 = tx2/z2, nty2 = ty2/z2,
 21725         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 21726       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 21727       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 21728       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 21729       if (ny0>=dimy() || ny2<0) return *this;
 21730       float
 21731         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 21732         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 21733         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 21734         ptyl = (nty1 - nty0)/(ny1 - ny0),
 21735         ptyr = (nty2 - nty0)/(ny2 - ny0),
 21736         ptyn = (nty2 - nty1)/(ny2 - ny1),
 21737         pzl = (nz1 - nz0)/(ny1 - ny0),
 21738         pzr = (nz2 - nz0)/(ny2 - ny0),
 21739         pzn = (nz2 - nz1)/(ny2 - ny1),
 21740         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 21741         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 21742         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 21743         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 21744         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 21745         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 21746       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 21747                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 21748         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 21749         int
 21750           xleft = xleft0, xright = xright0,
 21751           lxleft = lxleft0, lxright = lxright0,
 21752           lyleft = lyleft0, lyright = lyright0;
 21753         float
 21754           zleft = zl, zright = zr,
 21755           txleft = txl, txright = txr,
 21756           tyleft = tyl, tyright = tyr;
 21757         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
 21758         const int
 21759           dx = xright - xleft,
 21760           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 21761           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 21762           rlx = dx?(lxright - lxleft)/dx:0,
 21763           rly = dx?(lyright - lyleft)/dx:0,
 21764           slx = lxright>lxleft?1:-1,
 21765           sly = lyright>lyleft?1:-1,
 21766           ndlx = dlx - (dx?dx*(dlx/dx):0),
 21767           ndly = dly - (dx?dx*(dly/dx):0);
 21768         const float
 21769           pentez = (zright - zleft)/dx,
 21770           pentetx = (txright - txleft)/dx,
 21771           pentety = (tyright - tyleft)/dx;
 21772         int errlx = dx>>1, errly = errlx;
 21773         if (xleft<0 && dx) {
 21774           zleft-=xleft*(zright - zleft)/dx;
 21775           lxleft-=xleft*(lxright - lxleft)/dx;
 21776           lyleft-=xleft*(lyright - lyleft)/dx;
 21777           txleft-=xleft*(txright - txleft)/dx;
 21778           tyleft-=xleft*(tyright - tyleft)/dx;
 21780         if (xleft<0) xleft = 0;
 21781         if (xright>=dimx()-1) xright = dimx()-1;
 21782         T* ptrd = ptr(xleft,y,0,0);
 21783         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 21784           const float invz = 1/zleft;
 21785           const tl l = light(lxleft,lyleft);
 21786           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21787           cimg_forV(*this,k) {
 21788             *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21789             ptrd+=whz; col+=twhz;
 21791           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21792           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21793           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21794         } else for (int x = xleft; x<=xright; ++x) {
 21795           const float invz = 1/zleft;
 21796           const tl l = light(lxleft,lyleft);
 21797           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21798           cimg_forV(*this,k) {
 21799             const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21800             *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21801             ptrd+=whz; col+=twhz;
 21803           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21804           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21805           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21807         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 21809       return *this;
 21812     //! Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction.
 21813     template<typename tc, typename tl>
 21814     CImg<T>& draw_triangle(float *const zbuffer,
 21815                            const int x0, const int y0, const float z0,
 21816                            const int x1, const int y1, const float z1,
 21817                            const int x2, const int y2, const float z2,
 21818                            const CImg<tc>& texture,
 21819                            const int tx0, const int ty0,
 21820                            const int tx1, const int ty1,
 21821                            const int tx2, const int ty2,
 21822                            const CImg<tl>& light,
 21823                            const int lx0, const int ly0,
 21824                            const int lx1, const int ly1,
 21825                            const int lx2, const int ly2,
 21826                            const float opacity=1) {
 21827       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 21828       if (!texture || texture.dim<dim)
 21829         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 21830                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 21831       if (!light)
 21832         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 21833                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 21834       if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
 21835                                                        +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21836       if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
 21837                                                      texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 21838       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 21839       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 21840       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 21841       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 21842         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 21843       float
 21844         ntx0 = tx0/z0, nty0 = ty0/z0,
 21845         ntx1 = tx1/z1, nty1 = ty1/z1,
 21846         ntx2 = tx2/z2, nty2 = ty2/z2,
 21847         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 21848       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 21849       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 21850       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 21851       if (ny0>=dimy() || ny2<0) return *this;
 21852       float
 21853         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 21854         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 21855         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 21856         ptyl = (nty1 - nty0)/(ny1 - ny0),
 21857         ptyr = (nty2 - nty0)/(ny2 - ny0),
 21858         ptyn = (nty2 - nty1)/(ny2 - ny1),
 21859         pzl = (nz1 - nz0)/(ny1 - ny0),
 21860         pzr = (nz2 - nz0)/(ny2 - ny0),
 21861         pzn = (nz2 - nz1)/(ny2 - ny1),
 21862         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 21863         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 21864         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 21865         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 21866         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 21867         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 21868       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 21869                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 21870         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 21871         int
 21872           xleft = xleft0, xright = xright0,
 21873           lxleft = lxleft0, lxright = lxright0,
 21874           lyleft = lyleft0, lyright = lyright0;
 21875         float
 21876           zleft = zl, zright = zr,
 21877           txleft = txl, txright = txr,
 21878           tyleft = tyl, tyright = tyr;
 21879         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
 21880         const int
 21881           dx = xright - xleft,
 21882           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 21883           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 21884           rlx = dx?(lxright - lxleft)/dx:0,
 21885           rly = dx?(lyright - lyleft)/dx:0,
 21886           slx = lxright>lxleft?1:-1,
 21887           sly = lyright>lyleft?1:-1,
 21888           ndlx = dlx - (dx?dx*(dlx/dx):0),
 21889           ndly = dly - (dx?dx*(dly/dx):0);
 21890         const float
 21891           pentez = (zright - zleft)/dx,
 21892           pentetx = (txright - txleft)/dx,
 21893           pentety = (tyright - tyleft)/dx;
 21894         int errlx = dx>>1, errly = errlx;
 21895         if (xleft<0 && dx) {
 21896           zleft-=xleft*(zright - zleft)/dx;
 21897           lxleft-=xleft*(lxright - lxleft)/dx;
 21898           lyleft-=xleft*(lyright - lyleft)/dx;
 21899           txleft-=xleft*(txright - txleft)/dx;
 21900           tyleft-=xleft*(tyright - tyleft)/dx;
 21902         if (xleft<0) xleft = 0;
 21903         if (xright>=dimx()-1) xright = dimx()-1;
 21904         T* ptrd = ptr(xleft,y);
 21905         float *ptrz = zbuffer + xleft + y*width;
 21906         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 21907           if (zleft>*ptrz) {
 21908             *ptrz = zleft;
 21909             const float invz = 1/zleft;
 21910             const tl l = light(lxleft,lyleft);
 21911             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21912             cimg_forV(*this,k) {
 21913               *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21914               ptrd+=whz; col+=twhz;
 21916             ptrd-=offx;
 21918           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21919           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21920           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21921         } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 21922           if (zleft>*ptrz) {
 21923             *ptrz = zleft;
 21924             const float invz = 1/zleft;
 21925             const tl l = light(lxleft,lyleft);
 21926             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 21927             cimg_forV(*this,k) {
 21928               const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 21929               *ptrd = (T)(nopacity*val + *ptrd*copacity);
 21930               ptrd+=whz; col+=twhz;
 21932             ptrd-=offx;
 21934           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 21935           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 21936           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 21938         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 21940       return *this;
 21943     // Draw a 2D ellipse (inner routine).
 21944     template<typename tc>
 21945     CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 21946                            const tc *const color, const float opacity,
 21947                            const unsigned int pattern) {
 21948       if (is_empty()) return *this;
 21949       if (!color)
 21950         throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
 21951                                     pixel_type());
 21952       _draw_scanline(color,opacity);
 21953       const float
 21954         nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
 21955         norm = (float)cimg_std::sqrt(ru*ru+rv*rv),
 21956         u = norm>0?ru/norm:1,
 21957         v = norm>0?rv/norm:0,
 21958         rmax = cimg::max(nr1,nr2),
 21959         l1 = (float)cimg_std::pow(rmax/(nr1>0?nr1:1e-6),2),
 21960         l2 = (float)cimg_std::pow(rmax/(nr2>0?nr2:1e-6),2),
 21961         a = l1*u*u + l2*v*v,
 21962         b = u*v*(l1-l2),
 21963         c = l1*v*v + l2*u*u;
 21964       const int
 21965         yb = (int)cimg_std::sqrt(a*rmax*rmax/(a*c-b*b)),
 21966         tymin = y0 - yb - 1,
 21967         tymax = y0 + yb + 1,
 21968         ymin = tymin<0?0:tymin,
 21969         ymax = tymax>=dimy()?height-1:tymax;
 21970       int oxmin = 0, oxmax = 0;
 21971       bool first_line = true;
 21972       for (int y = ymin; y<=ymax; ++y) {
 21973         const float
 21974           Y = y-y0 + (y<y0?0.5f:-0.5f),
 21975           delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
 21976           sdelta = delta>0?(float)cimg_std::sqrt(delta)/a:0.0f,
 21977           bY = b*Y/a,
 21978           fxmin = x0-0.5f-bY-sdelta,
 21979           fxmax = x0+0.5f-bY+sdelta;
 21980         const int xmin = (int)fxmin, xmax = (int)fxmax;
 21981         if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
 21982         else {
 21983           if (first_line) {
 21984             if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
 21985             else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
 21986             first_line = false;
 21987           } else {
 21988             if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
 21989             else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
 21990             if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
 21991             else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
 21992             if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
 21995         oxmin = xmin; oxmax = xmax;
 21997       return *this;
 22000     //! Draw a filled ellipse.
 22001     /**
 22002        \param x0 = X-coordinate of the ellipse center.
 22003        \param y0 = Y-coordinate of the ellipse center.
 22004        \param r1 = First radius of the ellipse.
 22005        \param r2 = Second radius of the ellipse.
 22006        \param ru = X-coordinate of the orientation vector related to the first radius.
 22007        \param rv = Y-coordinate of the orientation vector related to the first radius.
 22008        \param color = array of dimv() values of type \c T, defining the drawing color.
 22009        \param opacity = opacity of the drawing.
 22010     **/
 22011     template<typename tc>
 22012     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 22013                           const tc *const color, const float opacity=1) {
 22014       return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
 22017     //! Draw a filled ellipse.
 22018     template<typename tc>
 22019     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 22020                           const CImg<tc>& color, const float opacity=1) {
 22021       return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
 22024     //! Draw a filled ellipse.
 22025     /**
 22026        \param x0 = X-coordinate of the ellipse center.
 22027        \param y0 = Y-coordinate of the ellipse center.
 22028        \param tensor = Diffusion tensor describing the ellipse.
 22029        \param color = array of dimv() values of type \c T, defining the drawing color.
 22030        \param opacity = opacity of the drawing.
 22031     **/
 22032     template<typename t, typename tc>
 22033     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 22034                           const tc *const color, const float opacity=1) {
 22035       CImgList<t> eig = tensor.get_symmetric_eigen();
 22036       const CImg<t> &val = eig[0], &vec = eig[1];
 22037       return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
 22040     //! Draw a filled ellipse.
 22041     template<typename t, typename tc>
 22042     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 22043                           const CImg<tc>& color, const float opacity=1) {
 22044       return draw_ellipse(x0,y0,tensor,color.data,opacity);
 22047     //! Draw an outlined ellipse.
 22048     /**
 22049        \param x0 = X-coordinate of the ellipse center.
 22050        \param y0 = Y-coordinate of the ellipse center.
 22051        \param r1 = First radius of the ellipse.
 22052        \param r2 = Second radius of the ellipse.
 22053        \param ru = X-coordinate of the orientation vector related to the first radius.
 22054        \param rv = Y-coordinate of the orientation vector related to the first radius.
 22055        \param color = array of dimv() values of type \c T, defining the drawing color.
 22056        \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
 22057        \param opacity = opacity of the drawing.
 22058     **/
 22059     template<typename tc>
 22060     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 22061                           const tc *const color, const float opacity,
 22062                           const unsigned int pattern) {
 22063       if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
 22064       return *this;
 22067     //! Draw an outlined ellipse.
 22068     template<typename tc>
 22069     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 22070                           const CImg<tc>& color, const float opacity,
 22071                           const unsigned int pattern) {
 22072       return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
 22075     //! Draw an outlined ellipse.
 22076     /**
 22077        \param x0 = X-coordinate of the ellipse center.
 22078        \param y0 = Y-coordinate of the ellipse center.
 22079        \param tensor = Diffusion tensor describing the ellipse.
 22080        \param color = array of dimv() values of type \c T, defining the drawing color.
 22081        \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
 22082        \param opacity = opacity of the drawing.
 22083     **/
 22084     template<typename t, typename tc>
 22085     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 22086                           const tc *const color, const float opacity,
 22087                           const unsigned int pattern) {
 22088       CImgList<t> eig = tensor.get_symmetric_eigen();
 22089       const CImg<t> &val = eig[0], &vec = eig[1];
 22090       return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
 22093     //! Draw an outlined ellipse.
 22094     template<typename t, typename tc>
 22095     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 22096                           const CImg<tc>& color, const float opacity,
 22097                           const unsigned int pattern) {
 22098       return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
 22101     //! Draw a filled circle.
 22102     /**
 22103        \param x0 X-coordinate of the circle center.
 22104        \param y0 Y-coordinate of the circle center.
 22105        \param radius  Circle radius.
 22106        \param color Array of dimv() values of type \c T, defining the drawing color.
 22107        \param opacity Drawing opacity.
 22108        \note
 22109        - Circle version of the Bresenham's algorithm is used.
 22110     **/
 22111     template<typename tc>
 22112     CImg<T>& draw_circle(const int x0, const int y0, int radius,
 22113                          const tc *const color, const float opacity=1) {
 22114       if (!is_empty()) {
 22115         if (!color)
 22116           throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
 22117                                       pixel_type());
 22118         _draw_scanline(color,opacity);
 22119         if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
 22120         if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
 22121         for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
 22122           if (f>=0) {
 22123             const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
 22124             if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 22125             if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
 22126             f+=(ddFy+=2); --y;
 22128           const bool no_diag = y!=(x++);
 22129           ++(f+=(ddFx+=2));
 22130           const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
 22131           if (no_diag) {
 22132             if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 22133             if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
 22137       return *this;
 22140     //! Draw a filled circle.
 22141     template<typename tc>
 22142     CImg<T>& draw_circle(const int x0, const int y0, int radius,
 22143                          const CImg<tc>& color, const float opacity=1) {
 22144       return draw_circle(x0,y0,radius,color.data,opacity);
 22147     //! Draw an outlined circle.
 22148     /**
 22149        \param x0 X-coordinate of the circle center.
 22150        \param y0 Y-coordinate of the circle center.
 22151        \param radius Circle radius.
 22152        \param color Array of dimv() values of type \c T, defining the drawing color.
 22153        \param opacity Drawing opacity.
 22154     **/
 22155     template<typename tc>
 22156     CImg<T>& draw_circle(const int x0, const int y0, int radius,
 22157                          const tc *const color, const float opacity,
 22158                          const unsigned int) {
 22159       if (!is_empty()) {
 22160         if (!color)
 22161           throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
 22162                                       pixel_type());
 22163         if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
 22164         if (!radius) return draw_point(x0,y0,color,opacity);
 22165         draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
 22166           draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
 22167         if (radius==1) return *this;
 22168         for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
 22169           if (f>=0) { f+=(ddFy+=2); --y; }
 22170           ++x; ++(f+=(ddFx+=2));
 22171           if (x!=y+1) {
 22172             const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x, x3 = x0-x, x4 = x0+x, y3 = y0-y, y4 = y0+y;
 22173             draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
 22174               draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
 22175             if (x!=y)
 22176               draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
 22177                 draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
 22181       return *this;
 22184     //! Draw an outlined circle.
 22185     template<typename tc>
 22186     CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
 22187                          const float opacity,
 22188                          const unsigned int pattern) {
 22189       return draw_circle(x0,y0,radius,color.data,opacity,pattern);
 22192     // Draw a text (internal).
 22193     template<typename tc1, typename tc2, typename t>
 22194     CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
 22195                         const tc1 *const foreground_color, const tc2 *const background_color,
 22196                         const float opacity, const CImgList<t>& font) {
 22197       if (!text) return *this;
 22198       if (!font)
 22199         throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
 22200                                     pixel_type(),font.size,font.data);
 22201       const int text_length = cimg::strlen(text);
 22203       if (is_empty()) {
 22204         // If needed, pre-compute necessary size of the image
 22205         int x = 0, y = 0, w = 0;
 22206         unsigned char c = 0;
 22207         for (int i = 0; i<text_length; ++i) {
 22208           c = text[i];
 22209           switch (c) {
 22210           case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
 22211           case '\t' : x+=4*font[' '].width; break;
 22212           default : if (c<font.size) x+=font[c].width;
 22215         if (x!=0 || c=='\n') {
 22216           if (x>w) w=x;
 22217           y+=font[' '].height;
 22219         assign(x0+w,y0+y,1,font[' '].dim,0);
 22220         if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
 22223       int x = x0, y = y0;
 22224       CImg<T> letter;
 22225       for (int i = 0; i<text_length; ++i) {
 22226         const unsigned char c = text[i];
 22227         switch (c) {
 22228         case '\n' : y+=font[' '].height; x = x0; break;
 22229         case '\t' : x+=4*font[' '].width; break;
 22230         default : if (c<font.size) {
 22231           letter = font[c];
 22232           const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
 22233           if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
 22234             if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
 22235           if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
 22236             if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
 22237           if (!background_color && font.size>=512) draw_image(x,y,letter,mask,opacity,(T)1);
 22238           else draw_image(x,y,letter,opacity);
 22239           x+=letter.width;
 22243       return *this;
 22246     //! Draw a text.
 22247     /**
 22248        \param x0 X-coordinate of the text in the instance image.
 22249        \param y0 Y-coordinate of the text in the instance image.
 22250        \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 22251        \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 22252        \param font Font used for drawing text.
 22253        \param opacity Drawing opacity.
 22254        \param format 'printf'-style format string, followed by arguments.
 22255        \note Clipping is supported.
 22256     **/
 22257     template<typename tc1, typename tc2, typename t>
 22258     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22259                        const tc1 *const foreground_color, const tc2 *const background_color,
 22260                        const float opacity, const CImgList<t>& font, ...) {
 22261       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 22262       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22263       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 22266     //! Draw a text.
 22267     template<typename tc1, typename tc2, typename t>
 22268     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22269                        const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 22270                        const float opacity, const CImgList<t>& font, ...) {
 22271       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 22272       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22273       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 22276     //! Draw a text.
 22277     template<typename tc, typename t>
 22278     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22279                        const tc *const foreground_color, const int background_color,
 22280                        const float opacity, const CImgList<t>& font, ...) {
 22281       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 22282       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22283       return _draw_text(x0,y0,tmp,foreground_color,(tc*)background_color,opacity,font);
 22286     //! Draw a text.
 22287     template<typename tc, typename t>
 22288     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22289                        const int foreground_color, const tc *const background_color,
 22290                        const float opacity, const CImgList<t>& font, ...) {
 22291       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 22292       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22293       return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
 22296     //! Draw a text.
 22297     /**
 22298        \param x0 X-coordinate of the text in the instance image.
 22299        \param y0 Y-coordinate of the text in the instance image.
 22300        \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 22301        \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 22302        \param font_size Size of the font (nearest match).
 22303        \param opacity Drawing opacity.
 22304        \param format 'printf'-style format string, followed by arguments.
 22305        \note Clipping is supported.
 22306     **/
 22307     template<typename tc1, typename tc2>
 22308     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22309                        const tc1 *const foreground_color, const tc2 *const background_color,
 22310                        const float opacity=1, const unsigned int font_size=11, ...) {
 22311       static CImgList<T> font;
 22312       static unsigned int fsize = 0;
 22313       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 22314       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22315       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 22318     //! Draw a text.
 22319     template<typename tc1, typename tc2>
 22320     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22321                        const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 22322                        const float opacity=1, const unsigned int font_size=11, ...) {
 22323       static CImgList<T> font;
 22324       static unsigned int fsize = 0;
 22325       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 22326       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22327       return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
 22330     //! Draw a text.
 22331     template<typename tc>
 22332     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22333                        const tc *const foreground_color, const int background_color=0,
 22334                        const float opacity=1, const unsigned int font_size=11, ...) {
 22335       static CImgList<T> font;
 22336       static unsigned int fsize = 0;
 22337       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 22338       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22339       return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
 22342     //! Draw a text.
 22343     template<typename tc>
 22344     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 22345                        const int foreground_color, const tc *const background_color,
 22346                        const float opacity=1, const unsigned int font_size=11, ...) {
 22347       static CImgList<T> font;
 22348       static unsigned int fsize = 0;
 22349       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 22350       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 22351       return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
 22354     //! Draw a vector field in the instance image, using a colormap.
 22355     /**
 22356        \param flow Image of 2d vectors used as input data.
 22357        \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 22358        \param sampling Length (in pixels) between each arrow.
 22359        \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 22360        \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 22361        \param opacity Opacity of the drawing.
 22362        \param pattern Used pattern to draw lines.
 22363        \note Clipping is supported.
 22364     **/
 22365     template<typename t1, typename t2>
 22366     CImg<T>& draw_quiver(const CImg<t1>& flow,
 22367                          const t2 *const color, const float opacity=1,
 22368                          const unsigned int sampling=25, const float factor=-20,
 22369                          const int quiver_type=0, const unsigned int pattern=~0U) {
 22370       return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,quiver_type,pattern);
 22373     //! Draw a vector field in the instance image, using a colormap.
 22374     /**
 22375        \param flow Image of 2d vectors used as input data.
 22376        \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 22377        \param sampling Length (in pixels) between each arrow.
 22378        \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 22379        \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 22380        \param opacity Opacity of the drawing.
 22381        \param pattern Used pattern to draw lines.
 22382        \note Clipping is supported.
 22383     **/
 22384     template<typename t1, typename t2>
 22385     CImg<T>& draw_quiver(const CImg<t1>& flow,
 22386                          const CImg<t2>& color, const float opacity=1,
 22387                          const unsigned int sampling=25, const float factor=-20,
 22388                          const int quiver_type=0, const unsigned int pattern=~0U) {
 22389       if (!is_empty()) {
 22390         if (!flow || flow.dim!=2)
 22391           throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
 22392                                       pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
 22393         if (sampling<=0)
 22394           throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
 22395                                       pixel_type(),sampling);
 22396         const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
 22397         if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,quiver_type,pattern);
 22399         float vmax,fact;
 22400         if (factor<=0) {
 22401           float m, M = (float)flow.get_pointwise_norm(2).maxmin(m);
 22402           vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
 22403           fact = -factor;
 22404         } else { fact = factor; vmax = 1; }
 22406         for (unsigned int y=sampling/2; y<height; y+=sampling)
 22407           for (unsigned int x=sampling/2; x<width; x+=sampling) {
 22408             const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
 22409             float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
 22410             if (!quiver_type) {
 22411               const int xx = x+(int)u, yy = y+(int)v;
 22412               if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
 22413               else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
 22414             } else {
 22415               if (colorfield) draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color.get_vector_at(X,Y),opacity,pattern);
 22416               else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color,opacity,pattern);
 22420       return *this;
 22423     //! Draw a 1D graph on the instance image.
 22424     /**
 22425        \param data Image containing the graph values I = f(x).
 22426        \param color Array of dimv() values of type \c T, defining the drawing color.
 22427        \param gtype Define the type of the plot :
 22428                       - 0 = Plot using points clouds.
 22429                       - 1 = Plot using linear interpolation (segments).
 22430                       - 2 = Plot with bars.
 22431                       - 3 = Plot using cubic interpolation (3-polynomials).
 22432                       - 4 = Plot using cross clouds.
 22433        \param ymin Lower bound of the y-range.
 22434        \param ymax Upper bound of the y-range.
 22435        \param opacity Drawing opacity.
 22436        \param pattern Drawing pattern.
 22437        \note
 22438          - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
 22439     **/
 22440     template<typename t, typename tc>
 22441     CImg<T>& draw_graph(const CImg<t>& data,
 22442                         const tc *const color, const float opacity=1,
 22443                         const unsigned int plot_type=1, const unsigned int vertex_type=1,
 22444                         const double ymin=0, const double ymax=0,
 22445                         const unsigned int pattern=~0U) {
 22446       if (is_empty() || height<=1) return *this;;
 22447       const unsigned long siz = data.size();
 22448       if (!color)
 22449         throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
 22450                                     pixel_type());
 22451       tc *color1 = 0, *color2 = 0;
 22452       if (plot_type==3) {
 22453         color1 = new tc[dim]; color2 = new tc[dim];
 22454         cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
 22457       double m = ymin, M = ymax;
 22458       if (ymin==ymax) m = (double)data.maxmin(M);
 22459       if (m==M) { --m; ++M; }
 22460       const float ca = (float)(M-m)/(height-1);
 22461       bool init_hatch = true;
 22463       // Draw graph edges
 22464       switch (plot_type%4) {
 22465       case 1 : { // Segments
 22466         int oX = 0, oY = (int)((data[0]-m)/ca);
 22467         for (unsigned long off = 1; off<siz; ++off) {
 22468           const int
 22469             X = (int)(off*width/siz),
 22470             Y = (int)((data[off]-m)/ca);
 22471           draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
 22472           oX = X; oY = Y;
 22473           init_hatch = false;
 22475       } break;
 22476       case 2 : { // Spline
 22477         const CImg<t> ndata = data.get_shared_points(0,siz-1);
 22478         int oY = (int)((data[0]-m)/ca);
 22479         cimg_forX(*this,x) {
 22480           const int Y = (int)((ndata._cubic_atX((float)x*ndata.width/width)-m)/ca);
 22481           if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
 22482           init_hatch = false;
 22483           oY = Y;
 22485       } break;
 22486       case 3 : { // Bars
 22487         const int Y0 = (int)(-m/ca);
 22488         int oX = 0;
 22489         cimg_foroff(data,off) {
 22490           const int
 22491             X = (off+1)*width/siz-1,
 22492             Y = (int)((data[off]-m)/ca);
 22493           draw_rectangle(oX,Y0,X,Y,color1,opacity).
 22494             draw_line(oX,Y,oX,Y0,color2,opacity).
 22495             draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
 22496             draw_line(X,Y,X,Y0,color,opacity).
 22497             draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
 22498           oX = X+1;
 22500       } break;
 22501       default : break; // No edges
 22504       // Draw graph points
 22505       switch (vertex_type%8) {
 22506       case 1 : { // Point
 22507         cimg_foroff(data,off) {
 22508           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22509           draw_point(X,Y,color,opacity);
 22511       } break;
 22512       case 2 : { // Standard Cross
 22513         cimg_foroff(data,off) {
 22514           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22515           draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
 22517       } break;
 22518       case 3 : { // Rotated Cross
 22519         cimg_foroff(data,off) {
 22520           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22521           draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
 22523       } break;
 22524       case 4 : { // Filled Circle
 22525         cimg_foroff(data,off) {
 22526           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22527           draw_circle(X,Y,3,color,opacity);
 22529       } break;
 22530       case 5 : { // Outlined circle
 22531         cimg_foroff(data,off) {
 22532           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22533           draw_circle(X,Y,3,color,opacity,0U);
 22535       } break;
 22536       case 6 : { // Square
 22537         cimg_foroff(data,off) {
 22538           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22539           draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
 22541       } break;
 22542       case 7 : { // Diamond
 22543         cimg_foroff(data,off) {
 22544           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 22545           draw_line(X,Y-4,X+4,Y,color,opacity).
 22546             draw_line(X+4,Y,X,Y+4,color,opacity).
 22547             draw_line(X,Y+4,X-4,Y,color,opacity).
 22548             draw_line(X-4,Y,X,Y-4,color,opacity);
 22550       } break;
 22551       default : break; // No vertices
 22554       if (color1) delete[] color1; if (color2) delete[] color2;
 22555       return *this;
 22558     //! Draw a 1D graph on the instance image.
 22559     template<typename t, typename tc>
 22560     CImg<T>& draw_graph(const CImg<t>& data,
 22561                         const CImg<tc>& color, const float opacity=1,
 22562                         const unsigned int plot_type=1, const unsigned int vertex_type=1,
 22563                         const double ymin=0, const double ymax=0,
 22564                         const unsigned int pattern=~0U) {
 22565       return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,pattern);
 22568     //! Draw a labeled horizontal axis on the instance image.
 22569     /**
 22570        \param xvalues Lower bound of the x-range.
 22571        \param y Y-coordinate of the horizontal axis in the instance image.
 22572        \param color Array of dimv() values of type \c T, defining the drawing color.
 22573        \param opacity Drawing opacity.
 22574        \param pattern Drawing pattern.
 22575        \param opacity_out Drawing opacity of 'outside' axes.
 22576        \note if \c precision==0, precision of the labels is automatically computed.
 22577     **/
 22578     template<typename t, typename tc>
 22579     CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 22580                        const tc *const color, const float opacity=1,
 22581                        const unsigned int pattern=~0U) {
 22582       if (!is_empty()) {
 22583         int siz = (int)xvalues.size()-1;
 22584         if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
 22585         else {
 22586           if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
 22587           else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
 22588           const int yt = (y+14)<dimy()?(y+3):(y-14);
 22589           char txt[32];
 22590           cimg_foroff(xvalues,x) {
 22591             cimg_std::sprintf(txt,"%g",(double)xvalues(x));
 22592             const int xi = (int)(x*(width-1)/siz), xt = xi-(int)cimg::strlen(txt)*3;
 22593             draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
 22594               draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
 22598       return *this;
 22601     //! Draw a labeled horizontal axis on the instance image.
 22602     template<typename t, typename tc>
 22603     CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 22604                        const CImg<tc>& color, const float opacity=1,
 22605                        const unsigned int pattern=~0U) {
 22606       return draw_axis(xvalues,y,color.data,opacity,pattern);
 22609     //! Draw a labeled vertical axis on the instance image.
 22610     template<typename t, typename tc>
 22611     CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 22612                        const tc *const color, const float opacity=1,
 22613                        const unsigned int pattern=~0U) {
 22614       if (!is_empty()) {
 22615         int siz = (int)yvalues.size()-1;
 22616         if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
 22617         else {
 22618           if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
 22619           else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
 22620           char txt[32];
 22621           cimg_foroff(yvalues,y) {
 22622             cimg_std::sprintf(txt,"%g",(double)yvalues(y));
 22623             const int
 22624               yi = (int)(y*(height-1)/siz),
 22625               tmp = yi-5,
 22626               nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
 22627               xt = x-(int)cimg::strlen(txt)*7;
 22628             draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
 22629             if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
 22630             else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
 22634       return *this;
 22637     //! Draw a labeled vertical axis on the instance image.
 22638     template<typename t, typename tc>
 22639     CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 22640                        const CImg<tc>& color, const float opacity=1,
 22641                        const unsigned int pattern=~0U) {
 22642       return draw_axis(x,yvalues,color.data,opacity,pattern);
 22645     //! Draw a labeled horizontal+vertical axis on the instance image.
 22646     template<typename tx, typename ty, typename tc>
 22647       CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 22648                          const tc *const color, const float opacity=1,
 22649                          const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22650       if (!is_empty()) {
 22651         const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
 22652         const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
 22653         if (sizx>0) {
 22654           float ox = (float)nxvalues[0];
 22655           for (unsigned int x = 1; x<width; ++x) {
 22656             const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
 22657             if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
 22658             ox = nx;
 22661         const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
 22662         const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
 22663         if (sizy>0) {
 22664           float oy = (float)nyvalues[0];
 22665           for (unsigned int y = 1; y<height; ++y) {
 22666             const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
 22667             if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
 22668             oy = ny;
 22672       return *this;
 22675     //! Draw a labeled horizontal+vertical axis on the instance image.
 22676     template<typename tx, typename ty, typename tc>
 22677     CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 22678                        const CImg<tc>& color, const float opacity=1,
 22679                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22680       return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
 22683     //! Draw a labeled horizontal+vertical axis on the instance image.
 22684     template<typename tc>
 22685     CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 22686                        const tc *const color, const float opacity=1,
 22687                        const int subdivisionx=-60, const int subdivisiony=-60,
 22688                        const float precisionx=0, const float precisiony=0,
 22689                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22690       if (!is_empty()) {
 22691         const float
 22692           dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
 22693           px = (precisionx==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0):precisionx,
 22694           py = (precisiony==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0):precisiony;
 22695         draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
 22696                   CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
 22697                   color,opacity,patternx,patterny);
 22699       return *this;
 22702     //! Draw a labeled horizontal+vertical axis on the instance image.
 22703     template<typename tc>
 22704     CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 22705                        const CImg<tc>& color, const float opacity=1,
 22706                        const int subdivisionx=-60, const int subdivisiony=-60,
 22707                        const float precisionx=0, const float precisiony=0,
 22708                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22709       return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
 22712     //! Draw grid.
 22713     template<typename tx, typename ty, typename tc>
 22714     CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 22715                        const tc *const color, const float opacity=1,
 22716                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22717       if (!is_empty()) {
 22718         if (xvalues) cimg_foroff(xvalues,x) {
 22719           const int xi = (int)xvalues[x];
 22720           if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
 22722         if (yvalues) cimg_foroff(yvalues,y) {
 22723           const int yi = (int)yvalues[y];
 22724           if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
 22727       return *this;
 22730     //! Draw grid.
 22731     template<typename tx, typename ty, typename tc>
 22732     CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 22733                        const CImg<tc>& color, const float opacity=1,
 22734                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22735       return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
 22738     //! Draw grid.
 22739     template<typename tc>
 22740     CImg<T>& draw_grid(const float deltax,  const float deltay,
 22741                        const float offsetx, const float offsety,
 22742                        const bool invertx, const bool inverty,
 22743                        const tc *const color, const float opacity=1,
 22744                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22745       CImg<uintT> seqx, seqy;
 22746       if (deltax!=0) {
 22747         const float dx = deltax>0?deltax:width*-deltax/100;
 22748         const unsigned int nx = (unsigned int)(width/dx);
 22749         seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
 22750         if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
 22751         if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
 22754       if (deltay!=0) {
 22755         const float dy = deltay>0?deltay:height*-deltay/100;
 22756         const unsigned int ny = (unsigned int)(height/dy);
 22757         seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
 22758         if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
 22759         if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
 22761       return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
 22764     //! Draw grid.
 22765     template<typename tc>
 22766     CImg<T>& draw_grid(const float deltax,  const float deltay,
 22767                        const float offsetx, const float offsety,
 22768                        const bool invertx, const bool inverty,
 22769                        const CImg<tc>& color, const float opacity=1,
 22770                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 22771       return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
 22774     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 22775     /**
 22776        \param x X-coordinate of the starting point of the region to fill.
 22777        \param y Y-coordinate of the starting point of the region to fill.
 22778        \param z Z-coordinate of the starting point of the region to fill.
 22779        \param color An array of dimv() values of type \c T, defining the drawing color.
 22780        \param region Image that will contain the mask of the filled region mask, as an output.
 22781        \param sigma Tolerance concerning neighborhood values.
 22782        \param opacity Opacity of the drawing.
 22783        \param high_connexity Tells if 8-connexity must be used (only for 2D images).
 22784        \return \p region is initialized with the binary mask of the filled region.
 22785     **/
 22786     template<typename tc, typename t>
 22787     CImg<T>& draw_fill(const int x, const int y, const int z,
 22788                        const tc *const color, const float opacity,
 22789                        CImg<t>& region, const float sigma=0,
 22790                        const bool high_connexity=false) {
 22792 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
 22793   res = true; \
 22794   const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
 22795   for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
 22796   region(x,y,z) = (t)(res?1:noregion); \
 22799 #define _cimg_draw_fill_set(x,y,z) { \
 22800   const tc *col = color; \
 22801   T *ptrd = ptr(x,y,z); \
 22802   if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
 22803   else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
 22806 #define _cimg_draw_fill_insert(x,y,z) { \
 22807   if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
 22808   unsigned int *ptrr = remaining.ptr(0,posr1); \
 22809   *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
 22812 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
 22813   const unsigned int tx = x, ty = y, tz = z; \
 22814   _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
 22817       if (!color)
 22818         throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
 22819                                     pixel_type());
 22820       region.assign(width,height,depth,1,(t)0);
 22821       if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
 22822         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 22823         const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
 22824         const bool threed = depth>1;
 22825         const CImg<T> reference_color = get_vector_at(x,y,z);
 22826         CImg<uintT> remaining(3,512,1,1,0);
 22827         remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
 22828         unsigned int posr0 = 0, posr1 = 1;
 22829         region(x,y,z) = (t)1;
 22830         const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
 22831         if (threed) do { // 3D version of the filling algorithm
 22832           const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
 22833           if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 22834           bool cont, res;
 22835           unsigned int nxc = xc;
 22836           do { // X-backward
 22837             _cimg_draw_fill_set(nxc,yc,zc);
 22838             _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 22839             _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 22840             _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 22841             _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 22842             if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 22843           } while (cont);
 22844           nxc = xc;
 22845           do { // X-forward
 22846             if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 22847             if (cont) {
 22848               _cimg_draw_fill_set(nxc,yc,zc);
 22849               _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 22850               _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 22851               _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 22852               _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 22854           } while (cont);
 22855           unsigned int nyc = yc;
 22856           do { // Y-backward
 22857             if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 22858             if (cont) {
 22859               _cimg_draw_fill_set(xc,nyc,zc);
 22860               _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 22861               _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 22862               _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 22863               _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 22865           } while (cont);
 22866           nyc = yc;
 22867           do { // Y-forward
 22868             if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 22869             if (cont) {
 22870               _cimg_draw_fill_set(xc,nyc,zc);
 22871               _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 22872               _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 22873               _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 22874               _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 22876           } while (cont);
 22877           unsigned int nzc = zc;
 22878           do { // Z-backward
 22879             if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 22880             if (cont) {
 22881               _cimg_draw_fill_set(xc,yc,nzc);
 22882               _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 22883               _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 22884               _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 22885               _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 22887           } while (cont);
 22888           nzc = zc;
 22889           do { // Z-forward
 22890             if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 22891             if (cont) {
 22892               _cimg_draw_fill_set(xc,nyc,zc);
 22893               _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 22894               _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 22895               _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 22896               _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 22898           } while (cont);
 22899         } while (posr1>posr0);
 22900         else do { // 2D version of the filling algorithm
 22901           const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
 22902           if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 22903           bool cont, res;
 22904           unsigned int nxc = xc;
 22905           do { // X-backward
 22906             _cimg_draw_fill_set(nxc,yc,0);
 22907             _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 22908             _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 22909             if (high_connexity) {
 22910               _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 22911               _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 22912               _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 22913               _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 22915             if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 22916           } while (cont);
 22917           nxc = xc;
 22918           do { // X-forward
 22919             if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 22920             if (cont) {
 22921               _cimg_draw_fill_set(nxc,yc,0);
 22922               _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 22923               _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 22924               if (high_connexity) {
 22925                 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 22926                 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 22927                 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 22928                 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 22931           } while (cont);
 22932           unsigned int nyc = yc;
 22933           do { // Y-backward
 22934             if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 22935             if (cont) {
 22936               _cimg_draw_fill_set(xc,nyc,0);
 22937               _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 22938               _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 22939               if (high_connexity) {
 22940                 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 22941                 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 22942                 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 22943                 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 22946           } while (cont);
 22947           nyc = yc;
 22948           do { // Y-forward
 22949             if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 22950             if (cont) {
 22951               _cimg_draw_fill_set(xc,nyc,0);
 22952               _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 22953               _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 22954               if (high_connexity) {
 22955                 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 22956                 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 22957                 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 22958                 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 22961           } while (cont);
 22962         } while (posr1>posr0);
 22963         if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
 22965       return *this;
 22968     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 22969     template<typename tc, typename t>
 22970     CImg<T>& draw_fill(const int x, const int y, const int z,
 22971                        const CImg<tc>& color, const float opacity,
 22972                        CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
 22973       return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
 22976     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 22977     /**
 22978        \param x = X-coordinate of the starting point of the region to fill.
 22979        \param y = Y-coordinate of the starting point of the region to fill.
 22980        \param z = Z-coordinate of the starting point of the region to fill.
 22981        \param color = an array of dimv() values of type \c T, defining the drawing color.
 22982        \param sigma = tolerance concerning neighborhood values.
 22983        \param opacity = opacity of the drawing.
 22984     **/
 22985     template<typename tc>
 22986     CImg<T>& draw_fill(const int x, const int y, const int z,
 22987                        const tc *const color, const float opacity=1,
 22988                        const float sigma=0, const bool high_connexity=false) {
 22989       CImg<boolT> tmp;
 22990       return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
 22993     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 22994     template<typename tc>
 22995     CImg<T>& draw_fill(const int x, const int y, const int z,
 22996                        const CImg<tc>& color, const float opacity=1,
 22997                        const float sigma=0, const bool high_connexity=false) {
 22998       return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
 23001     //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
 23002     /**
 23003        \param x = X-coordinate of the starting point of the region to fill.
 23004        \param y = Y-coordinate of the starting point of the region to fill.
 23005        \param color = an array of dimv() values of type \c T, defining the drawing color.
 23006        \param sigma = tolerance concerning neighborhood values.
 23007        \param opacity = opacity of the drawing.
 23008     **/
 23009     template<typename tc>
 23010     CImg<T>& draw_fill(const int x, const int y,
 23011                        const tc *const color, const float opacity=1,
 23012                        const float sigma=0, const bool high_connexity=false) {
 23013       CImg<boolT> tmp;
 23014       return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
 23017     //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
 23018     template<typename tc>
 23019     CImg<T>& draw_fill(const int x, const int y,
 23020                        const CImg<tc>& color, const float opacity=1,
 23021                        const float sigma=0, const bool high_connexity=false) {
 23022       return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
 23025     //! Draw a plasma random texture.
 23026     /**
 23027        \param x0 = X-coordinate of the upper-left corner of the plasma.
 23028        \param y0 = Y-coordinate of the upper-left corner of the plasma.
 23029        \param x1 = X-coordinate of the lower-right corner of the plasma.
 23030        \param y1 = Y-coordinate of the lower-right corner of the plasma.
 23031        \param alpha = Alpha-parameter of the plasma.
 23032        \param beta = Beta-parameter of the plasma.
 23033        \param opacity = opacity of the drawing.
 23034     **/
 23035     CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
 23036                          const float alpha=1, const float beta=1,
 23037                          const float opacity=1) {
 23038       if (!is_empty()) {
 23039         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 23040         int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
 23041         if (nx1<nx0) cimg::swap(nx0,nx1);
 23042         if (ny1<ny0) cimg::swap(ny0,ny1);
 23043         if (nx0<0) nx0 = 0;
 23044         if (nx1>=dimx()) nx1 = width-1;
 23045         if (ny0<0) ny0 = 0;
 23046         if (ny1>=dimy()) ny1 = height-1;
 23047         const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
 23048         const Tfloat dc = (Tfloat)(cimg_std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
 23049         Tfloat val = 0;
 23050         cimg_forV(*this,k) {
 23051           if (opacity>=1) {
 23052             const Tfloat
 23053               val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
 23054               val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
 23055             (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
 23056             (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
 23057             (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
 23058             (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
 23059             do {
 23060               val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
 23061                                    (Tfloat)((*this)(nx1,ny0,0,k)) +
 23062                                    (Tfloat)((*this)(nx1,ny1,0,k)) +
 23063                                    (Tfloat)((*this)(nx0,ny1,0,k))) +
 23064                             dc*cimg::grand());
 23065             } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
 23066             (*this)(xc,yc,0,k) = (T)val;
 23067           } else {
 23068             const Tfloat
 23069               val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
 23070               val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
 23071             (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
 23072             (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
 23073             (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
 23074             (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
 23075             do {
 23076               val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
 23077                                     (Tfloat)((*this)(nx1,ny0,0,k)) +
 23078                                     (Tfloat)((*this)(nx1,ny1,0,k)) +
 23079                                     (Tfloat)((*this)(nx0,ny1,0,k))) +
 23080                                    dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
 23081             } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
 23082             (*this)(xc,yc,0,k) = (T)val;
 23085         if (xc!=nx0 || yc!=ny0) {
 23086           draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
 23087           draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
 23088           draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
 23089           draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
 23092       return *this;
 23095     //! Draw a plasma random texture.
 23096     /**
 23097        \param alpha = Alpha-parameter of the plasma.
 23098        \param beta = Beta-parameter of the plasma.
 23099        \param opacity = opacity of the drawing.
 23100     **/
 23101     CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
 23102                          const float opacity=1) {
 23103       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
 23106     //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 23107     template<typename tc>
 23108     CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
 23109                              const CImg<tc>& color_palette, const float opacity=1,
 23110                              const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 23111                              const unsigned int itermax=255,
 23112                              const bool normalized_iteration=false,
 23113                              const bool julia_set=false,
 23114                              const double paramr=0, const double parami=0) {
 23115       if (is_empty()) return *this;
 23116       CImg<tc> palette;
 23117       if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
 23118       if (palette && palette.dim!=dim)
 23119         throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
 23120                                     "compatible with instance image (%u,%u,%u,%u,%p).",
 23121                                     pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
 23122                                     color_palette.data,width,height,depth,dim,data);
 23123       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)cimg_std::log(2.0);
 23124       unsigned int iter = 0;
 23125       cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 23126         const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
 23127         double zr, zi, cr, ci;
 23128         if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
 23129         else { zr = paramr; zi = parami; cr = x; ci = y; }
 23130         for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
 23131           const double temp = zr*zr - zi*zi + cr;
 23132           zi = 2*zr*zi + ci;
 23133           zr = temp;
 23135         if (iter>itermax) {
 23136           if (palette) {
 23137             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
 23138             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
 23139           } else {
 23140             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
 23141             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
 23143         } else if (normalized_iteration) {
 23144           const float
 23145             normz = (float)cimg::abs(zr*zr+zi*zi),
 23146             niter = (float)(iter + 1 - cimg_std::log(cimg_std::log(normz))/ln2);
 23147           if (palette) {
 23148             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
 23149             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 23150           } else {
 23151             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
 23152             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
 23154         } else {
 23155           if (palette) {
 23156             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
 23157             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 23158           } else {
 23159             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
 23160             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
 23164       return *this;
 23167     //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 23168     template<typename tc>
 23169     CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
 23170                              const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 23171                              const unsigned int itermax=255,
 23172                              const bool normalized_iteration=false,
 23173                              const bool julia_set=false,
 23174                              const double paramr=0, const double parami=0) {
 23175       return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
 23178     //! Draw a 1D gaussian function in the instance image.
 23179     /**
 23180        \param xc = X-coordinate of the gaussian center.
 23181        \param sigma = Standard variation of the gaussian distribution.
 23182        \param color = array of dimv() values of type \c T, defining the drawing color.
 23183        \param opacity = opacity of the drawing.
 23184     **/
 23185     template<typename tc>
 23186     CImg<T>& draw_gaussian(const float xc, const float sigma,
 23187                            const tc *const color, const float opacity=1) {
 23188       if (is_empty()) return *this;
 23189       if (!color)
 23190         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
 23191                                     pixel_type());
 23192       const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 23193       const unsigned int whz = width*height*depth;
 23194       const tc *col = color;
 23195       cimg_forX(*this,x) {
 23196         const float dx = (x - xc), val = (float)cimg_std::exp(-dx*dx/sigma2);
 23197         T *ptrd = ptr(x,0,0,0);
 23198         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 23199         else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 23200         col-=dim;
 23202       return *this;
 23205     //! Draw a 1D gaussian function in the instance image.
 23206     template<typename tc>
 23207     CImg<T>& draw_gaussian(const float xc, const float sigma,
 23208                            const CImg<tc>& color, const float opacity=1) {
 23209       return draw_gaussian(xc,sigma,color.data,opacity);
 23212     //! Draw an anisotropic 2D gaussian function.
 23213     /**
 23214        \param xc = X-coordinate of the gaussian center.
 23215        \param yc = Y-coordinate of the gaussian center.
 23216        \param tensor = 2x2 covariance matrix.
 23217        \param color = array of dimv() values of type \c T, defining the drawing color.
 23218        \param opacity = opacity of the drawing.
 23219     **/
 23220     template<typename t, typename tc>
 23221     CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 23222                            const tc *const color, const float opacity=1) {
 23223       if (is_empty()) return *this;
 23224       typedef typename cimg::superset<t,float>::type tfloat;
 23225       if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
 23226         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
 23227                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
 23228       if (!color)
 23229         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
 23230                                     pixel_type());
 23231       const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
 23232       const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
 23233       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 23234       const unsigned int whz = width*height*depth;
 23235       const tc *col = color;
 23236       float dy = -yc;
 23237       cimg_forY(*this,y) {
 23238         float dx = -xc;
 23239         cimg_forX(*this,x) {
 23240           const float val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
 23241           T *ptrd = ptr(x,y,0,0);
 23242           if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 23243           else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 23244           col-=dim;
 23245           ++dx;
 23247         ++dy;
 23249       return *this;
 23252     //! Draw an anisotropic 2D gaussian function.
 23253     template<typename t, typename tc>
 23254     CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 23255                            const CImg<tc>& color, const float opacity=1) {
 23256       return draw_gaussian(xc,yc,tensor,color.data,opacity);
 23259     //! Draw an anisotropic 2D gaussian function.
 23260     template<typename tc>
 23261     CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
 23262                            const tc *const color, const float opacity=1) {
 23263       const double
 23264         a = r1*ru*ru + r2*rv*rv,
 23265         b = (r1-r2)*ru*rv,
 23266         c = r1*rv*rv + r2*ru*ru;
 23267       const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
 23268       return draw_gaussian(xc,yc,tensor,color,opacity);
 23271     //! Draw an anisotropic 2D gaussian function.
 23272     template<typename tc>
 23273     CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
 23274                            const CImg<tc>& color, const float opacity=1) {
 23275       return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
 23278     //! Draw an isotropic 2D gaussian function.
 23279     /**
 23280        \param xc = X-coordinate of the gaussian center.
 23281        \param yc = Y-coordinate of the gaussian center.
 23282        \param sigma = standard variation of the gaussian distribution.
 23283        \param color = array of dimv() values of type \c T, defining the drawing color.
 23284        \param opacity = opacity of the drawing.
 23285     **/
 23286     template<typename tc>
 23287     CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
 23288                            const tc *const color, const float opacity=1) {
 23289       return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
 23292     //! Draw an isotropic 2D gaussian function.
 23293     template<typename tc>
 23294     CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
 23295                            const CImg<tc>& color, const float opacity=1) {
 23296       return draw_gaussian(xc,yc,sigma,color.data,opacity);
 23299     //! Draw an anisotropic 3D gaussian function.
 23300     /**
 23301        \param xc = X-coordinate of the gaussian center.
 23302        \param yc = Y-coordinate of the gaussian center.
 23303        \param zc = Z-coordinate of the gaussian center.
 23304        \param tensor = 3x3 covariance matrix.
 23305        \param color = array of dimv() values of type \c T, defining the drawing color.
 23306        \param opacity = opacity of the drawing.
 23307     **/
 23308     template<typename t, typename tc>
 23309     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 23310                            const tc *const color, const float opacity=1) {
 23311       if (is_empty()) return *this;
 23312       typedef typename cimg::superset<t,float>::type tfloat;
 23313       if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
 23314         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
 23315                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
 23316       const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
 23317       const tfloat 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);
 23318       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 23319       const unsigned int whz = width*height*depth;
 23320       const tc *col = color;
 23321       cimg_forXYZ(*this,x,y,z) {
 23322         const float
 23323           dx = (x - xc), dy = (y - yc), dz = (z - zc),
 23324           val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
 23325         T *ptrd = ptr(x,y,z,0);
 23326         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 23327         else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 23328         col-=dim;
 23330       return *this;
 23333     //! Draw an anisotropic 3D gaussian function.
 23334     template<typename t, typename tc>
 23335     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 23336                            const CImg<tc>& color, const float opacity=1) {
 23337       return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
 23340     //! Draw an isotropic 3D gaussian function.
 23341    /**
 23342        \param xc = X-coordinate of the gaussian center.
 23343        \param yc = Y-coordinate of the gaussian center.
 23344        \param zc = Z-coordinate of the gaussian center.
 23345        \param sigma = standard variation of the gaussian distribution.
 23346        \param color = array of dimv() values of type \c T, defining the drawing color.
 23347        \param opacity = opacity of the drawing.
 23348     **/
 23349     template<typename tc>
 23350     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
 23351                            const tc *const color, const float opacity=1) {
 23352       return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
 23355     //! Draw an isotropic 3D gaussian function.
 23356     template<typename tc>
 23357     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
 23358                            const CImg<tc>& color, const float opacity=1) {
 23359       return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
 23362     // Draw a 3D object (internal)
 23363     template<typename tc, typename to>
 23364     void _draw_object3d_sprite(const int x, const int y,
 23365                                const CImg<tc>& color, const CImg<to>& opacity, const CImg<T>& sprite) {
 23366       if (opacity.width==color.width && opacity.height==color.height)
 23367         draw_image(x,y,sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1));
 23368       else
 23369         draw_image(x,y,sprite,opacity(0));
 23372     template<typename tc>
 23373     void _draw_object3d_sprite(const int x, const int y,
 23374                                const CImg<tc>& color, const float opacity, const CImg<T>& sprite) {
 23375       if (color) draw_image(x,y,sprite,opacity);
 23378     template<typename tp, typename tf, typename tc, typename to>
 23379     CImg<T>& _draw_object3d(void *const pboard, float *const zbuffer,
 23380                             const float X, const float Y, const float Z,
 23381                             const tp& points, const unsigned int nb_points,
 23382                             const CImgList<tf>& primitives,
 23383                             const CImgList<tc>& colors,
 23384                             const to& opacities, const unsigned int nb_opacities,
 23385                             const unsigned int render_type,
 23386                             const bool double_sided, const float focale,
 23387                             const float lightx, const float lighty, const float lightz,
 23388                             const float specular_light, const float specular_shine) {
 23389       if (is_empty()) return *this;
 23390 #ifndef cimg_use_board
 23391       if (pboard) return *this;
 23392 #endif
 23393       const float
 23394         nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
 23395         nspec2 = 1+(specular_shine<0?0:specular_shine),
 23396         nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
 23397         nsl2 = (1-2*nsl1*nspec),
 23398         nsl3 = nspec2-nsl1-nsl2;
 23400       // Create light texture for phong-like rendering
 23401       static CImg<floatT> light_texture;
 23402       if (render_type==5) {
 23403         if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
 23404         else {
 23405           static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
 23406           if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
 23407             light_texture.assign(512,512);
 23408             const float white[] = { 1 },
 23409               dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
 23410                 nl = (float)cimg_std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
 23411                 nlx = light_texture.width/2*(1+dlx/nl),
 23412                 nly = light_texture.height/2*(1+dly/nl);
 23413               light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
 23414               cimg_forXY(light_texture,x,y) {
 23415                 const float factor = light_texture(x,y);
 23416                 if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
 23418               olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
 23423       // Compute 3D to 2D projection
 23424       CImg<floatT> projections(nb_points,2);
 23425       cimg_forX(projections,l) {
 23426         const float
 23427           x = (float)points(l,0),
 23428           y = (float)points(l,1),
 23429           z = (float)points(l,2);
 23430         const float projectedz = z + Z + focale;
 23431         projections(l,1) = Y + focale*y/projectedz;
 23432         projections(l,0) = X + focale*x/projectedz;
 23435       // Compute and sort visible primitives
 23436       CImg<uintT> visibles(primitives.size);
 23437       CImg<floatT> zrange(primitives.size);
 23438       unsigned int nb_visibles = 0;
 23439       const float zmin = -focale+1.5f;
 23440       { cimglist_for(primitives,l) {
 23441         const CImg<tf>& primitive = primitives[l];
 23442         switch (primitive.size()) {
 23444         case 1 : { // Point
 23445           const unsigned int i0 = (unsigned int)primitive(0);
 23446           const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
 23447           if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
 23448             visibles(nb_visibles) = (unsigned int)l;
 23449             zrange(nb_visibles++) = z0;
 23451         } break;
 23452         case 5 : { // Sphere
 23453           const unsigned int
 23454             i0 = (unsigned int)primitive(0),
 23455             i1 = (unsigned int)primitive(1),
 23456             i2 = (unsigned int)primitive(2);
 23457           const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
 23458           int radius;
 23459           if (i2) radius = (int)(i2*focale/(z0+focale));
 23460           else {
 23461             const float x1 = projections(i1,0), y1 = projections(i1,1);
 23462             const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
 23463             radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
 23465           if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
 23466             visibles(nb_visibles) = (unsigned int)l;
 23467             zrange(nb_visibles++) = z0;
 23469         } break;
 23470         case 2 : // Line
 23471         case 6 : {
 23472           const unsigned int
 23473             i0 = (unsigned int)primitive(0),
 23474             i1 = (unsigned int)primitive(1);
 23475           const float
 23476             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 23477             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2));
 23478           float xm, xM, ym, yM;
 23479           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 23480           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 23481           if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 23482             visibles(nb_visibles) = (unsigned int)l;
 23483             zrange(nb_visibles++) = 0.5f*(z0+z1);
 23485         } break;
 23486         case 3 :  // Triangle
 23487         case 9 : {
 23488           const unsigned int
 23489             i0 = (unsigned int)primitive(0),
 23490             i1 = (unsigned int)primitive(1),
 23491             i2 = (unsigned int)primitive(2);
 23492           const float
 23493             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 23494             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
 23495             x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2));
 23496           float xm, xM, ym, yM;
 23497           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 23498           if (x2<xm) xm = x2;
 23499           if (x2>xM) xM = x2;
 23500           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 23501           if (y2<ym) ym = y2;
 23502           if (y2>yM) yM = y2;
 23503           if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 23504             const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
 23505             if (double_sided || d<0) {
 23506               visibles(nb_visibles) = (unsigned int)l;
 23507               zrange(nb_visibles++) = (z0+z1+z2)/3;
 23510         } break;
 23511         case 4 : // Rectangle
 23512         case 12 : {
 23513           const unsigned int
 23514             i0 = (unsigned int)primitive(0),
 23515             i1 = (unsigned int)primitive(1),
 23516             i2 = (unsigned int)primitive(2),
 23517             i3 = (unsigned int)primitive(3);
 23518           const float
 23519             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 23520             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
 23521             x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)),
 23522             x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2));
 23523           float xm, xM, ym, yM;
 23524           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 23525           if (x2<xm) xm = x2;
 23526           if (x2>xM) xM = x2;
 23527           if (x3<xm) xm = x3;
 23528           if (x3>xM) xM = x3;
 23529           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 23530           if (y2<ym) ym = y2;
 23531           if (y2>yM) yM = y2;
 23532           if (y3<ym) ym = y3;
 23533           if (y3>yM) yM = y3;
 23534           if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 23535             const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
 23536             if (double_sided || d<0) {
 23537               visibles(nb_visibles) = (unsigned int)l;
 23538               zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
 23541         } break;
 23542         default :
 23543           throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
 23544                                       pixel_type(),l,primitive.size());
 23545         }}
 23547       if (nb_visibles<=0) return *this;
 23548       CImg<uintT> permutations;
 23549       CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
 23551       // Compute light properties
 23552       CImg<floatT> lightprops;
 23553       switch (render_type) {
 23554       case 3 : { // Flat Shading
 23555         lightprops.assign(nb_visibles);
 23556         cimg_forX(lightprops,l) {
 23557           const CImg<tf>& primitive = primitives(visibles(permutations(l)));
 23558           const unsigned int psize = primitive.size();
 23559           if (psize==3 || psize==4 || psize==9 || psize==12) {
 23560             const unsigned int
 23561               i0 = (unsigned int)primitive(0),
 23562               i1 = (unsigned int)primitive(1),
 23563               i2 = (unsigned int)primitive(2);
 23564             const float
 23565               x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
 23566               x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
 23567               x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
 23568               dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
 23569               dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
 23570               nx = dy1*dz2 - dz1*dy2,
 23571               ny = dz1*dx2 - dx1*dz2,
 23572               nz = dx1*dy2 - dy1*dx2,
 23573               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 23574               lx = X + (x0 + x1 + x2)/3 - lightx,
 23575               ly = Y + (y0 + y1 + y2)/3 - lighty,
 23576               lz = Z + (z0 + z1 + z2)/3 - lightz,
 23577               nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
 23578               factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
 23579             lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
 23580           } else lightprops[l] = 1;
 23582       } break;
 23584       case 4 : // Gouraud Shading
 23585       case 5 : { // Phong-Shading
 23586         CImg<floatT> points_normals(nb_points,3,1,1,0);
 23587         for (unsigned int l=0; l<nb_visibles; ++l) {
 23588           const CImg<tf>& primitive = primitives[visibles(l)];
 23589           const unsigned int psize = primitive.size();
 23590           const bool
 23591             triangle_flag = (psize==3) || (psize==9),
 23592             rectangle_flag = (psize==4) || (psize==12);
 23593           if (triangle_flag || rectangle_flag) {
 23594             const unsigned int
 23595               i0 = (unsigned int)primitive(0),
 23596               i1 = (unsigned int)primitive(1),
 23597               i2 = (unsigned int)primitive(2),
 23598               i3 = rectangle_flag?(unsigned int)primitive(3):0;
 23599             const float
 23600               x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
 23601               x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
 23602               x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
 23603               dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
 23604               dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
 23605               nnx = dy1*dz2 - dz1*dy2,
 23606               nny = dz1*dx2 - dx1*dz2,
 23607               nnz = dx1*dy2 - dy1*dx2,
 23608               norm = 1e-5f + (float)cimg_std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
 23609               nx = nnx/norm,
 23610               ny = nny/norm,
 23611               nz = nnz/norm;
 23612             points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
 23613             points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
 23614             points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
 23615             if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
 23619         if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
 23620           points_normals(p,0) = -points_normals(p,0);
 23621           points_normals(p,1) = -points_normals(p,1);
 23622           points_normals(p,2) = -points_normals(p,2);
 23625         if (render_type==4) {
 23626           lightprops.assign(nb_points);
 23627           cimg_forX(lightprops,ll) {
 23628             const float
 23629               nx = points_normals(ll,0),
 23630               ny = points_normals(ll,1),
 23631               nz = points_normals(ll,2),
 23632               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 23633               lx = (float)(X + points(ll,0) - lightx),
 23634               ly = (float)(Y + points(ll,1) - lighty),
 23635               lz = (float)(Z + points(ll,2) - lightz),
 23636               nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
 23637               factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
 23638             lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
 23640         } else {
 23641           const unsigned int
 23642             lw2 = light_texture.width/2 - 1,
 23643             lh2 = light_texture.height/2 - 1;
 23644           lightprops.assign(nb_points,2);
 23645           cimg_forX(lightprops,ll) {
 23646             const float
 23647               nx = points_normals(ll,0),
 23648               ny = points_normals(ll,1),
 23649               nz = points_normals(ll,2),
 23650               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 23651               nnx = nx/norm,
 23652               nny = ny/norm;
 23653             lightprops(ll,0) = lw2*(1 + nnx);
 23654             lightprops(ll,1) = lh2*(1 + nny);
 23657       } break;
 23660       // Draw visible primitives
 23661       const CImg<tc> default_color(1,dim,1,1,(tc)200);
 23662       { for (unsigned int l = 0; l<nb_visibles; ++l) {
 23663         const unsigned int n_primitive = visibles(permutations(l));
 23664         const CImg<tf>& primitive = primitives[n_primitive];
 23665         const CImg<tc>& color = n_primitive<colors.size?colors[n_primitive]:default_color;
 23666         const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
 23667 #ifdef cimg_use_board
 23668         BoardLib::Board &board = *(BoardLib::Board*)pboard;
 23669 #endif
 23671         switch (primitive.size()) {
 23672         case 1 : { // Colored point or sprite
 23673           const unsigned int n0 = (unsigned int)primitive[0];
 23674           const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
 23675           if (color.size()==dim) {
 23676             draw_point(x0,y0,color,opac);
 23677 #ifdef cimg_use_board
 23678             if (pboard) {
 23679               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23680               board.fillCircle((float)x0,dimy()-(float)y0,0);
 23682 #endif
 23683           } else {
 23684             const float z = Z + points(n0,2);
 23685             const int
 23686               factor = (int)(focale*100/(z+focale)),
 23687               sw = color.width*factor/200,
 23688               sh = color.height*factor/200;
 23689             if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
 23690               const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
 23691               _draw_object3d_sprite(x0-sw,y0-sh,color,opacities[n_primitive%nb_opacities],sprite);
 23692 #ifdef cimg_use_board
 23693                 if (pboard) {
 23694                   board.setPenColorRGBi(128,128,128);
 23695                   board.setFillColor(BoardLib::Color::none);
 23696                   board.drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
 23698 #endif
 23701         } break;
 23702         case 2 : { // Colored line
 23703           const unsigned int
 23704             n0 = (unsigned int)primitive[0],
 23705             n1 = (unsigned int)primitive[1];
 23706           const int
 23707             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 23708             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
 23709           const float
 23710             z0 = points(n0,2) + Z + focale,
 23711             z1 = points(n1,2) + Z + focale;
 23712           if (render_type) {
 23713             if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
 23714             else draw_line(x0,y0,x1,y1,color,opac);
 23715 #ifdef cimg_use_board
 23716             if (pboard) {
 23717               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23718               board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
 23720 #endif
 23721           } else {
 23722             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
 23723 #ifdef cimg_use_board
 23724             if (pboard) {
 23725               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23726               board.drawCircle((float)x0,dimy()-(float)y0,0);
 23727               board.drawCircle((float)x1,dimy()-(float)y1,0);
 23729 #endif
 23731         } break;
 23732         case 5 : { // Colored sphere
 23733           const unsigned int
 23734             n0 = (unsigned int)primitive[0],
 23735             n1 = (unsigned int)primitive[1],
 23736             n2 = (unsigned int)primitive[2];
 23737           const int
 23738             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
 23739           int radius;
 23740           if (n2) radius = (int)(n2*focale/(Z+points(n0,2)+focale));
 23741           else {
 23742             const int
 23743               x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 23744               deltax = x1-x0, deltay = y1-y0;
 23745             radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
 23747           switch (render_type) {
 23748           case 0 :
 23749             draw_point(x0,y0,color,opac);
 23750 #ifdef cimg_use_board
 23751             if (pboard) {
 23752               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23753               board.fillCircle((float)x0,dimy()-(float)y0,0);
 23755 #endif
 23756             break;
 23757           case 1 :
 23758             draw_circle(x0,y0,radius,color,opac,~0U);
 23759 #ifdef cimg_use_board
 23760             if (pboard) {
 23761               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23762               board.setFillColor(BoardLib::Color::none);
 23763               board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
 23765 #endif
 23766             break;
 23767           default :
 23768             draw_circle(x0,y0,radius,color,opac);
 23769 #ifdef cimg_use_board
 23770             if (pboard) {
 23771               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23772               board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
 23774 #endif
 23775             break;
 23777         } break;
 23778         case 6 : { // Textured line
 23779           const unsigned int
 23780             n0 = (unsigned int)primitive[0],
 23781             n1 = (unsigned int)primitive[1],
 23782             tx0 = (unsigned int)primitive[2],
 23783             ty0 = (unsigned int)primitive[3],
 23784             tx1 = (unsigned int)primitive[4],
 23785             ty1 = (unsigned int)primitive[5];
 23786           const int
 23787             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 23788             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
 23789           const float
 23790             z0 = points(n0,2) + Z + focale,
 23791             z1 = points(n1,2) + Z + focale;
 23792           if (render_type) {
 23793             if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
 23794             else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
 23795 #ifdef cimg_use_board
 23796             if (pboard) {
 23797               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 23798               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 23800 #endif
 23801           } else {
 23802             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 23803               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
 23804 #ifdef cimg_use_board
 23805             if (pboard) {
 23806               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 23807               board.drawCircle((float)x0,dimy()-(float)y0,0);
 23808               board.drawCircle((float)x1,dimy()-(float)y1,0);
 23810 #endif
 23812         } break;
 23813         case 3 : { // Colored triangle
 23814           const unsigned int
 23815             n0 = (unsigned int)primitive[0],
 23816             n1 = (unsigned int)primitive[1],
 23817             n2 = (unsigned int)primitive[2];
 23818           const int
 23819             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 23820             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 23821             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
 23822           const float
 23823             z0 = points(n0,2) + Z + focale,
 23824             z1 = points(n1,2) + Z + focale,
 23825             z2 = points(n2,2) + Z + focale;
 23826           switch (render_type) {
 23827           case 0 :
 23828             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
 23829 #ifdef cimg_use_board
 23830             if (pboard) {
 23831               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23832               board.drawCircle((float)x0,dimy()-(float)y0,0);
 23833               board.drawCircle((float)x1,dimy()-(float)y1,0);
 23834               board.drawCircle((float)x2,dimy()-(float)y2,0);
 23836 #endif
 23837             break;
 23838           case 1 :
 23839             if (zbuffer)
 23840               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
 23841                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
 23842             else
 23843               draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
 23844                 draw_line(x1,y1,x2,y2,color,opac);
 23845 #ifdef cimg_use_board
 23846             if (pboard) {
 23847               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23848               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 23849               board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 23850               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23852 #endif
 23853             break;
 23854           case 2 :
 23855             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
 23856             else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
 23857 #ifdef cimg_use_board
 23858             if (pboard) {
 23859               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23860               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23862 #endif
 23863             break;
 23864           case 3 :
 23865             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
 23866             else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
 23867 #ifdef cimg_use_board
 23868             if (pboard) {
 23869               const float lp = cimg::min(lightprops(l),1);
 23870               board.setPenColorRGBi((unsigned char)(color[0]*lp),
 23871                                      (unsigned char)(color[1]*lp),
 23872                                      (unsigned char)(color[2]*lp),
 23873                                      (unsigned char)(opac*255));
 23874               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23876 #endif
 23877             break;
 23878           case 4 :
 23879             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 23880             else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 23881 #ifdef cimg_use_board
 23882             if (pboard) {
 23883               board.setPenColorRGBi((unsigned char)(color[0]),
 23884                                      (unsigned char)(color[1]),
 23885                                      (unsigned char)(color[2]),
 23886                                      (unsigned char)(opac*255));
 23887               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 23888                                          (float)x1,dimy()-(float)y1,lightprops(n1),
 23889                                          (float)x2,dimy()-(float)y2,lightprops(n2));
 23891 #endif
 23892             break;
 23893           case 5 : {
 23894             const unsigned int
 23895               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 23896               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 23897               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
 23898             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
 23899             else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
 23900 #ifdef cimg_use_board
 23901             if (pboard) {
 23902               const float
 23903                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 23904                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 23905                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 23906               board.setPenColorRGBi((unsigned char)(color[0]),
 23907                                      (unsigned char)(color[1]),
 23908                                      (unsigned char)(color[2]),
 23909                                      (unsigned char)(opac*255));
 23910               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 23911                                          (float)x1,dimy()-(float)y1,l1,
 23912                                          (float)x2,dimy()-(float)y2,l2);
 23914 #endif
 23915           } break;
 23917         } break;
 23918         case 4 : { // Colored rectangle
 23919           const unsigned int
 23920             n0 = (unsigned int)primitive[0],
 23921             n1 = (unsigned int)primitive[1],
 23922             n2 = (unsigned int)primitive[2],
 23923             n3 = (unsigned int)primitive[3];
 23924           const int
 23925             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 23926             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 23927             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
 23928             x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
 23929           const float
 23930             z0 = points(n0,2) + Z + focale,
 23931             z1 = points(n1,2) + Z + focale,
 23932             z2 = points(n2,2) + Z + focale,
 23933             z3 = points(n3,2) + Z + focale;
 23934           switch (render_type) {
 23935           case 0 :
 23936             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
 23937               draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
 23938 #ifdef cimg_use_board
 23939             if (pboard) {
 23940               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23941               board.drawCircle((float)x0,dimy()-(float)y0,0);
 23942               board.drawCircle((float)x1,dimy()-(float)y1,0);
 23943               board.drawCircle((float)x2,dimy()-(float)y2,0);
 23944               board.drawCircle((float)x3,dimy()-(float)y3,0);
 23946 #endif
 23947             break;
 23948           case 1 :
 23949             if (zbuffer)
 23950               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
 23951                 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
 23952             else
 23953               draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
 23954                 draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
 23955 #ifdef cimg_use_board
 23956             if (pboard) {
 23957               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23958               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 23959               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23960               board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 23961               board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 23963 #endif
 23964             break;
 23965           case 2 :
 23966             if (zbuffer)
 23967               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac).draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,opac);
 23968             else
 23969               draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
 23970 #ifdef cimg_use_board
 23971             if (pboard) {
 23972               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 23973               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23974               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 23976 #endif
 23977             break;
 23978           case 3 :
 23979             if (zbuffer)
 23980               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
 23981                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
 23982             else
 23983               _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
 23984                 _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
 23985 #ifdef cimg_use_board
 23986             if (pboard) {
 23987               const float lp = cimg::min(lightprops(l),1);
 23988               board.setPenColorRGBi((unsigned char)(color[0]*lp),
 23989                                      (unsigned char)(color[1]*lp),
 23990                                      (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
 23991               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 23992               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 23994 #endif
 23995             break;
 23996           case 4 : {
 23997             const float
 23998               lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
 23999               lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
 24000             if (zbuffer)
 24001               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
 24002                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
 24003             else
 24004               draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
 24005                 draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
 24006 #ifdef cimg_use_board
 24007             if (pboard) {
 24008               board.setPenColorRGBi((unsigned char)(color[0]),
 24009                                      (unsigned char)(color[1]),
 24010                                      (unsigned char)(color[2]),
 24011                                      (unsigned char)(opac*255));
 24012               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 24013                                          (float)x1,dimy()-(float)y1,lightprop1,
 24014                                          (float)x2,dimy()-(float)y2,lightprop2);
 24015               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 24016                                          (float)x2,dimy()-(float)y2,lightprop2,
 24017                                          (float)x3,dimy()-(float)y3,lightprop3);
 24019 #endif
 24020           } break;
 24021           case 5 : {
 24022             const unsigned int
 24023               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 24024               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 24025               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
 24026               lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
 24027             if (zbuffer)
 24028               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 24029                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 24030             else
 24031               draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 24032                 draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 24033 #ifdef cimg_use_board
 24034             if (pboard) {
 24035               const float
 24036                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 24037                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 24038                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 24039                 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 24040               board.setPenColorRGBi((unsigned char)(color[0]),
 24041                                      (unsigned char)(color[1]),
 24042                                      (unsigned char)(color[2]),
 24043                                      (unsigned char)(opac*255));
 24044               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 24045                                          (float)x1,dimy()-(float)y1,l1,
 24046                                          (float)x2,dimy()-(float)y2,l2);
 24047               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 24048                                          (float)x2,dimy()-(float)y2,l2,
 24049                                          (float)x3,dimy()-(float)y3,l3);
 24051 #endif
 24052           } break;
 24054         } break;
 24055         case 9 : { // Textured triangle
 24056           const unsigned int
 24057             n0 = (unsigned int)primitive[0],
 24058             n1 = (unsigned int)primitive[1],
 24059             n2 = (unsigned int)primitive[2],
 24060             tx0 = (unsigned int)primitive[3],
 24061             ty0 = (unsigned int)primitive[4],
 24062             tx1 = (unsigned int)primitive[5],
 24063             ty1 = (unsigned int)primitive[6],
 24064             tx2 = (unsigned int)primitive[7],
 24065             ty2 = (unsigned int)primitive[8];
 24066           const int
 24067             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 24068             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 24069             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
 24070           const float
 24071             z0 = points(n0,2) + Z + focale,
 24072             z1 = points(n1,2) + Z + focale,
 24073             z2 = points(n2,2) + Z + focale;
 24074           switch (render_type) {
 24075           case 0 :
 24076             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 24077               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 24078               draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
 24079 #ifdef cimg_use_board
 24080             if (pboard) {
 24081               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24082               board.drawCircle((float)x0,dimy()-(float)y0,0);
 24083               board.drawCircle((float)x1,dimy()-(float)y1,0);
 24084               board.drawCircle((float)x2,dimy()-(float)y2,0);
 24086 #endif
 24087             break;
 24088           case 1 :
 24089             if (zbuffer)
 24090               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 24091                 draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
 24092                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
 24093             else
 24094               draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 24095                 draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
 24096                 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
 24097 #ifdef cimg_use_board
 24098             if (pboard) {
 24099               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24100               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 24101               board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 24102               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24104 #endif
 24105             break;
 24106           case 2 :
 24107             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
 24108             else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
 24109 #ifdef cimg_use_board
 24110             if (pboard) {
 24111               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24112               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24114 #endif
 24115             break;
 24116           case 3 :
 24117             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
 24118             else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
 24119 #ifdef cimg_use_board
 24120             if (pboard) {
 24121               const float lp = cimg::min(lightprops(l),1);
 24122               board.setPenColorRGBi((unsigned char)(128*lp),
 24123                                      (unsigned char)(128*lp),
 24124                                      (unsigned char)(128*lp),
 24125                                      (unsigned char)(opac*255));
 24126               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24128 #endif
 24129             break;
 24130           case 4 :
 24131             if (zbuffer)
 24132               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 24133             else
 24134               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 24135 #ifdef cimg_use_board
 24136             if (pboard) {
 24137               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24138               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 24139                                          (float)x1,dimy()-(float)y1,lightprops(n1),
 24140                                          (float)x2,dimy()-(float)y2,lightprops(n2));
 24142 #endif
 24143             break;
 24144           case 5 :
 24145             if (zbuffer)
 24146               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
 24147                             (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
 24148                             (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
 24149                             (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
 24150                             opac);
 24151             else
 24152               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
 24153                             (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
 24154                             (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
 24155                             (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
 24156                             opac);
 24157 #ifdef cimg_use_board
 24158             if (pboard) {
 24159               const float
 24160                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 24161                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 24162                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 24163               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24164               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
 24166 #endif
 24167             break;
 24169         } break;
 24170         case 12 : { // Textured rectangle
 24171           const unsigned int
 24172             n0 = (unsigned int)primitive[0],
 24173             n1 = (unsigned int)primitive[1],
 24174             n2 = (unsigned int)primitive[2],
 24175             n3 = (unsigned int)primitive[3],
 24176             tx0 = (unsigned int)primitive[4],
 24177             ty0 = (unsigned int)primitive[5],
 24178             tx1 = (unsigned int)primitive[6],
 24179             ty1 = (unsigned int)primitive[7],
 24180             tx2 = (unsigned int)primitive[8],
 24181             ty2 = (unsigned int)primitive[9],
 24182             tx3 = (unsigned int)primitive[10],
 24183             ty3 = (unsigned int)primitive[11];
 24184           const int
 24185             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 24186             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 24187             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
 24188             x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
 24189           const float
 24190             z0 = points(n0,2) + Z + focale,
 24191             z1 = points(n1,2) + Z + focale,
 24192             z2 = points(n2,2) + Z + focale,
 24193             z3 = points(n3,2) + Z + focale;
 24194           switch (render_type) {
 24195           case 0 :
 24196             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 24197               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 24198               draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
 24199               draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
 24200 #ifdef cimg_use_board
 24201             if (pboard) {
 24202               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24203               board.drawCircle((float)x0,dimy()-(float)y0,0);
 24204               board.drawCircle((float)x1,dimy()-(float)y1,0);
 24205               board.drawCircle((float)x2,dimy()-(float)y2,0);
 24206               board.drawCircle((float)x3,dimy()-(float)y3,0);
 24208 #endif
 24209             break;
 24210           case 1 :
 24211             if (zbuffer)
 24212               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 24213                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
 24214                 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
 24215                 draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
 24216             else
 24217               draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 24218                 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
 24219                 draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
 24220                 draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
 24221 #ifdef cimg_use_board
 24222             if (pboard) {
 24223               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24224               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 24225               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24226               board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 24227               board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 24229 #endif
 24230             break;
 24231           case 2 :
 24232             if (zbuffer)
 24233               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
 24234                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
 24235             else
 24236               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
 24237                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
 24238 #ifdef cimg_use_board
 24239             if (pboard) {
 24240               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24241               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24242               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 24244 #endif
 24245             break;
 24246           case 3 :
 24247             if (zbuffer)
 24248               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
 24249                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
 24250             else
 24251               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
 24252                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
 24253 #ifdef cimg_use_board
 24254             if (pboard) {
 24255               const float lp = cimg::min(lightprops(l),1);
 24256               board.setPenColorRGBi((unsigned char)(128*lp),
 24257                                      (unsigned char)(128*lp),
 24258                                      (unsigned char)(128*lp),
 24259                                      (unsigned char)(opac*255));
 24260               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 24261               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 24263 #endif
 24264             break;
 24265           case 4 : {
 24266             const float
 24267               lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
 24268               lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
 24269             if (zbuffer)
 24270               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
 24271                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
 24272             else
 24273               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
 24274                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
 24275 #ifdef cimg_use_board
 24276             if (pboard) {
 24277               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24278               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 24279                                          (float)x1,dimy()-(float)y1,lightprop1,
 24280                                          (float)x2,dimy()-(float)y2,lightprop2);
 24281               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 24282                                          (float)x2,dimy()-(float)y2,lightprop2,
 24283                                          (float)x3,dimy()-(float)y3,lightprop3);
 24285 #endif
 24286           } break;
 24287           case 5 : {
 24288             const unsigned int
 24289               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 24290               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 24291               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
 24292               lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
 24293             if (zbuffer)
 24294               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 24295                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 24296             else
 24297               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 24298                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 24299 #ifdef cimg_use_board
 24300             if (pboard) {
 24301               const float
 24302                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 24303                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 24304                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 24305                 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 24306               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 24307               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 24308                                          (float)x1,dimy()-(float)y1,l1,
 24309                                          (float)x2,dimy()-(float)y2,l2);
 24310               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 24311                                          (float)x2,dimy()-(float)y2,l2,
 24312                                          (float)x3,dimy()-(float)y3,l3);
 24314 #endif
 24315           } break;
 24317         } break;
 24321       return *this;
 24324     //! Draw a 3D object.
 24325     /**
 24326        \param X = X-coordinate of the 3d object position
 24327        \param Y = Y-coordinate of the 3d object position
 24328        \param Z = Z-coordinate of the 3d object position
 24329        \param points = Image N*3 describing 3D point coordinates
 24330        \param primitives = List of P primitives
 24331        \param colors = List of P color (or textures)
 24332        \param opacities = Image of P opacities
 24333        \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)
 24334        \param double_sided = Tell if object faces have two sides or are oriented.
 24335        \param focale = length of the focale
 24336        \param lightx = X-coordinate of the light
 24337        \param lighty = Y-coordinate of the light
 24338        \param lightz = Z-coordinate of the light
 24339        \param specular_shine = Shininess of the object
 24340     **/
 24341     template<typename tp, typename tf, typename tc, typename to>
 24342     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 24343                            const CImg<tp>& points, const CImgList<tf>& primitives,
 24344                            const CImgList<tc>& colors, const CImgList<to>& opacities,
 24345                            const unsigned int render_type=4,
 24346                            const bool double_sided=false, const float focale=500,
 24347                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24348                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24349                            float *const zbuffer=0) {
 24350       if (!points) return *this;
 24351       return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 24352                             primitives,colors,opacities,opacities.size,
 24353                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24356 #ifdef cimg_use_board
 24357     template<typename tp, typename tf, typename tc, typename to>
 24358     CImg<T>& draw_object3d(BoardLib::Board& board,
 24359                            const float x0, const float y0, const float z0,
 24360                            const CImg<tp>& points, const CImgList<tf>& primitives,
 24361                            const CImgList<tc>& colors, const CImgList<to>& opacities,
 24362                            const unsigned int render_type=4,
 24363                            const bool double_sided=false, const float focale=500,
 24364                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24365                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24366                            float *const zbuffer=0) {
 24367       if (!points) return *this;
 24368       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 24369                             primitives,colors,opacities,opacities.size,
 24370                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24372 #endif
 24374     //! Draw a 3D object.
 24375     template<typename tp, typename tf, typename tc, typename to>
 24376     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 24377                            const CImgList<tp>& points, const CImgList<tf>& primitives,
 24378                            const CImgList<tc>& colors, const CImgList<to>& opacities,
 24379                            const unsigned int render_type=4,
 24380                            const bool double_sided=false, const float focale=500,
 24381                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24382                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24383                            float *const zbuffer=0) {
 24384       if (!points) return *this;
 24385       return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
 24386                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24389 #ifdef cimg_use_board
 24390     template<typename tp, typename tf, typename tc, typename to>
 24391     CImg<T>& draw_object3d(BoardLib::Board& board,
 24392                            const float x0, const float y0, const float z0,
 24393                            const CImgList<tp>& points, const CImgList<tf>& primitives,
 24394                            const CImgList<tc>& colors, const CImgList<to>& opacities,
 24395                            const unsigned int render_type=4,
 24396                            const bool double_sided=false, const float focale=500,
 24397                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24398                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24399                            float *const zbuffer=0) {
 24400       if (!points) return *this;
 24401       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
 24402                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24404 #endif
 24406     //! Draw a 3D object.
 24407     template<typename tp, typename tf, typename tc, typename to>
 24408     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 24409                            const CImg<tp>& points, const CImgList<tf>& primitives,
 24410                            const CImgList<tc>& colors, const CImg<to>& opacities,
 24411                            const unsigned int render_type=4,
 24412                            const bool double_sided=false, const float focale=500,
 24413                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24414                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24415                            float *const zbuffer=0) {
 24416       if (!points) return *this;
 24417       return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 24418                             primitives,colors,opacities,opacities.size(),
 24419                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24422 #ifdef cimg_use_board
 24423     template<typename tp, typename tf, typename tc, typename to>
 24424     CImg<T>& draw_object3d(BoardLib::Board& board,
 24425                            const float x0, const float y0, const float z0,
 24426                            const CImg<tp>& points, const CImgList<tf>& primitives,
 24427                            const CImgList<tc>& colors, const CImg<to>& opacities,
 24428                            const unsigned int render_type=4,
 24429                            const bool double_sided=false, const float focale=500,
 24430                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24431                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24432                            float *const zbuffer=0) {
 24433       if (!points) return *this;
 24434       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width
 24435                             ,primitives,colors,opacities,opacities.size(),
 24436                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24438 #endif
 24440     //! Draw a 3D object.
 24441     template<typename tp, typename tf, typename tc, typename to>
 24442     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 24443                            const CImgList<tp>& points, const CImgList<tf>& primitives,
 24444                            const CImgList<tc>& colors, const CImg<to>& opacities,
 24445                            const unsigned int render_type=4,
 24446                            const bool double_sided=false, const float focale=500,
 24447                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24448                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24449                            float *const zbuffer=0) {
 24450       if (!points) return *this;
 24451       return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
 24452                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24455 #ifdef cimg_use_board
 24456     template<typename tp, typename tf, typename tc, typename to>
 24457     CImg<T>& draw_object3d(BoardLib::Board& board,
 24458                            const float x0, const float y0, const float z0,
 24459                            const CImgList<tp>& points, const CImgList<tf>& primitives,
 24460                            const CImgList<tc>& colors, const CImg<to>& opacities,
 24461                            const unsigned int render_type=4,
 24462                            const bool double_sided=false, const float focale=500,
 24463                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24464                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24465                            float *const zbuffer=0) {
 24466       if (!points) return *this;
 24467       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
 24468                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 24470 #endif
 24472     //! Draw a 3D object.
 24473     template<typename tp, typename tf, typename tc>
 24474     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 24475                            const tp& points, const CImgList<tf>& primitives,
 24476                            const CImgList<tc>& colors,
 24477                            const unsigned int render_type=4,
 24478                            const bool double_sided=false, const float focale=500,
 24479                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24480                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24481                            float *const zbuffer=0) {
 24482       static const CImg<floatT> opacities;
 24483       return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
 24484                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
 24487 #ifdef cimg_use_board
 24488     template<typename tp, typename tf, typename tc, typename to>
 24489     CImg<T>& draw_object3d(BoardLib::Board& board,
 24490                            const float x0, const float y0, const float z0,
 24491                            const tp& points, const CImgList<tf>& primitives,
 24492                            const CImgList<tc>& colors,
 24493                            const unsigned int render_type=4,
 24494                            const bool double_sided=false, const float focale=500,
 24495                            const float lightx=0, const float lighty=0, const float lightz=-5000,
 24496                            const float specular_light=0.2f, const float specular_shine=0.1f,
 24497                            float *const zbuffer=0) {
 24498       static const CImg<floatT> opacities;
 24499       return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
 24500                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
 24502 #endif
 24504     //@}
 24505     //----------------------------
 24506     //
 24507     //! \name Image Filtering
 24508     //@{
 24509     //----------------------------
 24511     //! Compute the correlation of the instance image by a mask.
 24512     /**
 24513        The correlation of the instance image \p *this by the mask \p mask is defined to be :
 24515        res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k)
 24517        \param mask = the correlation kernel.
 24518        \param cond = the border condition type (0=zero, 1=dirichlet)
 24519        \param weighted_correl = enable local normalization.
 24520     **/
 24521     template<typename t>
 24522     CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
 24523       return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
 24526     template<typename t>
 24527     CImg<typename cimg::superset2<T,t,float>::type> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
 24528                                                                   const bool weighted_correl=false) const {
 24529       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 24530       if (is_empty()) return *this;
 24531       if (!mask || mask.dim!=1)
 24532         throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
 24533                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 24534       CImg<Ttfloat> dest(width,height,depth,dim);
 24535       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
 24536         // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
 24537         switch (mask.depth) {
 24538         case 3 : {
 24539           T I[27] = { 0 };
 24540           cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24541             (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
 24542              I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 24543              I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
 24544              I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 24545              I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 24546              I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 24547              I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
 24548              I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 24549              I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
 24550           if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
 24551             const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
 24552                                            I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
 24553                                            I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
 24554                                            I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 24555                                            I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 24556                                            I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 24557                                            I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
 24558                                            I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 24559                                            I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
 24560             if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24562         } break;
 24563         case 2 : {
 24564           T I[8] = { 0 };
 24565           cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24566             (I[0]*mask[0] + I[1]*mask[1] +
 24567              I[2]*mask[2] + I[3]*mask[3] +
 24568              I[4]*mask[4] + I[5]*mask[5] +
 24569              I[6]*mask[6] + I[7]*mask[7]);
 24570           if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
 24571             const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 24572                                            I[2]*I[2] + I[3]*I[3] +
 24573                                            I[4]*I[4] + I[5]*I[5] +
 24574                                            I[6]*I[6] + I[7]*I[7]);
 24575             if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24577         } break;
 24578         default :
 24579         case 1 :
 24580           switch (mask.width) {
 24581           case 6 : {
 24582             T I[36] = { 0 };
 24583             cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24584               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 24585                I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 24586                I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 24587                I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 24588                I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
 24589                I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
 24590             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 24591               const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
 24592                                              I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 24593                                              I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 24594                                              I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 24595                                              I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
 24596                                              I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
 24597               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24599           } break;
 24600           case 5 : {
 24601             T I[25] = { 0 };
 24602             cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24603               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
 24604                I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
 24605                I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 24606                I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
 24607                I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
 24608             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 24609               const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
 24610                                              I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
 24611                                              I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 24612                                              I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
 24613                                              I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
 24614               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24616           } break;
 24617           case 4 : {
 24618             T I[16] = { 0 };
 24619             cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24620               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
 24621                I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
 24622                I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 24623                I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
 24624             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
 24625               const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
 24626                                              I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
 24627                                              I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 24628                                              I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
 24629               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24631           } break;
 24632           case 3 : {
 24633             T I[9] = { 0 };
 24634             cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24635               (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 24636                I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 24637                I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 24638             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
 24639               const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
 24640                                              I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
 24641                                              I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
 24642               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24644           } break;
 24645           case 2 : {
 24646             T I[4] = { 0 };
 24647             cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 24648               (I[0]*mask[0] + I[1]*mask[1] +
 24649                I[2]*mask[2] + I[3]*mask[3]);
 24650             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
 24651               const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 24652                                              I[2]*I[2] + I[3]*I[3]);
 24653               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 24655           } break;
 24656           case 1 : (dest.assign(*this))*=mask(0); break;
 24659       } else { // Generic version for other masks
 24660         const int
 24661           mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 24662           mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 24663           mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 24664         cimg_forV(*this,v)
 24665           if (!weighted_correl) { // Classical correlation
 24666             for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24667               Ttfloat val = 0;
 24668               for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 24669                 val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 24670               dest(x,y,z,v) = (Ttfloat)val;
 24672             if (cond)
 24673               cimg_forYZV(*this,y,z,v)
 24674                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24675                   Ttfloat val = 0;
 24676                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 24677                     val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 24678                   dest(x,y,z,v) = (Ttfloat)val;
 24680             else
 24681               cimg_forYZV(*this,y,z,v)
 24682                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24683                   Ttfloat val = 0;
 24684                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 24685                     val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
 24686                   dest(x,y,z,v) = (Ttfloat)val;
 24688           } else { // Weighted correlation
 24689             for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24690               Ttfloat val = 0, weight = 0;
 24691               for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24692                 const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
 24693                 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 24694                 weight+=cval*cval;
 24696               dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 24698             if (cond)
 24699               cimg_forYZV(*this,y,z,v)
 24700                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24701                   Ttfloat val = 0, weight = 0;
 24702                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24703                     const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
 24704                     val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 24705                     weight+=cval*cval;
 24707                   dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 24709             else
 24710               cimg_forYZV(*this,y,z,v)
 24711                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24712                   Ttfloat val = 0, weight = 0;
 24713                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24714                     const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
 24715                     val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 24716                     weight+=cval*cval;
 24718                   dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 24722       return dest;
 24725     //! Compute the convolution of the image by a mask.
 24726     /**
 24727        The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
 24729        res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)
 24731        \param mask = the correlation kernel.
 24732        \param cond = the border condition type (0=zero, 1=dirichlet)
 24733        \param weighted_convol = enable local normalization.
 24734     **/
 24735     template<typename t>
 24736     CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
 24737       return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
 24740     template<typename t>
 24741     CImg<typename cimg::superset2<T,t,float>::type> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
 24742                                                                  const bool weighted_convol=false) const {
 24743       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 24744       if (is_empty()) return *this;
 24745       if (!mask || mask.dim!=1)
 24746         throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
 24747                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 24748       return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
 24751     //! Return the erosion of the image by a structuring element.
 24752     template<typename t>
 24753     CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
 24754       return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
 24757     template<typename t>
 24758     CImg<typename cimg::superset<T,t>::type> get_erode(const CImg<t>& mask, const unsigned int cond=1,
 24759                                                        const bool weighted_erosion=false) const {
 24760       typedef typename cimg::superset<T,t>::type Tt;
 24761       if (is_empty()) return *this;
 24762       if (!mask || mask.dim!=1)
 24763         throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
 24764                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 24765       CImg<Tt> dest(width,height,depth,dim);
 24766       const int
 24767         mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 24768         mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 24769         mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 24770       cimg_forV(*this,v)
 24771         if (!weighted_erosion) { // Classical erosion
 24772           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24773             Tt min_val = cimg::type<Tt>::max();
 24774             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24775               const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 24776               if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 24778             dest(x,y,z,v) = min_val;
 24780           if (cond)
 24781             cimg_forYZV(*this,y,z,v)
 24782               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24783                 Tt min_val = cimg::type<Tt>::max();
 24784                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24785                   const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
 24786                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 24788                 dest(x,y,z,v) = min_val;
 24790           else
 24791             cimg_forYZV(*this,y,z,v)
 24792               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24793                 Tt min_val = cimg::type<Tt>::max();
 24794                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24795                   const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
 24796                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 24798                 dest(x,y,z,v) = min_val;
 24800         } else { // Weighted erosion
 24801           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24802             Tt min_val = cimg::type<Tt>::max();
 24803             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24804               const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24805               const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
 24806               if (mval && cval<min_val) min_val = cval;
 24808             dest(x,y,z,v) = min_val;
 24810           if (cond)
 24811             cimg_forYZV(*this,y,z,v)
 24812               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24813                 Tt min_val = cimg::type<Tt>::max();
 24814                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24815                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24816                   const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
 24817                   if (mval && cval<min_val) min_val = cval;
 24819                 dest(x,y,z,v) = min_val;
 24821           else
 24822             cimg_forYZV(*this,y,z,v)
 24823               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24824                 Tt min_val = cimg::type<Tt>::max();
 24825                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24826                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24827                   const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
 24828                   if (mval && cval<min_val) min_val = cval;
 24830                 dest(x,y,z,v) = min_val;
 24833       return dest;
 24836     //! Erode the image by a square structuring element of size n.
 24837     CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
 24838       if (n<2) return *this;
 24839       return get_erode(n,cond).transfer_to(*this);
 24842     CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
 24843       static CImg<T> mask;
 24844       if (n<2) return *this;
 24845       if (mask.width!=n) mask.assign(n,n,1,1,1);
 24846       const CImg<T> res = get_erode(mask,cond,false);
 24847       if (n>20) mask.assign();
 24848       return res;
 24851     //! Dilate the image by a structuring element.
 24852     template<typename t>
 24853     CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
 24854       return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
 24857     template<typename t>
 24858     CImg<typename cimg::superset<T,t>::type> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
 24859                                                         const bool weighted_dilatation=false) const {
 24860       typedef typename cimg::superset<T,t>::type Tt;
 24861       if (is_empty()) return *this;
 24862       if (!mask || mask.dim!=1)
 24863         throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
 24864                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 24865       CImg<Tt> dest(width,height,depth,dim);
 24866       const int
 24867         mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 24868         mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 24869         mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 24870       cimg_forV(*this,v)
 24871         if (!weighted_dilatation) { // Classical dilatation
 24872           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24873             Tt max_val = cimg::type<Tt>::min();
 24874             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24875               const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 24876               if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 24878             dest(x,y,z,v) = max_val;
 24880           if (cond)
 24881             cimg_forYZV(*this,y,z,v)
 24882               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24883                 Tt max_val = cimg::type<Tt>::min();
 24884                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24885                   const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
 24886                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 24888                 dest(x,y,z,v) = max_val;
 24890           else
 24891             cimg_forYZV(*this,y,z,v)
 24892               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24893                 Tt max_val = cimg::type<Tt>::min();
 24894                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24895                   const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
 24896                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 24898                 dest(x,y,z,v) = max_val;
 24900         } else { // Weighted dilatation
 24901           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 24902             Tt max_val = cimg::type<Tt>::min();
 24903             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24904               const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24905               const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
 24906               if (mval && cval>max_val) max_val = cval;
 24908             dest(x,y,z,v) = max_val;
 24910           if (cond)
 24911             cimg_forYZV(*this,y,z,v)
 24912               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24913                 Tt max_val = cimg::type<Tt>::min();
 24914                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24915                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24916                   const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
 24917                   if (mval && cval>max_val) max_val = cval;
 24919                 dest(x,y,z,v) = max_val;
 24921           else
 24922             cimg_forYZV(*this,y,z,v)
 24923               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 24924                 Tt max_val = cimg::type<Tt>::min();
 24925                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 24926                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 24927                   const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
 24928                   if (mval && cval>max_val) max_val = cval;
 24930                 dest(x,y,z,v) = max_val;
 24933       return dest;
 24936     //! Dilate the image by a square structuring element of size n.
 24937     CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
 24938       if (n<2) return *this;
 24939       return get_dilate(n,cond).transfer_to(*this);
 24942     CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
 24943       static CImg<T> mask;
 24944       if (n<2) return *this;
 24945       if (mask.width!=n) mask.assign(n,n,1,1,1);
 24946       const CImg<T> res = get_dilate(mask,cond,false);
 24947       if (n>20) mask.assign();
 24948       return res;
 24951     //! Add noise to the image.
 24952     /**
 24953        \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
 24954        \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper, 3=Poisson, 4=Rician.
 24955        \return A noisy version of the instance image.
 24956     **/
 24957     CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
 24958       if (!is_empty()) {
 24959         double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
 24960         Tfloat m = 0, M = 0;
 24961         if (nsigma==0 && noise_type!=3) return *this;
 24962         if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
 24963         if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
 24964         switch (noise_type) {
 24965         case 0 : { // Gaussian noise
 24966           cimg_for(*this,ptr,T) {
 24967             double val = *ptr + nsigma*cimg::grand();
 24968             if (val>max) val = max;
 24969             if (val<min) val = min;
 24970             *ptr = (T)val;
 24972         } break;
 24973         case 1 : { // Uniform noise
 24974           cimg_for(*this,ptr,T) {
 24975             double val = *ptr + nsigma*cimg::crand();
 24976             if (val>max) val = max;
 24977             if (val<min) val = min;
 24978             *ptr = (T)val;
 24980         } break;
 24981         case 2 : { // Salt & Pepper noise
 24982           if (nsigma<0) nsigma = -nsigma;
 24983           if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
 24984           cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
 24985         } break;
 24987         case 3 : { // Poisson Noise
 24988           cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
 24989         } break;
 24991         case 4 : { // Rice noise
 24992           const double sqrt2 = (double)cimg_std::sqrt(2.0);
 24993           cimg_for(*this,ptr,T) {
 24994             const double
 24995               val0 = (double)*ptr/sqrt2,
 24996               re = val0 + nsigma*cimg::grand(),
 24997               im = val0 + nsigma*cimg::grand();
 24998             double val = cimg_std::sqrt(re*re + im*im);
 24999             if (val>max) val = max;
 25000             if (val<min) val = min;
 25001             *ptr = (T)val;
 25003         } break;
 25004         default :
 25005           throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
 25006                                       "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
 25009       return *this;
 25012     CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
 25013       return (+*this).noise(sigma,noise_type);
 25016     //! Compute the result of the Deriche filter.
 25017     /**
 25018        The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
 25019        order 0,1 or 2 of an image.
 25020     **/
 25021     CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
 25022 #define _cimg_deriche2_apply \
 25023   Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
 25024   T xp = (T)0; \
 25025   if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
 25026   for (int m=0; m<N; ++m) { \
 25027     const T xc = *ptrX; ptrX+=off; \
 25028     const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
 25029     xp = xc; yb = yp; yp = yc; \
 25030   } \
 25031   T xn = (T)0, xa = (T)0; \
 25032   Tfloat yn = 0, ya = 0; \
 25033   if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
 25034   for (int n=N-1; n>=0; --n) { \
 25035     const T xc = *(ptrX-=off); \
 25036     const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
 25037     xa = xn; xn = xc; ya = yn; yn = yc; \
 25038     *ptrX = (T)(*(--ptrY)+yc); \
 25040       if (sigma<0)
 25041         throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",
 25042                                     pixel_type(),sigma);
 25043       if (is_empty() || (sigma<0.1 && !order)) return *this;
 25044       const float
 25045         nsigma = sigma<0.1f?0.1f:sigma,
 25046         alpha = 1.695f/nsigma,
 25047         ema = (float)cimg_std::exp(-alpha),
 25048         ema2 = (float)cimg_std::exp(-2*alpha),
 25049         b1 = -2*ema,
 25050         b2 = ema2;
 25051       float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
 25052       switch (order) {
 25053       case 0 : {
 25054         const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
 25055         a0 = k;
 25056         a1 = k*(alpha-1)*ema;
 25057         a2 = k*(alpha+1)*ema;
 25058         a3 = -k*ema2;
 25059       } break;
 25060       case 1 : {
 25061         const float k = (1-ema)*(1-ema)/ema;
 25062         a0 = k*ema;
 25063         a1 = a3 = 0;
 25064         a2 = -a0;
 25065       } break;
 25066       case 2 : {
 25067         const float
 25068           ea = (float)cimg_std::exp(-alpha),
 25069           k = -(ema2-1)/(2*alpha*ema),
 25070           kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
 25071         a0 = kn;
 25072         a1 = -kn*(1+k*alpha)*ema;
 25073         a2 = kn*(1-k*alpha)*ema;
 25074         a3 = -kn*ema2;
 25075       } break;
 25076       default :
 25077         throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
 25078                                     pixel_type(),order);
 25080       coefp = (a0+a1)/(1+b1+b2);
 25081       coefn = (a2+a3)/(1+b1+b2);
 25082       switch (cimg::uncase(axis)) {
 25083       case 'x' : {
 25084         const int N = width, off = 1;
 25085         CImg<Tfloat> Y(N);
 25086         cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
 25087       } break;
 25088       case 'y' : {
 25089         const int N = height, off = width;
 25090         CImg<Tfloat> Y(N);
 25091         cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
 25092       } break;
 25093       case 'z' : {
 25094         const int N = depth, off = width*height;
 25095         CImg<Tfloat> Y(N);
 25096         cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
 25097       } break;
 25098       case 'v' : {
 25099         const int N = dim, off = width*height*depth;
 25100         CImg<Tfloat> Y(N);
 25101         cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
 25102       } break;
 25104       return *this;
 25107     CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
 25108       return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
 25111     //! Return a blurred version of the image, using a Canny-Deriche filter.
 25112     /**
 25113        Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
 25114     **/
 25115     CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
 25116       if (!is_empty()) {
 25117         if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
 25118         if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
 25119         if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
 25121       return *this;
 25124     CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
 25125                           const bool cond=true) const {
 25126       return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
 25129     //! Return a blurred version of the image, using a Canny-Deriche filter.
 25130     CImg<T>& blur(const float sigma, const bool cond=true) {
 25131       return blur(sigma,sigma,sigma,cond);
 25134     CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
 25135       return CImg<Tfloat>(*this,false).blur(sigma,cond);
 25138     //! Blur the image anisotropically following a field of diffusion tensors.
 25139     /**
 25140        \param G = Field of square roots of diffusion tensors used to drive the smoothing.
 25141        \param amplitude = amplitude of the smoothing.
 25142        \param dl = spatial discretization.
 25143        \param da = angular discretization.
 25144        \param gauss_prec = precision of the gaussian function.
 25145        \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 25146        \param fast_approx = Tell to use the fast approximation or not.
 25147     **/
 25148     template<typename t>
 25149     CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
 25150                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) {
 25151 #define _cimg_valign2d(i,j) \
 25152     { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
 25153     if (u*curru + v*currv<0) { u=-u; v=-v; }}
 25154 #define _cimg_valign3d(i,j,k) \
 25155     { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
 25156     if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
 25158       // Check arguments and init variables
 25159       if (!is_empty() && amplitude>0) {
 25160         if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
 25161           throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
 25162                                       pixel_type(),G.width,G.height,G.depth,G.dim);
 25164         const float sqrt2amplitude = (float)cimg_std::sqrt(2*amplitude);
 25165         const bool threed = (G.dim>=6);
 25166         const int
 25167           dx1 = dimx()-1,
 25168           dy1 = dimy()-1,
 25169           dz1 = dimz()-1;
 25170         CImg<Tfloat>
 25171           dest(width,height,depth,dim,0),
 25172           W(width,height,depth,threed?4:3),
 25173           tmp(dim);
 25174         int N = 0;
 25176         if (threed)
 25177           // 3D version of the algorithm
 25178           for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
 25179             const float
 25180               phir = (float)(phi*cimg::valuePI/180),
 25181               datmp = (float)(da/cimg_std::cos(phir)),
 25182               da2 = datmp<1?360.0f:datmp;
 25184             for (float theta=0; theta<360; (theta+=da2),++N) {
 25185               const float
 25186                 thetar = (float)(theta*cimg::valuePI/180),
 25187                 vx = (float)(cimg_std::cos(thetar)*cimg_std::cos(phir)),
 25188                 vy = (float)(cimg_std::sin(thetar)*cimg_std::cos(phir)),
 25189                 vz = (float)cimg_std::sin(phir);
 25190               const t
 25191                 *pa = G.ptr(0,0,0,0),
 25192                 *pb = G.ptr(0,0,0,1),
 25193                 *pc = G.ptr(0,0,0,2),
 25194                 *pd = G.ptr(0,0,0,3),
 25195                 *pe = G.ptr(0,0,0,4),
 25196                 *pf = G.ptr(0,0,0,5);
 25197               Tfloat
 25198                 *pd0 = W.ptr(0,0,0,0),
 25199                 *pd1 = W.ptr(0,0,0,1),
 25200                 *pd2 = W.ptr(0,0,0,2),
 25201                 *pd3 = W.ptr(0,0,0,3);
 25202               cimg_forXYZ(G,xg,yg,zg) {
 25203                 const t
 25204                   a = *(pa++), b = *(pb++), c = *(pc++),
 25205                   d = *(pd++), e = *(pe++), f = *(pf++);
 25206                 const float
 25207                   u = (float)(a*vx + b*vy + c*vz),
 25208                   v = (float)(b*vx + d*vy + e*vz),
 25209                   w = (float)(c*vx + e*vy + f*vz),
 25210                   n = (float)cimg_std::sqrt(1e-5+u*u+v*v+w*w),
 25211                   dln = dl/n;
 25212                 *(pd0++) = (Tfloat)(u*dln);
 25213                 *(pd1++) = (Tfloat)(v*dln);
 25214                 *(pd2++) = (Tfloat)(w*dln);
 25215                 *(pd3++) = (Tfloat)n;
 25218               cimg_forXYZ(*this,x,y,z) {
 25219                 tmp.fill(0);
 25220                 const float
 25221                   cu = (float)W(x,y,z,0),
 25222                   cv = (float)W(x,y,z,1),
 25223                   cw = (float)W(x,y,z,2),
 25224                   n = (float)W(x,y,z,3),
 25225                   fsigma = (float)(n*sqrt2amplitude),
 25226                   length = gauss_prec*fsigma,
 25227                   fsigma2 = 2*fsigma*fsigma;
 25228                 float
 25229                   S = 0,
 25230                   pu = cu,
 25231                   pv = cv,
 25232                   pw = cw,
 25233                   X = (float)x,
 25234                   Y = (float)y,
 25235                   Z = (float)z;
 25237                 switch (interpolation_type) {
 25238                 case 0 : {
 25239                   // Nearest neighbor
 25240                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 25241                     const int
 25242                       cx = (int)(X+0.5f),
 25243                       cy = (int)(Y+0.5f),
 25244                       cz = (int)(Z+0.5f);
 25245                     float
 25246                       u = (float)W(cx,cy,cz,0),
 25247                       v = (float)W(cx,cy,cz,1),
 25248                       w = (float)W(cx,cy,cz,2);
 25249                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 25250                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
 25251                     else {
 25252                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25253                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
 25254                       S+=coef;
 25256                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 25258                 } break;
 25260                 case 1 : {
 25261                   // Linear interpolation
 25262                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 25263                     const int
 25264                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 25265                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
 25266                       cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
 25267                     const float
 25268                       curru = (float)W(cx,cy,cz,0),
 25269                       currv = (float)W(cx,cy,cz,1),
 25270                       currw = (float)W(cx,cy,cz,2);
 25271                     _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 25272                     _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 25273                     _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 25274                     _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 25275                     _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 25276                     _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 25277                     _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 25278                     _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 25279                     _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
 25280                     float
 25281                       u = (float)(W._linear_atXYZ(X,Y,Z,0)),
 25282                       v = (float)(W._linear_atXYZ(X,Y,Z,1)),
 25283                       w = (float)(W._linear_atXYZ(X,Y,Z,2));
 25284                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 25285                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
 25286                     else {
 25287                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25288                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
 25289                       S+=coef;
 25291                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 25293                 } break;
 25295                 default : {
 25296                   // 2nd order Runge Kutta
 25297                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 25298                     const int
 25299                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 25300                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
 25301                       cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
 25302                     const float
 25303                       curru = (float)W(cx,cy,cz,0),
 25304                       currv = (float)W(cx,cy,cz,1),
 25305                       currw = (float)W(cx,cy,cz,2);
 25306                     _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 25307                     _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 25308                     _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 25309                     _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 25310                     _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 25311                     _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 25312                     _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 25313                     _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 25314                     _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
 25315                     const float
 25316                       u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
 25317                       v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
 25318                       w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
 25319                     float
 25320                       u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
 25321                       v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
 25322                       w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
 25323                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 25324                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
 25325                     else {
 25326                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25327                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
 25328                       S+=coef;
 25330                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 25332                 } break;
 25334                 if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
 25335                 else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
 25336                 cimg_plugin_greycstoration_count;
 25339           } else
 25340             // 2D version of the algorithm
 25341             for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
 25342               const float
 25343                 thetar = (float)(theta*cimg::valuePI/180),
 25344                 vx = (float)(cimg_std::cos(thetar)),
 25345                 vy = (float)(cimg_std::sin(thetar));
 25346               const t
 25347                 *pa = G.ptr(0,0,0,0),
 25348                 *pb = G.ptr(0,0,0,1),
 25349                 *pc = G.ptr(0,0,0,2);
 25350               Tfloat
 25351                 *pd0 = W.ptr(0,0,0,0),
 25352                 *pd1 = W.ptr(0,0,0,1),
 25353                 *pd2 = W.ptr(0,0,0,2);
 25354               cimg_forXY(G,xg,yg) {
 25355                 const t a = *(pa++), b = *(pb++), c = *(pc++);
 25356                 const float
 25357                   u = (float)(a*vx + b*vy),
 25358                   v = (float)(b*vx + c*vy),
 25359                   n = (float)cimg_std::sqrt(1e-5+u*u+v*v),
 25360                   dln = dl/n;
 25361                 *(pd0++) = (Tfloat)(u*dln);
 25362                 *(pd1++) = (Tfloat)(v*dln);
 25363                 *(pd2++) = (Tfloat)n;
 25366               cimg_forXY(*this,x,y) {
 25367                 tmp.fill(0);
 25368                 const float
 25369                   cu = (float)W(x,y,0,0),
 25370                   cv = (float)W(x,y,0,1),
 25371                   n = (float)W(x,y,0,2),
 25372                   fsigma = (float)(n*sqrt2amplitude),
 25373                   length = gauss_prec*fsigma,
 25374                   fsigma2 = 2*fsigma*fsigma;
 25375                 float
 25376                   S = 0,
 25377                   pu = cu,
 25378                   pv = cv,
 25379                   X = (float)x,
 25380                   Y = (float)y;
 25382                 switch (interpolation_type) {
 25384                 case 0 : {
 25385                   // Nearest-neighbor interpolation for 2D images
 25386                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 25387                     const int
 25388                       cx = (int)(X+0.5f),
 25389                       cy = (int)(Y+0.5f);
 25390                     float
 25391                       u = (float)W(cx,cy,0,0),
 25392                       v = (float)W(cx,cy,0,1);
 25393                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 25394                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
 25395                     else {
 25396                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25397                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
 25398                       S+=coef;
 25400                     X+=(pu=u); Y+=(pv=v);
 25402                 } break;
 25404                 case 1 : {
 25405                   // Linear interpolation for 2D images
 25406                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 25407                     const int
 25408                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 25409                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
 25410                     const float
 25411                       curru = (float)W(cx,cy,0,0),
 25412                       currv = (float)W(cx,cy,0,1);
 25413                     _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 25414                     _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 25415                     _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
 25416                     float
 25417                       u = (float)(W._linear_atXY(X,Y,0,0)),
 25418                       v = (float)(W._linear_atXY(X,Y,0,1));
 25419                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 25420                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
 25421                     else {
 25422                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25423                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
 25424                       S+=coef;
 25426                     X+=(pu=u); Y+=(pv=v);
 25428                 } break;
 25430                 default : {
 25431                   // 2nd-order Runge-kutta interpolation for 2D images
 25432                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 25433                     const int
 25434                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 25435                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
 25436                     const float
 25437                       curru = (float)W(cx,cy,0,0),
 25438                       currv = (float)W(cx,cy,0,1);
 25439                     _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 25440                     _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 25441                     _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
 25442                     const float
 25443                       u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),
 25444                       v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
 25445                     float
 25446                       u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)),
 25447                       v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
 25448                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 25449                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
 25450                     else {
 25451                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 25452                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
 25453                       S+=coef;
 25455                     X+=(pu=u); Y+=(pv=v);
 25459                 if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
 25460                 else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
 25461                 cimg_plugin_greycstoration_count;
 25464         const Tfloat *ptrs = dest.data+dest.size();
 25465         const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
 25466         cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
 25468       return *this;
 25471     template<typename t>
 25472     CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
 25473                                  const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
 25474       return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 25477     //! Blur an image in an anisotropic way.
 25478     /**
 25479        \param mask Binary mask.
 25480        \param amplitude Amplitude of the anisotropic blur.
 25481        \param sharpness Contour preservation.
 25482        \param anisotropy Smoothing anisotropy.
 25483        \param alpha Image pre-blurring (gaussian).
 25484        \param sigma Regularity of the tensor-valued geometry.
 25485        \param dl Spatial discretization.
 25486        \param da Angular discretization.
 25487        \param gauss_prec Precision of the gaussian function.
 25488        \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 25489        \param fast_approx Tell to use the fast approximation or not
 25490        \param geom_factor Geometry factor.
 25491     **/
 25492     template<typename tm>
 25493     CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 25494                               const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
 25495                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
 25496                               const float geom_factor=1) {
 25497       if (!is_empty() && amplitude>0) {
 25498         if (amplitude==0) return *this;
 25499         if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
 25500           throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), "
 25501                                       "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n"
 25502                                       "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], "
 25503                                       "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.",
 25504                                       pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
 25505         const bool threed = (depth>1), no_mask = mask.is_empty();
 25506         const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
 25507         CImg<floatT> blurred = CImg<floatT>(*this,false).blur(alpha);
 25508         if (geom_factor>0) blurred*=geom_factor;
 25509         else blurred.normalize(0,-geom_factor);
 25511         if (threed) { // Field for 3D volumes
 25512           cimg_plugin_greycstoration_lock;
 25513           CImg<floatT> val(3), vec(3,3), G(blurred.get_structure_tensor());
 25514           if (sigma>0) G.blur(sigma);
 25515           cimg_forXYZ(*this,x,y,z) {
 25516             if (no_mask || mask(x,y,z)) {
 25517               G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
 25518               const float l1 = val[2], l2 = val[1], l3 = val[0],
 25519                 ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
 25520                 vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
 25521                 wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
 25522                 n1 = (float)cimg_std::pow(1+l1+l2+l3,-power1),
 25523                 n2 = (float)cimg_std::pow(1+l1+l2+l3,-power2);
 25524               G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
 25525               G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
 25526               G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
 25527               G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
 25528               G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
 25529               G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
 25530             } else G(x,y,z,0) = G(x,y,z,1) = G(x,y,z,2) = G(x,y,z,3) = G(x,y,z,4) = G(x,y,z,5) = 0;
 25531             cimg_plugin_greycstoration_count;
 25533           cimg_plugin_greycstoration_unlock;
 25534           blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 25535         } else { // Field for 2D images
 25536           cimg_plugin_greycstoration_lock;
 25537           CImg<floatT> val(2), vec(2,2), G(blurred.get_structure_tensor());
 25538           if (sigma>0) G.blur(sigma);
 25539           cimg_forXY(*this,x,y) {
 25540             if (no_mask || mask(x,y)) {
 25541               G.get_tensor_at(x,y).symmetric_eigen(val,vec);
 25542               const float l1 = val[1], l2 = val[0],
 25543                 ux = vec(1,0), uy = vec(1,1),
 25544                 vx = vec(0,0), vy = vec(0,1),
 25545                 n1 = (float)cimg_std::pow(1+l1+l2,-power1),
 25546                 n2 = (float)cimg_std::pow(1+l1+l2,-power2);
 25547               G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
 25548               G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
 25549               G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
 25550             } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
 25551             cimg_plugin_greycstoration_count;
 25553           cimg_plugin_greycstoration_unlock;
 25554           blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 25557       return *this;
 25560     template<typename tm>
 25561     CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 25562                                  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 25563                                  const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
 25564                                  const bool fast_approx=true, const float geom_factor=1) const {
 25565       return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 25568     //! Blur an image following in an anisotropic way.
 25569     CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 25570                               const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
 25571                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
 25572                               const float geom_factor=1) {
 25573       return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 25576     CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 25577                                  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 25578                                  const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
 25579                                  const bool fast_approx=true, const float geom_factor=1) const {
 25580       return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 25583     //! Blur an image using the bilateral filter.
 25584     /**
 25585        \param sigmax Amount of blur along the X-axis.
 25586        \param sigmay Amount of blur along the Y-axis.
 25587        \param sigmaz Amount of blur along the Z-axis.
 25588        \param sigmar Amount of blur along the range axis.
 25589        \param bgridx Size of the bilateral grid along the X-axis.
 25590        \param bgridy Size of the bilateral grid along the Y-axis.
 25591        \param bgridz Size of the bilateral grid along the Z-axis.
 25592        \param bgridr Size of the bilateral grid along the range axis.
 25593        \param interpolation_type Use interpolation for image slicing.
 25594        \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
 25595        (extended for 3D volumetric images).
 25596     **/
 25597     CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 25598                             const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 25599                             const bool interpolation_type=true) {
 25600       T m, M = maxmin(m);
 25601       const float range = (float)(1.0f+M-m);
 25602       const unsigned int
 25603         bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
 25604         by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
 25605         bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
 25606         br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
 25607         bx = bx0>0?bx0:1,
 25608         by = by0>0?by0:1,
 25609         bz = bz0>0?bz0:1,
 25610         br = br0>0?br0:1;
 25611       const float
 25612         nsigmax = sigmax*bx/width,
 25613         nsigmay = sigmay*by/height,
 25614         nsigmaz = sigmaz*bz/depth,
 25615         nsigmar = sigmar*br/range;
 25616       if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
 25617         const bool threed = depth>1;
 25618         if (threed) { // 3d version of the algorithm
 25619           CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
 25620           cimg_forV(*this,k) {
 25621             bgrid.fill(0); bgridw.fill(0);
 25622             cimg_forXYZ(*this,x,y,z) {
 25623               const T val = (*this)(x,y,z,k);
 25624               const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 25625               bgrid(X,Y,Z,R) = (float)val;
 25626               bgridw(X,Y,Z,R) = 1;
 25628             bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 25629             bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 25630             if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
 25631               const T val = (*this)(x,y,z,k);
 25632               const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
 25633                 bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
 25634               (*this)(x,y,z,k) = (T)(bval0/bval1);
 25635             } else cimg_forXYZ(*this,x,y,z) {
 25636               const T val = (*this)(x,y,z,k);
 25637               const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 25638               const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
 25639               (*this)(x,y,z,k) = (T)(bval0/bval1);
 25642         } else { // 2d version of the algorithm
 25643           CImg<floatT> bgrid(bx,by,br,2);
 25644           cimg_forV(*this,k) {
 25645             bgrid.fill(0);
 25646             cimg_forXY(*this,x,y) {
 25647               const T val = (*this)(x,y,k);
 25648               const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 25649               bgrid(X,Y,R,0) = (float)val;
 25650               bgrid(X,Y,R,1) = 1;
 25652             bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
 25653             if (interpolation_type) cimg_forXY(*this,x,y) {
 25654               const T val = (*this)(x,y,k);
 25655               const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
 25656                 bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
 25657               (*this)(x,y,k) = (T)(bval0/bval1);
 25658             } else cimg_forXY(*this,x,y) {
 25659               const T val = (*this)(x,y,k);
 25660               const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 25661               const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
 25662               (*this)(x,y,k) = (T)(bval0/bval1);
 25667       return *this;
 25670     CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 25671                                const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 25672                                const bool interpolation_type=true) const {
 25673       return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
 25676     //! Blur an image using the bilateral filter.
 25677     CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 25678                             const bool interpolation_type=true) {
 25679       return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 25682     CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 25683                                const bool interpolation_type=true) const {
 25684       return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 25687     //! Blur an image in its patch-based space.
 25688     CImg<T>& blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
 25689                         const unsigned int lookup_size=4, const bool fast_approx=true) {
 25691 #define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
 25692 #define _cimg_blur_patch_slowfunc(x) cimg_std::exp(-(x))
 25693 #define _cimg_blur_patch3d(N,func) { \
 25694   const unsigned int N3 = N*N*N; \
 25695   cimg_for##N##XYZ(*this,x,y,z) { \
 25696     cimg_plugin_greycstoration_count; \
 25697     cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
 25698     const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
 25699     float sum_weights = 0; \
 25700     cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
 25701       cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
 25702       float distance2 = 0; \
 25703       const T *pQ = Q.end(); \
 25704       cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
 25705       distance2/=Pnorm; \
 25706       const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
 25707         alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)func(alldist); \
 25708       sum_weights+=weight; \
 25709       { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
 25710     } \
 25711     if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k)); \
 25712   }}
 25713 #define _cimg_blur_patch2d(N,func) { \
 25714   const unsigned int N2 = N*N; \
 25715   cimg_for##N##XY(*this,x,y) { \
 25716     cimg_plugin_greycstoration_count; \
 25717     cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
 25718     const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
 25719     float sum_weights = 0; \
 25720     cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
 25721       cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
 25722       float distance2 = 0; \
 25723       const T *pQ = Q.end(); \
 25724       cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
 25725       distance2/=Pnorm; \
 25726       const float dx = (float)p-x, dy = (float)q-y, \
 25727         alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
 25728       sum_weights+=weight; \
 25729       { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
 25730     } \
 25731     if (sum_weights>0) cimg_forV(*this,k) res(x,y,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,k) = (Tfloat)((*this)(x,y,k)); \
 25732   }}
 25734       CImg<Tfloat> res(width,height,depth,dim,0);
 25735       CImg<T> P(patch_size*patch_size*dim), Q(P);
 25736       const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
 25737       const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
 25738       if (depth>1) switch (patch_size) { // 3D version
 25739       case 2 :
 25740         if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
 25741         else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
 25742         break;
 25743       case 3 :
 25744         if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
 25745         else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
 25746         break;
 25747       default : {
 25748         const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 25749         cimg_forXYZ(*this,x,y,z) {
 25750           cimg_plugin_greycstoration_count;
 25751           P = get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
 25752           const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
 25753           float sum_weights = 0;
 25754           cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
 25755             (Q = get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
 25756             const float
 25757               dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
 25758               distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
 25759               weight = (float)cimg_std::exp(-distance2);
 25760             sum_weights+=weight;
 25761             cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
 25763           if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k));
 25766       } else switch (patch_size) { // 2D version
 25767       case 2 :
 25768         if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
 25769         else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
 25770         break;
 25771       case 3 :
 25772         if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
 25773         else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
 25774         break;
 25775       case 4 :
 25776         if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
 25777         else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
 25778         break;
 25779       case 5 :
 25780         if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
 25781         else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
 25782         break;
 25783       case 6 :
 25784         if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
 25785         else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
 25786         break;
 25787       case 7 :
 25788         if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
 25789         else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
 25790         break;
 25791       case 8 :
 25792         if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
 25793         else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
 25794         break;
 25795       case 9 :
 25796         if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
 25797         else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
 25798         break;
 25799       default : {
 25800         const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 25801         cimg_forXY(*this,x,y) {
 25802           cimg_plugin_greycstoration_count;
 25803           P = get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
 25804           const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
 25805           float sum_weights = 0;
 25806           cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 25807             (Q = get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
 25808             const float
 25809               dx = (float)x - p, dy = (float)y - q,
 25810               distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
 25811               weight = (float)cimg_std::exp(-distance2);
 25812             sum_weights+=weight;
 25813             cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
 25815           if (sum_weights>0) cimg_forV(*this,k) res(x,y,0,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,0,k) = (Tfloat)((*this)(x,y,0,k));
 25819       return res.transfer_to(*this);
 25822     CImg<T> get_blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
 25823                            const unsigned int lookup_size=4, const bool fast_approx=true) const {
 25824       return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
 25827     //! Compute the Fast Fourier Transform of an image (along a specified axis).
 25828     CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
 25829       return CImgList<Tfloat>(*this).FFT(axis,invert);
 25832     //! Compute the Fast Fourier Transform on an image.
 25833     CImgList<Tfloat> get_FFT(const bool invert=false) const {
 25834       return CImgList<Tfloat>(*this).FFT(invert);
 25837     //! Apply a median filter.
 25838     CImg<T>& blur_median(const unsigned int n) {
 25839       return get_blur_median(n).transfer_to(*this);
 25842     CImg<T> get_blur_median(const unsigned int n) {
 25843       CImg<T> res(width,height,depth,dim);
 25844       if (!n || n==1) return *this;
 25845       const int hl=n/2, hr=hl-1+n%2;
 25846       if (res.depth!=1) {  // 3D median filter
 25847         CImg<T> vois;
 25848         cimg_forXYZV(*this,x,y,z,k) {
 25849           const int
 25850             x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
 25851             nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
 25852             nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
 25853           vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
 25854           res(x,y,z,k) = vois.median();
 25856       } else {
 25857 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
 25858         if (res.height!=1) switch (n) { // 2D median filter
 25859         case 3 : {
 25860           T I[9] = { 0 };
 25861           CImg_3x3(J,T);
 25862           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 25863             cimg_std::memcpy(J,I,9*sizeof(T));
 25864             _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 25865             _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
 25866             _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 25867             _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
 25868             _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
 25869             _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
 25870             _cimg_median_sort(Jcc, Jnp);
 25871             res(x,y,0,k) = Jcc;
 25873         } break;
 25874         case 5 : {
 25875           T I[25] = { 0 };
 25876           CImg_5x5(J,T);
 25877           cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
 25878             cimg_std::memcpy(J,I,25*sizeof(T));
 25879             _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
 25880             _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
 25881             _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
 25882             _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
 25883             _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
 25884             _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
 25885             _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
 25886             _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
 25887             _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
 25888             _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
 25889             _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
 25890             _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
 25891             _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
 25892             _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
 25893             _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
 25894             _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
 25895             _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
 25896             _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
 25897             _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
 25898             _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
 25899             _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
 25900             _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
 25901             _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
 25902             _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
 25903             _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
 25904             res(x,y,0,k) = Jcc;
 25906         } break;
 25907         default : {
 25908           CImg<T> vois;
 25909           cimg_forXYV(*this,x,y,k) {
 25910             const int
 25911               x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
 25912               nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
 25913               nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
 25914             vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
 25915             res(x,y,0,k) = vois.median();
 25918         } else switch (n) { // 1D median filter
 25919         case 2 : {
 25920           T I[4] = { 0 };
 25921           cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
 25922         } break;
 25923         case 3 : {
 25924           T I[9] = { 0 };
 25925           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 25926             res(x,0,0,k) = I[3]<I[4]?
 25927               (I[4]<I[5]?I[4]:
 25928                (I[3]<I[5]?I[5]:I[3])):
 25929               (I[3]<I[5]?I[3]:
 25930                (I[4]<I[5]?I[5]:I[4]));
 25932         } break;
 25933         default : {
 25934           CImg<T> vois;
 25935           cimg_forXV(*this,x,k) {
 25936             const int
 25937               x0 = x - hl, x1 = x + hr,
 25938               nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
 25939             vois = get_crop(nx0,0,0,k,nx1,0,0,k);
 25940             res(x,0,0,k) = vois.median();
 25945       return res;
 25948     //! Sharpen image using anisotropic shock filters or inverse diffusion.
 25949     CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
 25950       if (is_empty()) return *this;
 25951       T valm, valM = maxmin(valm);
 25952       const bool threed = (depth>1);
 25953       const float nedge = 0.5f*edge;
 25954       CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
 25956       if (threed) {
 25957         CImg_3x3x3(I,T);
 25958         if (sharpen_type) { // 3D Shock filter.
 25959           CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
 25960           if (sigma>0) G.blur(sigma);
 25962           cimg_forXYZ(G,x,y,z) {
 25963             G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
 25964             G(x,y,z,0) = vec(0,0);
 25965             G(x,y,z,1) = vec(0,1);
 25966             G(x,y,z,2) = vec(0,2);
 25967             G(x,y,z,3) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
 25969           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 25970             const Tfloat
 25971               u = G(x,y,z,0),
 25972               v = G(x,y,z,1),
 25973               w = G(x,y,z,2),
 25974               amp = G(x,y,z,3),
 25975               ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
 25976               ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
 25977               ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
 25978               iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
 25979               iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
 25980               izz = (Tfloat)Iccn + Iccp - 2*Iccc,
 25981               ixf = (Tfloat)Incc - Iccc,
 25982               ixb = (Tfloat)Iccc - Ipcc,
 25983               iyf = (Tfloat)Icnc - Iccc,
 25984               iyb = (Tfloat)Iccc - Icpc,
 25985               izf = (Tfloat)Iccn - Iccc,
 25986               izb = (Tfloat)Iccc - Iccp,
 25987               itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
 25988               it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
 25989             veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
 25991         } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) veloc(x,y,z,k) = -(Tfloat)Ipcc-Incc-Icpc-Icnc-Iccp-Iccn+6*Iccc; // 3D Inverse diffusion.
 25992       } else {
 25993         CImg_3x3(I,T);
 25994         if (sharpen_type) { // 2D Shock filter.
 25995           CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
 25996           if (sigma>0) G.blur(sigma);
 25997           cimg_forXY(G,x,y) {
 25998             G.get_tensor_at(x,y).symmetric_eigen(val,vec);
 25999             G(x,y,0) = vec(0,0);
 26000             G(x,y,1) = vec(0,1);
 26001             G(x,y,2) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1],-(Tfloat)nedge);
 26003           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 26004             const Tfloat
 26005               u = G(x,y,0),
 26006               v = G(x,y,1),
 26007               amp = G(x,y,2),
 26008               ixx = (Tfloat)Inc + Ipc - 2*Icc,
 26009               ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
 26010               iyy = (Tfloat)Icn + Icp - 2*Icc,
 26011               ixf = (Tfloat)Inc - Icc,
 26012               ixb = (Tfloat)Icc - Ipc,
 26013               iyf = (Tfloat)Icn - Icc,
 26014               iyb = (Tfloat)Icc - Icp,
 26015               itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
 26016               it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
 26017             veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
 26019         } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) veloc(x,y,k) = -(Tfloat)Ipc-Inc-Icp-Icn+4*Icc;  // 3D Inverse diffusion.
 26021       float m, M = (float)veloc.maxmin(m);
 26022       const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
 26023       if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
 26024       return cut(valm,valM);
 26027     CImg<T> get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) const {
 26028       return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
 26031     //! Compute the Haar multiscale wavelet transform (monodimensional version).
 26032     /**
 26033        \param axis Axis considered for the transform.
 26034        \param invert Set inverse of direct transform.
 26035        \param nb_scales Number of scales used for the transform.
 26036     **/
 26037     CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
 26038       return get_haar(axis,invert,nb_scales).transfer_to(*this);
 26041     CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
 26042       if (is_empty() || !nb_scales) return *this;
 26043       CImg<Tfloat> res;
 26045       if (nb_scales==1) {
 26046         switch (cimg::uncase(axis)) { // Single scale transform
 26047         case 'x' : {
 26048           const unsigned int w = width/2;
 26049           if (w) {
 26050             if (w%2)
 26051               throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
 26052                                           pixel_type(),w);
 26053             res.assign(width,height,depth,dim);
 26054             if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
 26055               for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 26056                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
 26057                 res(x2++,y,z,v) = val0 - val1;
 26058                 res(x2++,y,z,v) = val0 + val1;
 26060             } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
 26061               for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 26062                 const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
 26063                 res(x,y,z,v) = (val0 + val1)/2;
 26064                 res(xw,y,z,v) = (val1 - val0)/2;
 26067           } else return *this;
 26068         } break;
 26069         case 'y' : {
 26070           const unsigned int h = height/2;
 26071           if (h) {
 26072             if (h%2)
 26073               throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
 26074                                           pixel_type(),h);
 26075             res.assign(width,height,depth,dim);
 26076             if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
 26077               for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
 26078                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
 26079                 res(x,y2++,z,v) = val0 - val1;
 26080                 res(x,y2++,z,v) = val0 + val1;
 26082             } else cimg_forXZV(*this,x,z,v) {
 26083               for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
 26084                 const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
 26085                 res(x,y,z,v) = (val0 + val1)/2;
 26086                 res(x,yh,z,v) = (val1 - val0)/2;
 26089           } else return *this;
 26090         } break;
 26091         case 'z' : {
 26092           const unsigned int d = depth/2;
 26093           if (d) {
 26094             if (d%2)
 26095               throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
 26096                                           pixel_type(),d);
 26097             res.assign(width,height,depth,dim);
 26098             if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
 26099               for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
 26100                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
 26101                 res(x,y,z2++,v) = val0 - val1;
 26102                 res(x,y,z2++,v) = val0 + val1;
 26104             } else cimg_forXYV(*this,x,y,v) {
 26105               for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
 26106                 const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
 26107                 res(x,y,z,v) = (val0 + val1)/2;
 26108                 res(x,y,zd,v) = (val1 - val0)/2;
 26111           } else return *this;
 26112         } break;
 26113         default :
 26114           throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 26115                                       pixel_type(),axis);
 26117       } else { // Multi-scale version
 26118         if (invert) {
 26119           res.assign(*this);
 26120           switch (cimg::uncase(axis)) {
 26121           case 'x' : {
 26122             unsigned int w = width;
 26123             for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 26124             for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
 26125           } break;
 26126           case 'y' : {
 26127             unsigned int h = width;
 26128             for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 26129             for (h=h?h:1; h<=height; h*=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',true,1));
 26130           } break;
 26131           case 'z' : {
 26132             unsigned int d = depth;
 26133             for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 26134             for (d=d?d:1; d<=depth; d*=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',true,1));
 26135           } break;
 26136           default :
 26137             throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 26138                                         pixel_type(),axis);
 26140         } else { // Direct transform
 26141           res = get_haar(axis,false,1);
 26142           switch (cimg::uncase(axis)) {
 26143           case 'x' : {
 26144             for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',false,1));
 26145           } break;
 26146           case 'y' : {
 26147             for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',false,1));
 26148           } break;
 26149           case 'z' : {
 26150             for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',false,1));
 26151           } break;
 26152           default :
 26153             throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 26154                                         pixel_type(),axis);
 26158       return res;
 26161     //! Compute the Haar multiscale wavelet transform.
 26162     /**
 26163        \param invert Set inverse of direct transform.
 26164        \param nb_scales Number of scales used for the transform.
 26165     **/
 26166     CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
 26167       return get_haar(invert,nb_scales).transfer_to(*this);
 26170     CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
 26171       CImg<Tfloat> res;
 26173       if (nb_scales==1) { // Single scale transform
 26174         if (width>1) get_haar('x',invert,1).transfer_to(res);
 26175         if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
 26176         if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
 26177         if (res) return res;
 26178       } else { // Multi-scale transform
 26179         if (invert) { // Inverse transform
 26180           res.assign(*this);
 26181           if (width>1) {
 26182             if (height>1) {
 26183               if (depth>1) {
 26184                 unsigned int w = width, h = height, d = depth; for (unsigned int s=1; w && h && d && s<nb_scales; ++s) { w/=2; h/=2; d/=2; }
 26185                 for (w=w?w:1, h=h?h:1, d=d?d:1; w<=width && h<=height && d<=depth; w*=2, h*=2, d*=2)
 26186                   res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
 26187               } else {
 26188                 unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
 26189                 for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
 26190                   res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
 26192             } else {
 26193               if (depth>1) {
 26194                 unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
 26195                 for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
 26196                   res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
 26197               } else {
 26198                 unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 26199                 for (w=w?w:1; w<=width; w*=2)
 26200                   res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
 26203           } else {
 26204             if (height>1) {
 26205               if (depth>1) {
 26206                 unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
 26207                 for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
 26208                   res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
 26209               } else {
 26210                 unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 26211                 for (h=h?h:1; h<=height; h*=2)
 26212                   res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
 26214             } else {
 26215               if (depth>1) {
 26216                 unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 26217                 for (d=d?d:1; d<=depth; d*=2)
 26218                   res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
 26219               } else return *this;
 26222         } else { // Direct transform
 26223           res = get_haar(false,1);
 26224           if (width>1) {
 26225             if (height>1) {
 26226               if (depth>1) for (unsigned int s=1, w=width/2, h=height/2, d=depth/2; w && h && d && s<nb_scales; ++s, w/=2, h/=2, d/=2)
 26227                 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
 26228               else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
 26229                 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
 26230             } else {
 26231               if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
 26232                 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
 26233               else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
 26234                 res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
 26236           } else {
 26237             if (height>1) {
 26238               if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
 26239                 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
 26240               else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
 26241                 res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
 26242             } else {
 26243               if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
 26244                 res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
 26245               else return *this;
 26249         return res;
 26251       return *this;
 26254     //! Estimate a displacement field between instance image and given target image.
 26255     CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
 26256                                 const unsigned int nb_scales=0, const unsigned int itermax=10000) {
 26257       return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
 26260     CImg<Tfloat> get_displacement_field(const CImg<T>& target,
 26261                                         const float smoothness=0.1f, const float precision=0.1f,
 26262                                         const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
 26263       if (is_empty() || !target) return *this;
 26264       if (!is_sameXYZV(target))
 26265         throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
 26266                                     "have different size.",
 26267                                     pixel_type(),width,height,depth,dim,data,
 26268                                     target.width,target.height,target.depth,target.dim,target.data);
 26269       if (smoothness<0)
 26270         throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
 26271                                     pixel_type(),smoothness);
 26272       if (precision<0)
 26273         throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
 26274                                     pixel_type(),precision);
 26276       const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*cimg_std::log((double)(cimg::max(width,height,depth))));
 26277       Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
 26278       const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
 26279       CImg<Tfloat> U0;
 26280       const bool threed = (depth>1);
 26282       // Begin multi-scale motion estimation
 26283       for (int scale = (int)nscales-1; scale>=0; --scale) {
 26284         const float sfactor = (float)cimg_std::pow(1.5f,(float)scale), sprecision = (float)(precision/cimg_std::pow(2.25,1+scale));
 26285         const int
 26286           sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
 26287           swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
 26288         CImg<Tfloat>
 26289           I1 = get_resize(swidth,sheight,sdepth,-100,2),
 26290           I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
 26291         I1/=factor; I2/=factor;
 26292         CImg<Tfloat> U;
 26293         if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
 26294         else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
 26296         // Begin single-scale motion estimation
 26297         CImg<Tfloat> veloc(U);
 26298         float dt = 2, Energy = cimg::type<float>::max();
 26299         const CImgList<Tfloat> dI = I2.get_gradient();
 26300         for (unsigned int iter=0; iter<itermax; iter++) {
 26301           veloc.fill(0);
 26302           float nEnergy = 0;
 26303           if (threed) {
 26304             cimg_for3XYZ(U,x,y,z) {
 26305               const float X = (float)(x + U(x,y,z,0)), Y = (float)(y + U(x,y,z,1)), Z = (float)(z + U(x,y,z,2));
 26306               cimg_forV(U,k) {
 26307                 const Tfloat
 26308                   Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
 26309                   Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
 26310                   Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
 26311                   Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
 26312                   Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
 26313                   Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
 26314                 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
 26315                 Tfloat deltaIgrad = 0;
 26316                 cimg_forV(I1,i) {
 26317                   const Tfloat deltaIi = (float)(I2._linear_atXYZ(X,Y,Z,i) - I1(x,y,z,i));
 26318                   nEnergy += (float)(deltaIi*deltaIi/2);
 26319                   deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
 26321                 veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
 26324           } else {
 26325             cimg_for3XY(U,x,y) {
 26326               const float X = (float)(x + U(x,y,0)), Y = (float)(y + U(x,y,1));
 26327               cimg_forV(U,k) {
 26328                 const Tfloat
 26329                   Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
 26330                   Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
 26331                   Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
 26332                   Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
 26333                 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
 26334                 Tfloat deltaIgrad = 0;
 26335                 cimg_forV(I1,i) {
 26336                   const Tfloat deltaIi = (float)(I2._linear_atXY(X,Y,i) - I1(x,y,i));
 26337                   nEnergy += (float)(deltaIi*deltaIi/2);
 26338                   deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
 26340                 veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
 26344           const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
 26345           U+=(veloc*=dt/vmax);
 26346           if (cimg::abs(nEnergy-Energy)<sprecision) break;
 26347           if (nEnergy<Energy) dt*=0.5f;
 26348           Energy = nEnergy;
 26350         U.transfer_to(U0);
 26352       return U0;
 26355     //@}
 26356     //-----------------------------
 26357     //
 26358     //! \name Matrix and Vectors
 26359     //@{
 26360     //-----------------------------
 26362     //! Return a vector with specified coefficients.
 26363     static CImg<T> vector(const T& a0) {
 26364       static CImg<T> r(1,1); r[0] = a0;
 26365       return r;
 26368     //! Return a vector with specified coefficients.
 26369     static CImg<T> vector(const T& a0, const T& a1) {
 26370       static CImg<T> r(1,2); T *ptr = r.data;
 26371       *(ptr++) = a0; *(ptr++) = a1;
 26372       return r;
 26375     //! Return a vector with specified coefficients.
 26376     static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
 26377       static CImg<T> r(1,3); T *ptr = r.data;
 26378       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
 26379       return r;
 26382     //! Return a vector with specified coefficients.
 26383     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
 26384       static CImg<T> r(1,4); T *ptr = r.data;
 26385       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26386       return r;
 26389     //! Return a vector with specified coefficients.
 26390     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 26391       static CImg<T> r(1,5); T *ptr = r.data;
 26392       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
 26393       return r;
 26396     //! Return a vector with specified coefficients.
 26397     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
 26398       static CImg<T> r(1,6); T *ptr = r.data;
 26399       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
 26400       return r;
 26403     //! Return a vector with specified coefficients.
 26404     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26405                           const T& a4, const T& a5, const T& a6) {
 26406       static CImg<T> r(1,7); T *ptr = r.data;
 26407       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26408       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
 26409       return r;
 26412     //! Return a vector with specified coefficients.
 26413     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26414                           const T& a4, const T& a5, const T& a6, const T& a7) {
 26415       static CImg<T> r(1,8); T *ptr = r.data;
 26416       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26417       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26418       return r;
 26421     //! Return a vector with specified coefficients.
 26422     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26423                           const T& a4, const T& a5, const T& a6, const T& a7,
 26424                           const T& a8) {
 26425       static CImg<T> r(1,9); T *ptr = r.data;
 26426       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26427       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26428       *(ptr++) = a8;
 26429       return r;
 26432     //! Return a vector with specified coefficients.
 26433     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26434                           const T& a4, const T& a5, const T& a6, const T& a7,
 26435                           const T& a8, const T& a9) {
 26436       static CImg<T> r(1,10); T *ptr = r.data;
 26437       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26438       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26439       *(ptr++) = a8; *(ptr++) = a9;
 26440       return r;
 26443     //! Return a vector with specified coefficients.
 26444     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26445                           const T& a4, const T& a5, const T& a6, const T& a7,
 26446                           const T& a8, const T& a9, const T& a10) {
 26447       static CImg<T> r(1,11); T *ptr = r.data;
 26448       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26449       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26450       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
 26451       return r;
 26454     //! Return a vector with specified coefficients.
 26455     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26456                           const T& a4, const T& a5, const T& a6, const T& a7,
 26457                           const T& a8, const T& a9, const T& a10, const T& a11) {
 26458       static CImg<T> r(1,12); T *ptr = r.data;
 26459       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26460       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26461       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26462       return r;
 26465     //! Return a vector with specified coefficients.
 26466     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26467                           const T& a4, const T& a5, const T& a6, const T& a7,
 26468                           const T& a8, const T& a9, const T& a10, const T& a11,
 26469                           const T& a12) {
 26470       static CImg<T> r(1,13); T *ptr = r.data;
 26471       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26472       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26473       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26474       *(ptr++) = a12;
 26475       return r;
 26478     //! Return a vector with specified coefficients.
 26479     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26480                           const T& a4, const T& a5, const T& a6, const T& a7,
 26481                           const T& a8, const T& a9, const T& a10, const T& a11,
 26482                           const T& a12, const T& a13) {
 26483       static CImg<T> r(1,14); T *ptr = r.data;
 26484       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26485       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26486       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26487       *(ptr++) = a12; *(ptr++) = a13;
 26488       return r;
 26491     //! Return a vector with specified coefficients.
 26492     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26493                           const T& a4, const T& a5, const T& a6, const T& a7,
 26494                           const T& a8, const T& a9, const T& a10, const T& a11,
 26495                           const T& a12, const T& a13, const T& a14) {
 26496       static CImg<T> r(1,15); T *ptr = r.data;
 26497       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26498       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26499       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26500       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
 26501       return r;
 26504     //! Return a vector with specified coefficients.
 26505     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 26506                           const T& a4, const T& a5, const T& a6, const T& a7,
 26507                           const T& a8, const T& a9, const T& a10, const T& a11,
 26508                           const T& a12, const T& a13, const T& a14, const T& a15) {
 26509       static CImg<T> r(1,16); T *ptr = r.data;
 26510       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26511       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26512       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26513       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
 26514       return r;
 26517     //! Return a 1x1 square matrix with specified coefficients.
 26518     static CImg<T> matrix(const T& a0) {
 26519       return vector(a0);
 26522     //! Return a 2x2 square matrix with specified coefficients.
 26523     static CImg<T> matrix(const T& a0, const T& a1,
 26524                           const T& a2, const T& a3) {
 26525       static CImg<T> r(2,2); T *ptr = r.data;
 26526       *(ptr++) = a0; *(ptr++) = a1;
 26527       *(ptr++) = a2; *(ptr++) = a3;
 26528       return r;
 26531     //! Return a 3x3 square matrix with specified coefficients.
 26532     static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
 26533                           const T& a3, const T& a4, const T& a5,
 26534                           const T& a6, const T& a7, const T& a8) {
 26535       static CImg<T> r(3,3); T *ptr = r.data;
 26536       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
 26537       *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
 26538       *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
 26539       return r;
 26542     //! Return a 4x4 square matrix with specified coefficients.
 26543     static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
 26544                           const T& a4, const T& a5, const T& a6, const T& a7,
 26545                           const T& a8, const T& a9, const T& a10, const T& a11,
 26546                           const T& a12, const T& a13, const T& a14, const T& a15) {
 26547       static CImg<T> r(4,4); T *ptr = r.data;
 26548       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 26549       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 26550       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 26551       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
 26552       return r;
 26555     //! Return a 5x5 square matrix with specified coefficients.
 26556     static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
 26557                           const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
 26558                           const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
 26559                           const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
 26560                           const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
 26561       static CImg<T> r(5,5); T *ptr = r.data;
 26562       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
 26563       *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
 26564       *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
 26565       *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
 26566       *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
 26567       return r;
 26570     //! Return a 1x1 symmetric matrix with specified coefficients.
 26571     static CImg<T> tensor(const T& a1) {
 26572       return matrix(a1);
 26575     //! Return a 2x2 symmetric matrix tensor with specified coefficients.
 26576     static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
 26577       return matrix(a1,a2,a2,a3);
 26580     //! Return a 3x3 symmetric matrix with specified coefficients.
 26581     static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
 26582       return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
 26585     //! Return a 1x1 diagonal matrix with specified coefficients.
 26586     static CImg<T> diagonal(const T& a0) {
 26587       return matrix(a0);
 26590     //! Return a 2x2 diagonal matrix with specified coefficients.
 26591     static CImg<T> diagonal(const T& a0, const T& a1) {
 26592       return matrix(a0,0,0,a1);
 26595     //! Return a 3x3 diagonal matrix with specified coefficients.
 26596     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
 26597       return matrix(a0,0,0,0,a1,0,0,0,a2);
 26600     //! Return a 4x4 diagonal matrix with specified coefficients.
 26601     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
 26602       return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
 26605     //! Return a 5x5 diagonal matrix with specified coefficients.
 26606     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 26607       return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);
 26610     //! Return a NxN identity matrix.
 26611     static CImg<T> identity_matrix(const unsigned int N) {
 26612       CImg<T> res(N,N,1,1,0);
 26613       cimg_forX(res,x) res(x,x) = 1;
 26614       return res;
 26617     //! Return a N-numbered sequence vector from \p a0 to \p a1.
 26618     static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
 26619       if (N) return CImg<T>(1,N).sequence(a0,a1);
 26620       return CImg<T>();
 26623     //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
 26624     static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
 26625       float X,Y,Z,W;
 26626       if (!quaternion_data) {
 26627         const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z),
 26628           nx = norm>0?x/norm:0,
 26629           ny = norm>0?y/norm:0,
 26630           nz = norm>0?z/norm:1,
 26631           nw = norm>0?w:0,
 26632           sina = (float)cimg_std::sin(nw/2),
 26633           cosa = (float)cimg_std::cos(nw/2);
 26634         X = nx*sina;
 26635         Y = ny*sina;
 26636         Z = nz*sina;
 26637         W = cosa;
 26638       } else {
 26639         const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z + w*w);
 26640         if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
 26641         else { X = Y = Z = 0; W = 1; }
 26643       const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W;
 26644       return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)),   (T)(2*(xz-yw)),
 26645                              (T)(2*(xy-zw)),   (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
 26646                              (T)(2*(xz+yw)),   (T)(2*(yz-xw)),   (T)(1-2*(xx+yy)));
 26649     //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
 26650     CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
 26651       static CImg<T> dest;
 26652       if (dest.height!=dim) dest.assign(1,dim);
 26653       const unsigned int whz = width*height*depth;
 26654       const T *ptrs = ptr(x,y,z);
 26655       T *ptrd = dest.data;
 26656       cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
 26657       return dest;
 26660     //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
 26661     template<typename t>
 26662     CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
 26663       if (x<width && y<height && z<depth) {
 26664         const unsigned int whz = width*height*depth;
 26665         const t *ptrs = vec.data;
 26666         T *ptrd = ptr(x,y,z);
 26667         for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
 26669       return *this;
 26672     //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image.
 26673     CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
 26674       const int n = (int)cimg_std::sqrt((double)dim);
 26675       CImg<T> dest(n,n);
 26676       cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
 26677       return dest;
 26680     //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
 26681     template<typename t>
 26682     CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 26683       return set_vector_at(mat,x,y,z);
 26686     //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image.
 26687     CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
 26688       if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
 26689                                 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
 26690       if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
 26691       return tensor((*this)(x,y,z,0));
 26694     //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
 26695     template<typename t>
 26696     CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 26697       if (ten.height==2) {
 26698         (*this)(x,y,z,0) = (T)ten[0];
 26699         (*this)(x,y,z,1) = (T)ten[1];
 26700         (*this)(x,y,z,2) = (T)ten[3];
 26702       else {
 26703         (*this)(x,y,z,0) = (T)ten[0];
 26704         (*this)(x,y,z,1) = (T)ten[1];
 26705         (*this)(x,y,z,2) = (T)ten[2];
 26706         (*this)(x,y,z,3) = (T)ten[4];
 26707         (*this)(x,y,z,4) = (T)ten[5];
 26708         (*this)(x,y,z,5) = (T)ten[8];
 26710       return *this;
 26713     //! Unroll all images values into a one-column vector.
 26714     CImg<T>& vector() {
 26715       return unroll('y');
 26718     CImg<T> get_vector() const {
 26719       return get_unroll('y');
 26722     //! Realign pixel values of the instance image as a square matrix
 26723     CImg<T>& matrix() {
 26724       const unsigned int siz = size();
 26725       switch (siz) {
 26726       case 1 : break;
 26727       case 4 : width = height = 2; break;
 26728       case 9 : width = height = 3; break;
 26729       case 16 : width = height = 4; break;
 26730       case 25 : width = height = 5; break;
 26731       case 36 : width = height = 6; break;
 26732       case 49 : width = height = 7; break;
 26733       case 64 : width = height = 8; break;
 26734       case 81 : width = height = 9; break;
 26735       case 100 : width = height = 10; break;
 26736       default : {
 26737         unsigned int i = 11, i2 = i*i;
 26738         while (i2<siz) { i2+=2*i+1; ++i; }
 26739         if (i2==siz) width = height = i;
 26740         else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
 26741                                          pixel_type(),siz);
 26744       return *this;
 26747     CImg<T> get_matrix() const {
 26748       return (+*this).matrix();
 26751     //! Realign pixel values of the instance image as a symmetric tensor.
 26752     CImg<T>& tensor() {
 26753       return get_tensor().transfer_to(*this);
 26756     CImg<T> get_tensor() const {
 26757       CImg<T> res;
 26758       const unsigned int siz = size();
 26759       switch (siz) {
 26760       case 1 : break;
 26761       case 3 :
 26762         res.assign(2,2);
 26763         res(0,0) = (*this)(0);
 26764         res(1,0) = res(0,1) = (*this)(1);
 26765         res(1,1) = (*this)(2);
 26766         break;
 26767       case 6 :
 26768         res.assign(3,3);
 26769         res(0,0) = (*this)(0);
 26770         res(1,0) = res(0,1) = (*this)(1);
 26771         res(2,0) = res(0,2) = (*this)(2);
 26772         res(1,1) = (*this)(3);
 26773         res(2,1) = res(1,2) = (*this)(4);
 26774         res(2,2) = (*this)(5);
 26775         break;
 26776       default :
 26777         throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
 26778                                     pixel_type(), dim);
 26780       return res;
 26783     //! Unroll all images values into specified axis.
 26784     CImg<T>& unroll(const char axis) {
 26785       const unsigned int siz = size();
 26786       if (siz) switch (axis) {
 26787       case 'x' : width = siz; height=depth=dim=1; break;
 26788       case 'y' : height = siz; width=depth=dim=1; break;
 26789       case 'z' : depth = siz; width=height=dim=1; break;
 26790       case 'v' : dim = siz; width=height=depth=1; break;
 26791       default :
 26792         throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
 26793                                     pixel_type(),axis);
 26795       return *this;
 26798     CImg<T> get_unroll(const char axis) const {
 26799       return (+*this).unroll(axis);
 26802     //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
 26803     CImg<T>& diagonal() {
 26804       return get_diagonal().transfer_to(*this);
 26807     CImg<T> get_diagonal() const {
 26808       if (is_empty()) return *this;
 26809       CImg<T> res(size(),size(),1,1,0);
 26810       cimg_foroff(*this,off) res(off,off) = (*this)(off);
 26811       return res;
 26814     //! Get an identity matrix having same dimension than instance image.
 26815     CImg<T>& identity_matrix() {
 26816       return identity_matrix(cimg::max(width,height)).transfer_to(*this);
 26819     CImg<T> get_identity_matrix() const {
 26820       return identity_matrix(cimg::max(width,height));
 26823     //! Return a N-numbered sequence vector from \p a0 to \p a1.
 26824     CImg<T>& sequence(const T a0, const T a1) {
 26825       if (is_empty()) return *this;
 26826       const unsigned int siz = size() - 1;
 26827       T* ptr = data;
 26828       if (siz) {
 26829         const Tfloat delta = (Tfloat)a1 - a0;
 26830         cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
 26831       } else *ptr = a0;
 26832       return *this;
 26835     CImg<T> get_sequence(const T a0, const T a1) const {
 26836       return (+*this).sequence(a0,a1);
 26839     //! Transpose the current matrix.
 26840     CImg<T>& transpose() {
 26841       if (width==1) { width=height; height=1; return *this; }
 26842       if (height==1) { height=width; width=1; return *this; }
 26843       if (width==height) {
 26844         cimg_forYZV(*this,y,z,v) for (int x=y; x<dimx(); ++x) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v));
 26845         return *this;
 26847       return get_transpose().transfer_to(*this);
 26850     CImg<T> get_transpose() const {
 26851       return get_permute_axes("yxzv");
 26854     //! Invert the current matrix.
 26855     CImg<T>& invert(const bool use_LU=true) {
 26856       if (!is_empty()) {
 26857         if (width!=height || depth!=1 || dim!=1)
 26858           throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
 26859                                       pixel_type(),width,height,depth,dim,data);
 26860 #ifdef cimg_use_lapack
 26861         int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
 26862         Tfloat
 26863           *lapA = new Tfloat[N*N],
 26864           *WORK = new Tfloat[LWORK];
 26865         cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
 26866         cimg::getrf(N,lapA,IPIV,INFO);
 26867         if (INFO)
 26868           cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
 26869                      pixel_type(),INFO);
 26870         else {
 26871           cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
 26872           if (INFO)
 26873             cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
 26874                        pixel_type(),INFO);
 26876         if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
 26877         delete[] IPIV; delete[] lapA; delete[] WORK;
 26878 #else
 26879         const double dete = width>3?-1.0:det();
 26880         if (dete!=0.0 && width==2) {
 26881           const double
 26882             a = data[0], c = data[1],
 26883             b = data[2], d = data[3];
 26884           data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
 26885           data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
 26886         } else if (dete!=0.0 && width==3) {
 26887           const double
 26888             a = data[0], d = data[1], g = data[2],
 26889             b = data[3], e = data[4], h = data[5],
 26890             c = data[6], f = data[7], i = data[8];
 26891           data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
 26892           data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
 26893           data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
 26894         } else {
 26895           if (use_LU) { // LU-based inverse computation
 26896             CImg<Tfloat> A(*this), indx, col(1,width);
 26897             bool d;
 26898             A._LU(indx,d);
 26899             cimg_forX(*this,j) {
 26900               col.fill(0);
 26901               col(j) = 1;
 26902               col._solve(A,indx);
 26903               cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
 26905           } else { // SVD-based inverse computation
 26906             CImg<Tfloat> U(width,width), S(1,width), V(width,width);
 26907             SVD(U,S,V,false);
 26908             U.transpose();
 26909             cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
 26910             S.diagonal();
 26911             *this = V*S*U;
 26914 #endif
 26916       return *this;
 26919     CImg<Tfloat> get_invert(const bool use_LU=true) const {
 26920       return CImg<Tfloat>(*this,false).invert(use_LU);
 26923     //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
 26924     CImg<T>& pseudoinvert() {
 26925       return get_pseudoinvert().transfer_to(*this);
 26928     CImg<Tfloat> get_pseudoinvert() const {
 26929       CImg<Tfloat> U, S, V;
 26930       SVD(U,S,V);
 26931       cimg_forX(V,x) {
 26932         const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
 26933         cimg_forY(V,y) V(x,y)*=invs;
 26935       return V*U.transpose();
 26938     //! Compute the cross product between two 3d vectors.
 26939     template<typename t>
 26940     CImg<T>& cross(const CImg<t>& img) {
 26941       if (width!=1 || height<3 || img.width!=1 || img.height<3)
 26942         throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
 26943                                     pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
 26944       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
 26945       (*this)[0] = (T)(y*img[2]-z*img[1]);
 26946       (*this)[1] = (T)(z*img[0]-x*img[2]);
 26947       (*this)[2] = (T)(x*img[1]-y*img[0]);
 26948       return *this;
 26951     template<typename t>
 26952     CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
 26953       typedef typename cimg::superset<T,t>::type Tt;
 26954       return CImg<Tt>(*this).cross(img);
 26957     //! Solve a linear system AX=B where B=*this.
 26958     template<typename t>
 26959     CImg<T>& solve(const CImg<t>& A) {
 26960       if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
 26961         throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
 26962                                     "size of given matrix A is (%u,%u,%u,%u).",
 26963                                     pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
 26965       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 26966       if (A.width==A.height) {
 26967 #ifdef cimg_use_lapack
 26968         char TRANS='N';
 26969         int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
 26970         Ttfloat
 26971           *lapA = new Ttfloat[N*N],
 26972           *lapB = new Ttfloat[N],
 26973           *WORK = new Ttfloat[LWORK];
 26974         cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
 26975         cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
 26976         cimg::getrf(N,lapA,IPIV,INFO);
 26977         if (INFO)
 26978           cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
 26979                      pixel_type(),INFO);
 26980         if (!INFO) {
 26981           cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
 26982           if (INFO)
 26983             cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
 26984                        pixel_type(),INFO);
 26986         if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
 26987         delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
 26988 #else
 26989         CImg<Ttfloat> lu(A);
 26990         CImg<Ttfloat> indx;
 26991         bool d;
 26992         lu._LU(indx,d);
 26993         _solve(lu,indx);
 26994 #endif
 26995       } else assign(A.get_pseudoinvert()*(*this));
 26996       return *this;
 26999     template<typename t>
 27000     CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
 27001       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 27002       return CImg<Ttfloat>(*this,false).solve(A);
 27005     template<typename t, typename ti>
 27006     CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
 27007       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 27008       const int N = size();
 27009       int ii = -1;
 27010       Ttfloat sum;
 27011       for (int i=0; i<N; ++i) {
 27012         const int ip = (int)indx[i];
 27013         Ttfloat sum = (*this)(ip);
 27014         (*this)(ip) = (*this)(i);
 27015         if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
 27016         else if (sum!=0) ii=i;
 27017         (*this)(i) = (T)sum;
 27019       { for (int i=N-1; i>=0; --i) {
 27020         sum = (*this)(i);
 27021         for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
 27022         (*this)(i) = (T)(sum/A(i,i));
 27023       }}
 27024       return *this;
 27027     //! Solve a linear system AX=B where B=*this and A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ].
 27028     // (Use the Thomas Algorithm).
 27029     template<typename t>
 27030     CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
 27031       const int siz = (int)size();
 27032       if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
 27033         throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
 27034       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 27035       CImg<Ttfloat> nc(siz);
 27036       const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
 27037       T *ptrnc = nc.data, *ptrd = data;
 27038       const Ttfloat valb0 = (Ttfloat)*(ptrb++);
 27039       *ptrnc = *(ptrc++)/valb0;
 27040       Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
 27041       for (int i = 1; i<siz; ++i) {
 27042         const Ttfloat
 27043           vala = (Tfloat)*(ptra++),
 27044           id = 1/(*(ptrb++) - *(ptrnc++)*vala);
 27045         *ptrnc = *(ptrc++)*id;
 27046         vald = ((*ptrd-=vala*vald)*=id);
 27047         ++ptrd;
 27049       vald = *(--ptrd);
 27050       for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
 27051       return *this;
 27054     template<typename t>
 27055     CImg<typename cimg::superset2<T,t,float>::type> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
 27056       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 27057       return CImg<Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
 27060     //! Sort values of a vector and get permutations.
 27061     template<typename t>
 27062     CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
 27063       if (is_empty()) permutations.assign();
 27064       else {
 27065         if (permutations.size()!=size()) permutations.assign(size());
 27066         cimg_foroff(permutations,off) permutations[off] = (t)off;
 27067         _quicksort(0,size()-1,permutations,increasing);
 27069       return *this;
 27072     template<typename t>
 27073     CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
 27074       return (+*this).sort(permutations,increasing);
 27077     // Sort image values.
 27078     CImg<T>& sort(const bool increasing=true) {
 27079       CImg<T> foo;
 27080       return sort(foo,increasing);
 27083     CImg<T> get_sort(const bool increasing=true) const {
 27084       return (+*this).sort(increasing);
 27087     template<typename t>
 27088     CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
 27089       if (min<max) {
 27090         const int mid = (min+max)/2;
 27091         if (increasing) {
 27092           if ((*this)[min]>(*this)[mid]) {
 27093             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 27094           if ((*this)[mid]>(*this)[max]) {
 27095             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 27096           if ((*this)[min]>(*this)[mid]) {
 27097             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 27098         } else {
 27099           if ((*this)[min]<(*this)[mid]) {
 27100             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 27101           if ((*this)[mid]<(*this)[max]) {
 27102             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 27103           if ((*this)[min]<(*this)[mid]) {
 27104             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 27106         if (max-min>=3) {
 27107           const T pivot = (*this)[mid];
 27108           int i = min, j = max;
 27109           if (increasing) {
 27110             do {
 27111               while ((*this)[i]<pivot) ++i;
 27112               while ((*this)[j]>pivot) --j;
 27113               if (i<=j) {
 27114                 cimg::swap((*this)[i],(*this)[j]);
 27115                 cimg::swap(permutations[i++],permutations[j--]);
 27117             } while (i<=j);
 27118           } else {
 27119             do {
 27120               while ((*this)[i]>pivot) ++i;
 27121               while ((*this)[j]<pivot) --j;
 27122               if (i<=j) {
 27123                 cimg::swap((*this)[i],(*this)[j]);
 27124                 cimg::swap(permutations[i++],permutations[j--]);
 27126             } while (i<=j);
 27128           if (min<j) _quicksort(min,j,permutations,increasing);
 27129           if (i<max) _quicksort(i,max,permutations,increasing);
 27132       return *this;
 27135     //! Get a permutation of the pixels.
 27136     template<typename t>
 27137     CImg<T>& permute(const CImg<t>& permutation) {
 27138       return get_permute(permutation).transfer_to(*this);
 27141     template<typename t>
 27142     CImg<T> get_permute(const CImg<t>& permutation) const {
 27143       if (permutation.size()!=size())
 27144         throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
 27145                                     "have different sizes.",
 27146                                     pixel_type(),width,height,depth,dim,data,
 27147                                     permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
 27148       CImg<T> res(width,height,depth,dim);
 27149       const t *p = permutation.ptr(permutation.size());
 27150       cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
 27151       return res;
 27154     //! Compute the SVD of a general matrix.
 27155     template<typename t>
 27156     const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
 27157                        const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
 27158       if (is_empty()) { U.assign(); S.assign(); V.assign(); }
 27159       else {
 27160         U = *this;
 27161         if (lambda!=0) {
 27162           const unsigned int delta = cimg::min(U.width,U.height);
 27163           for (unsigned int i=0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
 27165         if (S.size()<width) S.assign(1,width);
 27166         if (V.width<width || V.height<height) V.assign(width,width);
 27167         CImg<t> rv1(width);
 27168         t anorm = 0, c, f, g = 0, h, s, scale = 0;
 27169         int l = 0, nm = 0;
 27171         cimg_forX(U,i) {
 27172           l = i+1; rv1[i] = scale*g; g = s = scale = 0;
 27173           if (i<dimy()) {
 27174             for (int k=i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
 27175             if (scale) {
 27176               for (int k=i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
 27177               f = U(i,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
 27178               for (int j=l; j<dimx(); ++j) {
 27179                 s = 0; for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
 27180                 f = s/h;
 27181                 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
 27183               { for (int k=i; k<dimy(); ++k) U(i,k)*= scale; }
 27186           S[i]=scale*g;
 27188           g = s = scale = 0;
 27189           if (i<dimy() && i!=dimx()-1) {
 27190             for (int k=l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
 27191             if (scale) {
 27192               for (int k=l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
 27193               f = U(l,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
 27194               { for (int k=l; k<dimx(); ++k) rv1[k]=U(k,i)/h; }
 27195               for (int j=l; j<dimy(); ++j) {
 27196                 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
 27197                 { for (int k=l; k<dimx(); ++k) U(k,j)+= s*rv1[k]; }
 27199               { for (int k=l; k<dimx(); ++k) U(k,i)*= scale; }
 27202           anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
 27205         { for (int i=dimx()-1; i>=0; --i) {
 27206           if (i<dimx()-1) {
 27207             if (g) {
 27208               { for (int j=l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; }
 27209               for (int j=l; j<dimx(); ++j) {
 27210                 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
 27211                 { for (int k=l; k<dimx(); ++k) V(j,k)+= s*V(i,k); }
 27214             for (int j=l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
 27216           V(i,i) = (t)1.0; g = rv1[i]; l = i;
 27220         { for (int i=cimg::min(dimx(),dimy())-1; i>=0; --i) {
 27221           l = i+1; g = S[i];
 27222           for (int j=l; j<dimx(); ++j) U(j,i) = 0;
 27223           if (g) {
 27224             g = 1/g;
 27225             for (int j=l; j<dimx(); ++j) {
 27226               s = 0; for (int k=l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
 27227               f = (s/U(i,i))*g;
 27228               { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
 27230             { for (int j=i; j<dimy(); ++j) U(i,j)*= g; }
 27231           } else for (int j=i; j<dimy(); ++j) U(i,j) = 0;
 27232           ++U(i,i);
 27236         for (int k=dimx()-1; k>=0; --k) {
 27237           for (unsigned int its=0; its<max_iter; ++its) {
 27238             bool flag = true;
 27239             for (l=k; l>=1; --l) {
 27240               nm = l-1;
 27241               if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
 27242               if ((cimg::abs(S[nm])+anorm)==anorm) break;
 27244             if (flag) {
 27245               c = 0; s = 1;
 27246               for (int i=l; i<=k; ++i) {
 27247                 f = s*rv1[i]; rv1[i] = c*rv1[i];
 27248                 if ((cimg::abs(f)+anorm)==anorm) break;
 27249                 g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
 27250                 cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; }
 27253             const t z = S[k];
 27254             if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
 27255             nm = k-1;
 27256             t x = S[l], y = S[nm];
 27257             g = rv1[nm]; h = rv1[k];
 27258             f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
 27259             g = (t)cimg::_pythagore(f,1.0);
 27260             f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
 27261             c = s = 1;
 27262             for (int j=l; j<=nm; ++j) {
 27263               const int i = j+1;
 27264               g = rv1[i]; h = s*g; g = c*g;
 27265               t y = S[i];
 27266               t z = (t)cimg::_pythagore(f,h);
 27267               rv1[j] = z; c = f/z; s = h/z;
 27268               f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
 27269               cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; }
 27270               z = (t)cimg::_pythagore(f,h); S[j] = z;
 27271               if (z) { z = 1/z; c = f*z; s = h*z; }
 27272               f = c*g+s*y; x = c*y-s*g;
 27273               { cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; }}
 27275             rv1[l] = 0; rv1[k]=f; S[k]=x;
 27279         if (sorting) {
 27280           CImg<intT> permutations(width);
 27281           CImg<t> tmp(width);
 27282           S.sort(permutations,false);
 27283           cimg_forY(U,k) {
 27284             cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
 27285             cimg_std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
 27287           { cimg_forY(V,k) {
 27288             cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
 27289             cimg_std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
 27290           }}
 27293     return *this;
 27296     //! Compute the SVD of a general matrix.
 27297     template<typename t>
 27298     const CImg<T>& SVD(CImgList<t>& USV) const {
 27299       if (USV.size<3) USV.assign(3);
 27300       return SVD(USV[0],USV[1],USV[2]);
 27303     //! Compute the SVD of a general matrix.
 27304     CImgList<Tfloat> get_SVD(const bool sorting=true) const {
 27305       CImgList<Tfloat> res(3);
 27306       SVD(res[0],res[1],res[2],sorting);
 27307       return res;
 27310     // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
 27311     template<typename t>
 27312     CImg<T>& _LU(CImg<t>& indx, bool& d) {
 27313       const int N = dimx();
 27314       int imax = 0;
 27315       CImg<Tfloat> vv(N);
 27316       indx.assign(N);
 27317       d = true;
 27318       cimg_forX(*this,i) {
 27319         Tfloat vmax = 0;
 27320         cimg_forX(*this,j) {
 27321           const Tfloat tmp = cimg::abs((*this)(j,i));
 27322           if (tmp>vmax) vmax = tmp;
 27324         if (vmax==0) { indx.fill(0); return fill(0); }
 27325         vv[i] = 1/vmax;
 27327       cimg_forX(*this,j) {
 27328         for (int i=0; i<j; ++i) {
 27329           Tfloat sum=(*this)(j,i);
 27330           for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
 27331           (*this)(j,i) = (T)sum;
 27333         Tfloat vmax = 0;
 27334         { for (int i=j; i<dimx(); ++i) {
 27335           Tfloat sum=(*this)(j,i);
 27336           for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
 27337           (*this)(j,i) = (T)sum;
 27338           const Tfloat tmp = vv[i]*cimg::abs(sum);
 27339           if (tmp>=vmax) { vmax=tmp; imax=i; }
 27340         }}
 27341         if (j!=imax) {
 27342           cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
 27343           d =!d;
 27344           vv[imax] = vv[j];
 27346         indx[j] = (t)imax;
 27347         if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
 27348         if (j<N) {
 27349           const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
 27350           for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
 27353       return *this;
 27356     //! Compute the eigenvalues and eigenvectors of a matrix.
 27357     template<typename t>
 27358     const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
 27359       if (is_empty()) { val.assign(); vec.assign(); }
 27360       else {
 27361         if (width!=height || depth>1 || dim>1)
 27362           throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
 27363                                       pixel_type(),width,height,depth,dim,data);
 27364         if (val.size()<width) val.assign(1,width);
 27365         if (vec.size()<width*width) vec.assign(width,width);
 27366         switch (width) {
 27367         case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
 27368         case 2 : {
 27369           const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
 27370           double f = e*e-4*(a*d-b*c);
 27371           if (f<0)
 27372             cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
 27373                        pixel_type());
 27374           f = cimg_std::sqrt(f);
 27375           const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
 27376           const double theta1 = cimg_std::atan2(l2-a,b), theta2 = cimg_std::atan2(l1-a,b);
 27377           val[0]=(t)l2;
 27378           val[1]=(t)l1;
 27379           vec(0,0) = (t)cimg_std::cos(theta1);
 27380           vec(0,1) = (t)cimg_std::sin(theta1);
 27381           vec(1,0) = (t)cimg_std::cos(theta2);
 27382           vec(1,1) = (t)cimg_std::sin(theta2);
 27383         } break;
 27384         default :
 27385           throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
 27386                                       "to 2x2 matrices (given is %ux%u)",
 27387                                       pixel_type(),width,height);
 27390       return *this;
 27393     //! Compute the eigenvalues and eigenvectors of a matrix.
 27394     CImgList<Tfloat> get_eigen() const {
 27395       CImgList<Tfloat> res(2);
 27396       eigen(res[0],res[1]);
 27397       return res;
 27400     //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
 27401     template<typename t>
 27402     const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
 27403       if (is_empty()) { val.assign(); vec.assign(); }
 27404       else {
 27405 #ifdef cimg_use_lapack
 27406         char JOB = 'V', UPLO = 'U';
 27407         int N = width, LWORK = 4*N, INFO;
 27408         Tfloat
 27409           *lapA = new Tfloat[N*N],
 27410           *lapW = new Tfloat[N],
 27411           *WORK = new Tfloat[LWORK];
 27412         cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
 27413         cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
 27414         if (INFO)
 27415           cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
 27416                      pixel_type(),INFO);
 27417         val.assign(1,N);
 27418         vec.assign(N,N);
 27419         if (!INFO) {
 27420           cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
 27421           cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
 27422         } else { val.fill(0); vec.fill(0); }
 27423         delete[] lapA; delete[] lapW; delete[] WORK;
 27424 #else
 27425         if (width!=height || depth>1 || dim>1)
 27426           throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
 27427                                       pixel_type(),width,height,depth,dim,data);
 27428         val.assign(1,width);
 27429         if (vec.data) vec.assign(width,width);
 27430         if (width<3) return eigen(val,vec);
 27431         CImg<t> V(width,width);
 27432         SVD(vec,val,V,false);
 27433         bool ambiguous = false;
 27434         float eig = 0;
 27435         cimg_forY(val,p) {       // check for ambiguous cases.
 27436           if (val[p]>eig) eig = (float)val[p];
 27437           t scal = 0;
 27438           cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
 27439           if (cimg::abs(scal)<0.9f) ambiguous = true;
 27440           if (scal<0) val[p] = -val[p];
 27442         if (ambiguous) {
 27443           (eig*=2)++;
 27444           SVD(vec,val,V,false,40,eig);
 27445           val-=eig;
 27447         CImg<intT> permutations(width);  // sort eigenvalues in decreasing order
 27448         CImg<t> tmp(width);
 27449         val.sort(permutations,false);
 27450         cimg_forY(vec,k) {
 27451           cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
 27452           cimg_std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
 27454 #endif
 27456       return *this;
 27459     //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
 27460     CImgList<Tfloat> get_symmetric_eigen() const {
 27461       CImgList<Tfloat> res(2);
 27462       symmetric_eigen(res[0],res[1]);
 27463       return res;
 27466     //@}
 27467     //-------------------
 27468     //
 27469     //! \name Display
 27470     //@{
 27471     //-------------------
 27473     //! Display an image into a CImgDisplay window.
 27474     const CImg<T>& display(CImgDisplay& disp) const {
 27475       disp.display(*this);
 27476       return *this;
 27479     //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
 27480     const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
 27481       return _display(disp,0,display_info);
 27484     //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
 27485     const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
 27486       CImgDisplay disp;
 27487       return _display(disp,title,display_info);
 27490     const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
 27491       if (is_empty())
 27492         throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
 27493                                     pixel_type(),width,height,depth,dim,data);
 27494       unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
 27495       int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
 27496       float frametiming = 5;
 27498       char ntitle[256] = { 0 };
 27499       if (!disp) {
 27500         if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 27501         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 27503       cimg_std::strncpy(ntitle,disp.title,255);
 27504       if (display_info) print(ntitle);
 27506       CImg<T> zoom;
 27507       for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
 27508         if (reset_view) {
 27509           XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
 27510           x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
 27511           oldw = disp.width; oldh = disp.height;
 27512           reset_view = false;
 27514         if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
 27515         else zoom = get_crop(x0,y0,z0,x1,y1,z1);
 27517         const unsigned int
 27518           dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
 27519           tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
 27520         if (resize_disp) {
 27521           const unsigned int
 27522             ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
 27523             dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
 27524             imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
 27525           disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
 27526           resize_disp = false;
 27528         oldw = tw; oldh = th;
 27530         bool
 27531           go_up = false, go_down = false, go_left = false, go_right = false,
 27532           go_inc = false, go_dec = false, go_in = false, go_out = false,
 27533           go_in_center = false;
 27534         const CImg<T>& visu = zoom?zoom:*this;
 27535         const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
 27536         if (disp.wheel) {
 27537           if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
 27538           else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
 27539           else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
 27540           else mkey = 0;
 27541           disp.wheel = 0;
 27542         } else mkey = 0;
 27543         const int
 27544           sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
 27545           sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
 27546         if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
 27547           x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
 27548           if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
 27549           resize_disp = true;
 27550         } else switch (key = disp.key) {
 27551         case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
 27552         case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
 27553           const unsigned int
 27554             w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
 27555             h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
 27556           disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
 27557           for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
 27558             if (disp.is_resized) disp.resize();
 27559             if (!timer) {
 27560               visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
 27561               if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
 27563             if (++timer>(unsigned int)frametiming) timer = 0;
 27564             if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
 27565             switch (key = disp.key) {
 27566             case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 27567             case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
 27568             case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
 27569             case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 27570               disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 27571                                          CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
 27572               disp.key = key = 0;
 27573             } break;
 27574             case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 27575               disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
 27576               disp.key = key = 0;
 27577             } break;
 27578             case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 27579               disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
 27580               disp.key = key = 0;
 27581             } break;
 27582             case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 27583               disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
 27584               disp.key = key = 0;
 27585             } break;
 27587             frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
 27588             disp.wait(20);
 27590           const unsigned int
 27591             w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
 27592             h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
 27593           disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
 27594           key = disp.key = disp.button = disp.wheel = 0;
 27595         } break;
 27596         case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
 27597         case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
 27598         case cimg::keyPADSUB : go_out = true; key = 0; break;
 27599         case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
 27600         case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
 27601         case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
 27602         case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
 27603         case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
 27604         case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
 27605         case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
 27606         case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
 27607         case cimg::keyPAGEUP : go_inc = true; key = 0; break;
 27608         case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
 27610         if (go_in) {
 27611           const int
 27612             mx = go_in_center?disp.dimx()/2:disp.mouse_x,
 27613             my = go_in_center?disp.dimy()/2:disp.mouse_y,
 27614             mX = mx*(width+(depth>1?depth:0))/disp.width,
 27615             mY = my*(height+(depth>1?depth:0))/disp.height;
 27616           int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
 27617           if (mX<dimx() && mY<dimy())  { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
 27618           if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
 27619           if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
 27620           if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
 27621           if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
 27622           if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
 27624         if (go_out) {
 27625           const int
 27626             deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
 27627             ndeltax = deltax?deltax:(width>1?1:0),
 27628             ndeltay = deltay?deltay:(height>1?1:0),
 27629             ndeltaz = deltaz?deltaz:(depth>1?1:0);
 27630           x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
 27631           x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
 27632           if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
 27633           if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
 27634           if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
 27635           if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
 27636           if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
 27637           if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
 27639         if (go_left) {
 27640           const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 27641           if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
 27642           else { x1-=x0; x0 = 0; }
 27644         if (go_right) {
 27645           const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 27646           if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
 27647           else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
 27649         if (go_up) {
 27650           const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 27651           if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
 27652           else { y1-=y0; y0 = 0; }
 27654         if (go_down) {
 27655           const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 27656           if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
 27657           else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
 27659         if (go_inc) {
 27660           const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 27661           if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
 27662           else { z1-=z0; z0 = 0; }
 27664         if (go_dec) {
 27665           const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 27666           if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
 27667           else { z0+=(depth-1-z1); z1 = depth-1; }
 27670       disp.key = key;
 27671       return *this;
 27674     //! Simple interface to select a shape from an image.
 27675     /**
 27676        \param selection  Array of 6 values containing the selection result
 27677        \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
 27678        \param disp       Display window used to make the selection
 27679        \param XYZ        Initial XYZ position (for volumetric images only)
 27680        \param color      Color of the shape selector.
 27681     **/
 27682     CImg<T>& select(CImgDisplay &disp,
 27683                     const int select_type=2, unsigned int *const XYZ=0,
 27684                     const unsigned char *const color=0) {
 27685       return get_select(disp,select_type,XYZ,color).transfer_to(*this);
 27688     //! Simple interface to select a shape from an image.
 27689     CImg<T>& select(const char *const title,
 27690                     const int select_type=2, unsigned int *const XYZ=0,
 27691                     const unsigned char *const color=0) {
 27692       return get_select(title,select_type,XYZ,color).transfer_to(*this);
 27695     //! Simple interface to select a shape from an image.
 27696     CImg<intT> get_select(CImgDisplay &disp,
 27697                           const int select_type=2, unsigned int *const XYZ=0,
 27698                           const unsigned char *const color=0) const {
 27699       return _get_select(disp,0,select_type,XYZ,color,0,0,0);
 27702     //! Simple interface to select a shape from an image.
 27703     CImg<intT> get_select(const char *const title,
 27704                           const int select_type=2, unsigned int *const XYZ=0,
 27705                           const unsigned char *const color=0) const {
 27706       CImgDisplay disp;
 27707       return _get_select(disp,title,select_type,XYZ,color,0,0,0);
 27710     CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
 27711                            const int coords_type, unsigned int *const XYZ,
 27712                            const unsigned char *const color,
 27713                            const int origX, const int origY, const int origZ) const {
 27714       if (is_empty())
 27715         throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
 27716                                     pixel_type(),width,height,depth,dim,data);
 27717       if (!disp) {
 27718         char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
 27719         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 27722       const unsigned int
 27723         old_normalization = disp.normalization,
 27724         hatch = 0x55555555;
 27726       bool old_is_resized = disp.is_resized;
 27727       disp.normalization = 0;
 27728       disp.show().key = 0;
 27730       unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
 27731       if (color) cimg_std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
 27733       int area = 0, clicked_area = 0, phase = 0,
 27734         X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
 27735         X1 =-1, Y1 = -1, Z1 = -1,
 27736         X = -1, Y = -1, Z = -1,
 27737         oX = X, oY = Y, oZ = Z;
 27738       unsigned int old_button = 0, key = 0;
 27740       bool shape_selected = false, text_down = false;
 27741       CImg<ucharT> visu, visu0;
 27742       char text[1024] = { 0 };
 27744       while (!key && !disp.is_closed && !shape_selected) {
 27746         // Handle mouse motion and selection
 27747         oX = X; oY = Y; oZ = Z;
 27748         int mx = disp.mouse_x, my = disp.mouse_y;
 27749         const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
 27751         area = 0;
 27752         if (mX<dimx() && mY<dimy())  { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
 27753         if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
 27754         if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
 27756         switch (key = disp.key) {
 27757         case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 27758         case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
 27759         case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
 27760         case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 27761           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 27762                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 27763           disp.key = key = 0;
 27764         } break;
 27765         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 27766           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 27767           disp.key = key = 0; visu0.assign();
 27768         } break;
 27769         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 27770           disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
 27771           disp.key = key = 0; visu0.assign();
 27772         } break;
 27773         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 27774           disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
 27775           disp.key = key = 0; visu0.assign();
 27776         } break;
 27777         case cimg::keyS : if (disp.is_keyCTRLLEFT) {
 27778           static unsigned int snap_number = 0;
 27779           char filename[32] = { 0 };
 27780           cimg_std::FILE *file;
 27781           do {
 27782             cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 27783             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 27784           } while (file);
 27785           if (visu0) {
 27786             visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
 27787             visu0.save(filename);
 27788             visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
 27790           disp.key = key = 0;
 27791         } break;
 27792         case cimg::keyO : if (disp.is_keyCTRLLEFT) {
 27793           static unsigned int snap_number = 0;
 27794           char filename[32] = { 0 };
 27795           cimg_std::FILE *file;
 27796           do {
 27797             cimg_std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
 27798             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 27799           } while (file);
 27800           visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
 27801           save(filename);
 27802           visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
 27803           disp.key = key = 0;
 27804         } break;
 27807         if (!area) mx = my = X = Y = Z = -1;
 27808         else {
 27809           if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
 27810           if (!(disp.button&1) && phase>=2) {
 27811             switch (clicked_area) {
 27812             case 1 : Z1 = Z; break;
 27813             case 2 : Y1 = Y; break;
 27814             case 3 : X1 = X; break;
 27817           if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
 27818           if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
 27819           if (disp.wheel) {
 27820             if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
 27821               switch (area) {
 27822               case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
 27823               case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
 27824               case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
 27826               disp.wheel = 0;
 27827             } else key = ~0U;
 27829           if ((disp.button&1)!=old_button) {
 27830             switch (phase++) {
 27831             case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
 27832             case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
 27834             old_button = disp.button&1;
 27836           if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
 27839         if (phase) {
 27840           if (!coords_type) shape_selected = phase?true:false;
 27841           else {
 27842             if (depth>1) shape_selected = (phase==3)?true:false;
 27843             else shape_selected = (phase==2)?true:false;
 27847         if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
 27848         if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
 27849         if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
 27850         if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
 27852         // Draw visualization image on the display
 27853         if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
 27854           if (!visu0) {
 27855             CImg<Tuchar> tmp, tmp0;
 27856             if (depth!=1) {
 27857               tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
 27858               tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
 27859             } else tmp = get_channels(0,cimg::min(2U,dim-1));
 27860             switch (old_normalization) {
 27861             case 0 : visu0 = tmp; break;
 27862             case 3 :
 27863               if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
 27864               else {
 27865                 const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
 27866                 visu0.assign(tmp.width,tmp.height,1,tmp.dim);
 27867                 unsigned char *ptrd = visu0.end();
 27868                 cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
 27869               } break;
 27870             default : visu0 = tmp.normalize(0,255);
 27872             visu0.resize(disp);
 27874           visu = visu0;
 27875           if (!color) {
 27876             if (visu.mean()<200) {
 27877               foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
 27878               background_color[0] = background_color[1] = background_color[2] = 0;
 27879             } else {
 27880               foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
 27881               background_color[0] = background_color[1] = background_color[2] = 255;
 27885           const int d = (depth>1)?depth:0;
 27886           if (phase) switch (coords_type) {
 27887           case 1 : {
 27888             const int
 27889               x0 = (int)((X0+0.5f)*disp.width/(width+d)),
 27890               y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
 27891               x1 = (int)((X1+0.5f)*disp.width/(width+d)),
 27892               y1 = (int)((Y1+0.5f)*disp.height/(height+d));
 27893             visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
 27894             if (d) {
 27895               const int
 27896                 zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
 27897                 zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
 27898                 zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
 27899                 zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
 27900               visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
 27901                 draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
 27903           } break;
 27904           case 2 : {
 27905             const int
 27906               x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
 27907               x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
 27908             visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
 27909             if (d) {
 27910               const int
 27911                 zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
 27912                 zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
 27913                 zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
 27914                 zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
 27915               visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
 27916               visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
 27918           } break;
 27919           case 3 : {
 27920             const int
 27921               x0 = X0*disp.width/(width+d),
 27922               y0 = Y0*disp.height/(height+d),
 27923               x1 = X1*disp.width/(width+d)-1,
 27924               y1 = Y1*disp.height/(height+d)-1;
 27925             visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.2f).
 27926               draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch);
 27927             if (d) {
 27928               const int
 27929                 zx0 = (int)((width+Z0)*disp.width/(width+d)),
 27930                 zy0 = (int)((height+Z0)*disp.height/(height+d)),
 27931                 zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
 27932                 zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
 27933               visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.2f).
 27934                 draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch).
 27935                 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.2f).
 27936                 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.6f,hatch);
 27938           } break;
 27939           } else {
 27940             const int
 27941               x0 = X*disp.width/(width+d),
 27942               y0 = Y*disp.height/(height+d),
 27943               x1 = (X+1)*disp.width/(width+d)-1,
 27944               y1 = (Y+1)*disp.height/(height+d)-1;
 27945             if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
 27948           if (my<12) text_down = true;
 27949           if (my>=visu.dimy()-11) text_down = false;
 27950           if (!coords_type || !phase) {
 27951             if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
 27952               if (depth>1) cimg_std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
 27953               else cimg_std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
 27954               char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
 27955               for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
 27956                 cimg_std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
 27957                 ctext = text + cimg::strlen(text);
 27958                 *(ctext++) = ' '; *ctext = '\0';
 27960               cimg_std::sprintf(text + cimg::strlen(text),"]");
 27962           } else switch (coords_type) {
 27963           case 1 : {
 27964             const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = cimg_std::sqrt(dX*dX+dY*dY+dZ*dZ);
 27965             if (depth>1) cimg_std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
 27966                                       origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
 27967             else cimg_std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
 27968                               origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
 27969           } break;
 27970           case 2 :
 27971             if (depth>1) cimg_std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
 27972                                       origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
 27973                                       origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
 27974                                       1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
 27975             else  cimg_std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
 27976                                origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
 27977                                1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
 27978             break;
 27979           default :
 27980             if (depth>1) cimg_std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
 27981                                       origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
 27982                                       1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
 27983             else  cimg_std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
 27984                                origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
 27987           if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
 27988           disp.display(visu).wait(25);
 27989         } else if (!shape_selected) disp.wait();
 27991         if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
 27994       // Return result
 27995       CImg<intT> res(1,6,1,1,-1);
 27996       if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
 27997       if (shape_selected) {
 27998         if (coords_type==2) {
 27999           if (X0>X1) cimg::swap(X0,X1);
 28000           if (Y0>Y1) cimg::swap(Y0,Y1);
 28001           if (Z0>Z1) cimg::swap(Z0,Z1);
 28003         if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
 28004         switch (coords_type) {
 28005         case 1 :
 28006         case 2 :  res[3] = X1; res[4] = Y1; res[5] = Z1;
 28007         default : res[0] = X0; res[1] = Y0; res[2] = Z0;
 28010       disp.button = 0;
 28011       disp.normalization = old_normalization;
 28012       disp.is_resized = old_is_resized;
 28013       if (key!=~0U) disp.key = key;
 28014       return res;
 28017     //! High-level interface for displaying a 3d object.
 28018     template<typename tp, typename tf, typename tc, typename to>
 28019     const CImg<T>& display_object3d(CImgDisplay& disp,
 28020                                     const CImg<tp>& points, const CImgList<tf>& primitives,
 28021                                     const CImgList<tc>& colors, const to& opacities,
 28022                                     const bool centering=true,
 28023                                     const int render_static=4, const int render_motion=1,
 28024                                     const bool double_sided=false, const float focale=500,
 28025                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28026                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28027       return _display_object3d(disp,0,points,points.width,primitives,colors,opacities,centering,render_static,
 28028                                render_motion,double_sided,focale,specular_light,specular_shine,
 28029                                display_axes,pose_matrix);
 28032     //! High-level interface for displaying a 3d object.
 28033     template<typename tp, typename tf, typename tc, typename to>
 28034     const CImg<T>& display_object3d(const char *const title,
 28035                                     const CImg<tp>& points, const CImgList<tf>& primitives,
 28036                                     const CImgList<tc>& colors, const to& opacities,
 28037                                     const bool centering=true,
 28038                                     const int render_static=4, const int render_motion=1,
 28039                                     const bool double_sided=false, const float focale=500,
 28040                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28041                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28042       CImgDisplay disp;
 28043       return _display_object3d(disp,title,points,points.width,primitives,colors,opacities,centering,render_static,
 28044                                render_motion,double_sided,focale,specular_light,specular_shine,
 28045                                display_axes,pose_matrix);
 28048     //! High-level interface for displaying a 3d object.
 28049     template<typename tp, typename tf, typename tc, typename to>
 28050     const CImg<T>& display_object3d(CImgDisplay& disp,
 28051                                     const CImgList<tp>& points, const CImgList<tf>& primitives,
 28052                                     const CImgList<tc>& colors, const to& opacities,
 28053                                     const bool centering=true,
 28054                                     const int render_static=4, const int render_motion=1,
 28055                                     const bool double_sided=false, const float focale=500,
 28056                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28057                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28058       return _display_object3d(disp,0,points,points.size,primitives,colors,opacities,centering,render_static,
 28059                                render_motion,double_sided,focale,specular_light,specular_shine,
 28060                                display_axes,pose_matrix);
 28063     //! High-level interface for displaying a 3d object.
 28064     template<typename tp, typename tf, typename tc, typename to>
 28065     const CImg<T>& display_object3d(const char *const title,
 28066                                     const CImgList<tp>& points, const CImgList<tf>& primitives,
 28067                                     const CImgList<tc>& colors, const to& opacities,
 28068                                     const bool centering=true,
 28069                                     const int render_static=4, const int render_motion=1,
 28070                                     const bool double_sided=false, const float focale=500,
 28071                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28072                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28073       CImgDisplay disp;
 28074       return _display_object3d(disp,title,points,points.size,primitives,colors,opacities,centering,render_static,
 28075                                render_motion,double_sided,focale,specular_light,specular_shine,
 28076                                display_axes,pose_matrix);
 28079    //! High-level interface for displaying a 3d object.
 28080     template<typename tp, typename tf, typename tc>
 28081     const CImg<T>& display_object3d(CImgDisplay &disp,
 28082                                     const tp& points, const CImgList<tf>& primitives,
 28083                                     const CImgList<tc>& colors,
 28084                                     const bool centering=true,
 28085                                     const int render_static=4, const int render_motion=1,
 28086                                     const bool double_sided=false, const float focale=500,
 28087                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28088                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28089       return display_object3d(disp,points,primitives,colors,CImg<floatT>(),centering,
 28090                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28091                               display_axes,pose_matrix);
 28094     //! High-level interface for displaying a 3d object.
 28095     template<typename tp, typename tf, typename tc>
 28096     const CImg<T>& display_object3d(const char *const title,
 28097                                     const tp& points, const CImgList<tf>& primitives,
 28098                                     const CImgList<tc>& colors,
 28099                                     const bool centering=true,
 28100                                     const int render_static=4, const int render_motion=1,
 28101                                     const bool double_sided=false, const float focale=500,
 28102                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28103                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28104       return display_object3d(title,points,primitives,colors,CImg<floatT>(),centering,
 28105                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28106                               display_axes,pose_matrix);
 28109     //! High-level interface for displaying a 3d object.
 28110     template<typename tp, typename tf>
 28111     const CImg<T>& display_object3d(CImgDisplay &disp,
 28112                                     const tp& points, const CImgList<tf>& primitives,
 28113                                     const bool centering=true,
 28114                                     const int render_static=4, const int render_motion=1,
 28115                                     const bool double_sided=false, const float focale=500,
 28116                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28117                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28118       return display_object3d(disp,points,primitives,CImgList<T>(),centering,
 28119                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28120                               display_axes,pose_matrix);
 28123     //! High-level interface for displaying a 3d object.
 28124     template<typename tp, typename tf>
 28125     const CImg<T>& display_object3d(const char *const title,
 28126                                     const tp& points, const CImgList<tf>& primitives,
 28127                                     const bool centering=true,
 28128                                     const int render_static=4, const int render_motion=1,
 28129                                     const bool double_sided=false, const float focale=500,
 28130                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28131                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28132       return display_object3d(title,points,primitives,CImgList<T>(),centering,
 28133                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28134                               display_axes,pose_matrix);
 28137     //! High-level interface for displaying a 3d object.
 28138     template<typename tp>
 28139     const CImg<T>& display_object3d(CImgDisplay &disp,
 28140                                     const tp& points,
 28141                                     const bool centering=true,
 28142                                     const int render_static=4, const int render_motion=1,
 28143                                     const bool double_sided=false, const float focale=500,
 28144                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28145                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28146       return display_object3d(disp,points,CImgList<uintT>(),centering,
 28147                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28148                               display_axes,pose_matrix);
 28151     //! High-level interface for displaying a 3d object.
 28152     template<typename tp>
 28153     const CImg<T>& display_object3d(const char *const title,
 28154                                     const tp& points,
 28155                                     const bool centering=true,
 28156                                     const int render_static=4, const int render_motion=1,
 28157                                     const bool double_sided=false, const float focale=500,
 28158                                     const float specular_light=0.2f, const float specular_shine=0.1f,
 28159                                     const bool display_axes=true, float *const pose_matrix=0) const {
 28160       return display_object3d(title,points,CImgList<uintT>(),centering,
 28161                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28162                               display_axes,pose_matrix);
 28165     T _display_object3d_at2(const int i, const int j) const {
 28166       return atXY(i,j,0,0,0);
 28169     template<typename tp, typename tf, typename tc, typename to>
 28170     const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
 28171                                      const tp& points, const unsigned int Npoints,
 28172                                      const CImgList<tf>& primitives,
 28173                                      const CImgList<tc>& colors, const to& opacities,
 28174                                      const bool centering,
 28175                                      const int render_static, const int render_motion,
 28176                                      const bool double_sided, const float focale,
 28177                                      const float specular_light, const float specular_shine,
 28178                                      const bool display_axes, float *const pose_matrix) const {
 28180       // Check input arguments
 28181       if (!points || !Npoints)
 28182         throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
 28183                                     pixel_type());
 28184       if (is_empty()) {
 28185         if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
 28186                     _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
 28187                                      render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28188                                      display_axes,pose_matrix);
 28189         else return CImg<T>(cimg_fitscreen(640,480,1),1,colors[0].size(),0).
 28190                _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
 28191                                  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28192                                  display_axes,pose_matrix);
 28194       if (!primitives) {
 28195         CImgList<tf> nprimitives(Npoints,1,1,1,1);
 28196         cimglist_for(nprimitives,l) nprimitives(l,0) = l;
 28197         return _display_object3d(disp,title,points,Npoints,nprimitives,colors,opacities,
 28198                                  centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 28199                                  display_axes,pose_matrix);
 28201       if (!disp) {
 28202         char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
 28203         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 28206       CImgList<tc> _colors;
 28207       if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
 28208       const CImgList<tc> &ncolors = colors?colors:_colors;
 28210       // Init 3D objects and compute object statistics
 28211       CImg<floatT>
 28212         pose, rot_mat, zbuffer,
 28213         centered_points = centering?CImg<floatT>(Npoints,3):CImg<floatT>(),
 28214         rotated_points(Npoints,3),
 28215         bbox_points, rotated_bbox_points,
 28216         axes_points, rotated_axes_points,
 28217         bbox_opacities, axes_opacities;
 28218       CImgList<uintT> bbox_primitives, axes_primitives;
 28219       CImgList<T> bbox_colors, bbox_colors2, axes_colors;
 28220       float dx = 0, dy = 0, dz = 0, ratio = 1;
 28222       T minval = (T)0, maxval = (T)255;
 28223       if (disp.normalization && colors) {
 28224         minval = colors.minmax(maxval);
 28225         if (minval==maxval) { minval = (T)0; maxval = (T)255; }
 28227       const float meanval = (float)mean();
 28228       bool color_model = true;
 28229       if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
 28230       const CImg<T>
 28231         background_color(1,1,1,dim,color_model?minval:maxval),
 28232         foreground_color(1,1,1,dim,color_model?maxval:minval);
 28234       float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
 28235       for (unsigned int i = 0; i<Npoints; ++i) {
 28236         const float
 28237           x = points._display_object3d_at2(i,0),
 28238           y = points._display_object3d_at2(i,1),
 28239           z = points._display_object3d_at2(i,2);
 28240         if (x<xm) xm = x;
 28241         if (x>xM) xM = x;
 28242         if (y<ym) ym = y;
 28243         if (y>yM) yM = y;
 28244         if (z<zm) zm = z;
 28245         if (z>zM) zM = z;
 28247       const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
 28249       if (display_axes) {
 28250         rotated_axes_points = axes_points.assign(7,3,1,1,
 28251                                                  0,20,0,0,22,-6,-6,
 28252                                                  0,0,20,0,-6,22,-6,
 28253                                                  0,0,0,20,0,0,22);
 28254         axes_opacities.assign(3,1,1,1,1);
 28255         axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
 28256         axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
 28259       // Begin user interaction loop
 28260       CImg<T> visu0(*this), visu;
 28261       bool init = true, clicked = false, redraw = true;
 28262       unsigned int key = 0;
 28263       int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
 28264       disp.show().flush();
 28266       while (!disp.is_closed && !key) {
 28268         // Init object position and scale if necessary
 28269         if (init) {
 28270           ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
 28271           dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
 28272           if (centering) {
 28273             cimg_forX(centered_points,l) {
 28274               centered_points(l,0) = (float)((points(l,0) - dx)*ratio);
 28275               centered_points(l,1) = (float)((points(l,1) - dy)*ratio);
 28276               centered_points(l,2) = (float)((points(l,2) - dz)*ratio);
 28280           if (render_static<0 || render_motion<0) {
 28281             rotated_bbox_points = bbox_points.assign(8,3,1,1,
 28282                                                      xm,xM,xM,xm,xm,xM,xM,xm,
 28283                                                      ym,ym,yM,yM,ym,ym,yM,yM,
 28284                                                      zm,zm,zm,zm,zM,zM,zM,zM);
 28285             bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6);
 28286             bbox_colors.assign(6,dim,1,1,1,background_color[0]);
 28287             bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
 28288             bbox_opacities.assign(bbox_colors.size,1,1,1,0.3f);
 28291           if (!pose) {
 28292             if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
 28293             else pose = CImg<floatT>::identity_matrix(4);
 28295           init = false;
 28296           redraw = true;
 28299         // Rotate and Draw 3D object
 28300         if (redraw) {
 28301           const float
 28302             r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
 28303             r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
 28304             r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
 28305           if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
 28306             if (centering) cimg_forX(centered_points,l) {
 28307                 const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2);
 28308                 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
 28309                 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
 28310                 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
 28311               } else for (unsigned int l = 0; l<Npoints; ++l) {
 28312                 const float
 28313                   x = (float)points._display_object3d_at2(l,0),
 28314                   y = (float)points._display_object3d_at2(l,1),
 28315                   z = (float)points._display_object3d_at2(l,2);
 28316                 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
 28317                 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
 28318                 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
 28320           } else {
 28321             if (!centering) cimg_forX(bbox_points,l) {
 28322                 const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2);
 28323                 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
 28324                 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
 28325                 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
 28326               } else cimg_forX(bbox_points,l) {
 28327                 const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio;
 28328                 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
 28329                 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
 28330                 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
 28334           // Draw object
 28335           visu = visu0;
 28336           if ((clicked && render_motion<0) || (!clicked && render_static<0))
 28337             visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
 28338               draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors2,1,false,focale);
 28339           else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
 28340                                   rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 28341                                   double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 28342                                   (!clicked && render_static>0)?zbuffer.fill(0).ptr():0);
 28344           // Draw axes
 28345           if (display_axes) {
 28346             const float Xaxes = 25, Yaxes = visu.height - 35.0f;
 28347             cimg_forX(axes_points,l) {
 28348               const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2);
 28349               rotated_axes_points(l,0) = r00*x + r10*y + r20*z;
 28350               rotated_axes_points(l,1) = r01*x + r11*y + r21*z;
 28351               rotated_axes_points(l,2) = r02*x + r12*y + r22*z;
 28353             axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f;
 28354             axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
 28355             axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
 28356             visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale).
 28357               draw_text((int)(Xaxes+rotated_axes_points(4,0)),
 28358                         (int)(Yaxes+rotated_axes_points(4,1)),
 28359                         "X",axes_colors[0].data,0,axes_opacities(0,0),11).
 28360               draw_text((int)(Xaxes+rotated_axes_points(5,0)),
 28361                         (int)(Yaxes+rotated_axes_points(5,1)),
 28362                         "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
 28363               draw_text((int)(Xaxes+rotated_axes_points(6,0)),
 28364                         (int)(Yaxes+rotated_axes_points(6,1)),
 28365                         "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
 28367           visu.display(disp);
 28368           if (!clicked || render_motion==render_static) redraw = false;
 28371         // Handle user interaction
 28372         disp.wait();
 28373         if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
 28374           redraw = true;
 28375           if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
 28376           else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
 28377           if (disp.button&1) {
 28378             const float
 28379               R = 0.45f*cimg::min(disp.width,disp.height),
 28380               R2 = R*R,
 28381               u0 = (float)(x0-disp.dimx()/2),
 28382               v0 = (float)(y0-disp.dimy()/2),
 28383               u1 = (float)(x1-disp.dimx()/2),
 28384               v1 = (float)(y1-disp.dimy()/2),
 28385               n0 = (float)cimg_std::sqrt(u0*u0+v0*v0),
 28386               n1 = (float)cimg_std::sqrt(u1*u1+v1*v1),
 28387               nu0 = n0>R?(u0*R/n0):u0,
 28388               nv0 = n0>R?(v0*R/n0):v0,
 28389               nw0 = (float)cimg_std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
 28390               nu1 = n1>R?(u1*R/n1):u1,
 28391               nv1 = n1>R?(v1*R/n1):v1,
 28392               nw1 = (float)cimg_std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
 28393               u = nv0*nw1-nw0*nv1,
 28394               v = nw0*nu1-nu0*nw1,
 28395               w = nv0*nu1-nu0*nv1,
 28396               n = (float)cimg_std::sqrt(u*u+v*v+w*w),
 28397               alpha = (float)cimg_std::asin(n/R2);
 28398             rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
 28399             rot_mat *= pose.get_crop(0,0,2,2);
 28400             pose.draw_image(rot_mat);
 28401             x0=x1; y0=y1;
 28403           if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
 28404           if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
 28405           if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
 28406           if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
 28407         } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
 28409         switch (key = disp.key) {
 28410         case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 28411         case cimg::keyD: if (disp.is_keyCTRLLEFT) {
 28412           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 28413                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 28414           disp.key = key = 0;
 28415         } break;
 28416         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 28417           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 28418           disp.key = key = 0;
 28419         } break;
 28420         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 28421           disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
 28422           disp.key = key = 0;
 28423         } break;
 28424         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 28425           disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 28426           disp.key = key = 0;
 28427         } break;
 28428         case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
 28429           if (zbuffer) zbuffer.assign();
 28430           else zbuffer.assign(disp.width,disp.height);
 28431           disp.key = key = 0; redraw = true;
 28432         } break;
 28433         case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
 28434           static unsigned int snap_number = 0;
 28435           char filename[32] = { 0 };
 28436           cimg_std::FILE *file;
 28437           do {
 28438             cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 28439             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 28440           } while (file);
 28441           (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
 28442           visu.save(filename);
 28443           visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 28444           disp.key = key = 0;
 28445         } break;
 28446         case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
 28447           static unsigned int snap_number = 0;
 28448           char filename[32] = { 0 };
 28449           cimg_std::FILE *file;
 28450           do {
 28451             cimg_std::sprintf(filename,"CImg_%.4u.off",snap_number++);
 28452             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 28453           } while (file);
 28454           visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
 28455           points.save_off(filename,primitives,ncolors);
 28456           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 28457           disp.key = key = 0;
 28458         } break;
 28459 #ifdef cimg_use_board
 28460         case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
 28461           static unsigned int snap_number = 0;
 28462           char filename[32] = { 0 };
 28463           cimg_std::FILE *file;
 28464           do {
 28465             cimg_std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
 28466             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 28467           } while (file);
 28468           visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
 28469           BoardLib::Board board;
 28470           (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 28471                                 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 28472                                 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 28473                                 zbuffer.fill(0).ptr());
 28474           board.saveEPS(filename);
 28475           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 28476           disp.key = key = 0;
 28477         } break;
 28478         case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
 28479           static unsigned int snap_number = 0;
 28480           char filename[32] = { 0 };
 28481           cimg_std::FILE *file;
 28482           do {
 28483             cimg_std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
 28484             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 28485           } while (file);
 28486           visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
 28487           BoardLib::Board board;
 28488           (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 28489                                 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 28490                                 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 28491                                 zbuffer.fill(0).ptr());
 28492           board.saveSVG(filename);
 28493           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 28494           disp.key = key = 0;
 28495         } break;
 28496 #endif
 28498         if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
 28500       if (pose_matrix) cimg_std::memcpy(pose_matrix,pose.data,16*sizeof(float));
 28501       disp.button = 0;
 28502       disp.key = key;
 28503       return *this;
 28506     //! High-level interface for displaying a graph.
 28507     const CImg<T>& display_graph(CImgDisplay &disp,
 28508                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
 28509                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
 28510                                  const char *const labely=0, const double ymin=0, const double ymax=0) const {
 28511       if (is_empty())
 28512         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 28513                                     pixel_type(),width,height,depth,dim,data);
 28514       const unsigned int siz = width*height*depth, onormalization = disp.normalization;
 28515       if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
 28516       disp.show().flush().normalization = 0;
 28517       double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
 28518       if (nxmin==nxmax) { nxmin = 0; nxmax = siz - 1.0; }
 28519       int x0 = 0, x1 = size()/dimv()-1, key = 0;
 28521       for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
 28522         if (reset_view) { x0 = 0; x1 = size()/dimv()-1; y0 = ymin; y1 = ymax; reset_view = false; }
 28523         CImg<T> zoom(x1-x0+1,1,1,dimv());
 28524         cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
 28526         if (y0==y1) y0 = zoom.minmax(y1);
 28527         if (y0==y1) { --y0; ++y1; }
 28528         const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
 28529                                                            labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + x1*(nxmax-nxmin)/siz,
 28530                                                            labely,y0,y1);
 28532         const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
 28533         if (selection[0]>=0 && selection[2]>=0) {
 28534           x1 = x0 + selection[2];
 28535           x0 += selection[0];
 28536           if (x0==x1) reset_view = true;
 28537           if (selection[1]>=0 && selection[3]>=0) {
 28538             y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
 28539             y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
 28541         } else {
 28542           bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
 28543           switch (key = disp.key) {
 28544           case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
 28545           case cimg::keyPADADD : go_in = true; key = 0; break;
 28546           case cimg::keyPADSUB : go_out = true; key = 0; break;
 28547           case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
 28548           case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
 28549           case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
 28550           case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
 28551           case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
 28552           case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
 28553           case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
 28554           case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
 28556           if (disp.wheel) go_out = !(go_in = disp.wheel>0);
 28558           if (go_in) {
 28559             const int
 28560               xsiz = x1 - x0,
 28561               mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
 28562               cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
 28563             if (x1-x0>4) {
 28564               x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
 28565               if (disp.is_keyCTRLLEFT) {
 28566                 const double
 28567                   ysiz = y1 - y0,
 28568                   my = (mouse_y-16)*ysiz/(disp.dimy()-32),
 28569                   cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
 28570                 y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
 28571               } else y0 = y1 = 0;
 28574           if (go_out) {
 28575             const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
 28576             x0-=ndeltax; x1+=ndeltax;
 28577             if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
 28578             if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
 28579             if (disp.is_keyCTRLLEFT) {
 28580               const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
 28581               y0-=ndeltay; y1+=ndeltay;
 28584           if (go_left) {
 28585             const int delta = (x1-x0)/5, ndelta = delta?delta:1;
 28586             if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
 28587             else { x1-=x0; x0 = 0; }
 28588             go_left = false;
 28590           if (go_right) {
 28591             const int delta = (x1-x0)/5, ndelta = delta?delta:1;
 28592             if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
 28593             else { x0+=(siz-1-x1); x1 = siz-1; }
 28594             go_right = false;
 28596           if (go_up) {
 28597             const double delta = (y1-y0)/10, ndelta = delta?delta:1;
 28598             y0+=ndelta; y1+=ndelta;
 28599             go_up = false;
 28601           if (go_down) {
 28602             const double delta = (y1-y0)/10, ndelta = delta?delta:1;
 28603             y0-=ndelta; y1-=ndelta;
 28604             go_down = false;
 28608       disp.normalization = onormalization;
 28609       return *this;
 28612     //! High-level interface for displaying a graph.
 28613     const CImg<T>& display_graph(const char *const title=0,
 28614                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
 28615                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
 28616                                  const char *const labely=0, const double ymin=0, const double ymax=0) const {
 28617       if (is_empty())
 28618         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 28619                                     pixel_type(),width,height,depth,dim,data);
 28620       char ntitle[64] = { 0 }; if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 28621       CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
 28622       return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
 28625     //! Select sub-graph in a graph.
 28626     CImg<intT> get_select_graph(CImgDisplay &disp,
 28627                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
 28628                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
 28629                                 const char *const labely=0, const double ymin=0, const double ymax=0) const {
 28630       if (is_empty())
 28631         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 28632                                     pixel_type(),width,height,depth,dim,data);
 28633       const unsigned int siz = width*height*depth, onormalization = disp.normalization;
 28634       if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
 28635       disp.show().key = disp.normalization = disp.button = disp.wheel = 0;  // Must keep 'key' field unchanged.
 28636       double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
 28637       if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
 28638       if (nymin==nymax) { --nymin; ++nymax; }
 28639       if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
 28641       const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
 28642       const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
 28643       static unsigned int odimv = 0;
 28644       static CImg<ucharT> palette;
 28645       if (odimv!=dim) {
 28646         odimv = dim;
 28647         palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
 28648         if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
 28649         else {
 28650           palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
 28651           if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
 28652           if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
 28656       CImg<ucharT> visu0, visu, graph, text, axes;
 28657       const unsigned int whz = width*height*depth;
 28658       int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
 28659       char message[1024] = { 0 };
 28660       unsigned int okey = 0, obutton = 0;
 28661       CImg_3x3(I,unsigned char);
 28663       for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
 28664         const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
 28665         const unsigned int key = disp.key, button = disp.button;
 28667         // Generate graph representation.
 28668         if (!visu0) {
 28669           visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
 28670           const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
 28671           if (gdimx>0 && gdimy>0) {
 28672             graph.assign(gdimx,gdimy,1,3,255);
 28673             graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
 28674             cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
 28675                                                 plot_type,vertex_type,nymax,nymin);
 28677             axes.assign(gdimx,gdimy,1,1,0);
 28678             const float
 28679               dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
 28680               px = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0),
 28681               py = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0);
 28682             const CImg<Tdouble>
 28683               seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
 28684               seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
 28685             axes.draw_axis(seqx,seqy,white);
 28686             if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
 28687             if (nymax<0) axes.draw_axis(seqx,0,gray);
 28688             if (nxmin>0) axes.draw_axis(0,seqy,gray);
 28689             if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
 28691             cimg_for3x3(axes,x,y,0,0,I)
 28692               if (Icc) {
 28693                 if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
 28694                 else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
 28696               else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
 28698             visu0.draw_image(16,16,graph);
 28699             visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
 28700               draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
 28701           } else graph.assign();
 28702           text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
 28703           visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
 28704           text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
 28705           visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
 28706           visu.assign();
 28709         // Generate and display current view.
 28710         if (!visu) {
 28711           visu.assign(visu0);
 28712           if (graph && x0>=0 && x1>=0) {
 28713             const int
 28714               nx0 = x0<=x1?x0:x1,
 28715               nx1 = x0<=x1?x1:x0,
 28716               ny0 = y0<=y1?y0:y1,
 28717               ny1 = y0<=y1?y1:y0,
 28718               sx0 = 16 + nx0*(visu.dimx()-32)/whz,
 28719               sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
 28720               sy0 = 16 + ny0,
 28721               sy1 = 16 + ny1;
 28723             if (y0>=0 && y1>=0)
 28724               visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
 28725             else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
 28726                    draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
 28727                    draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
 28729           if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
 28730             if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
 28731             const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
 28732             const double cx = nxmin + x*(nxmax-nxmin)/whz;
 28733             if (dim>=7)
 28734               cimg_std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
 28735                            (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
 28736                            (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
 28737             else {
 28738               cimg_std::sprintf(message,"Value[%g] = ( ",cx);
 28739               cimg_forV(*this,k) cimg_std::sprintf(message+cimg::strlen(message),"%g ",(double)(*this)(x,0,0,k));
 28740               cimg_std::sprintf(message+cimg::strlen(message),")");
 28742             if (x0>=0 && x1>=0) {
 28743               const int
 28744                  nx0 = x0<=x1?x0:x1,
 28745                  nx1 = x0<=x1?x1:x0,
 28746                  ny0 = y0<=y1?y0:y1,
 28747                  ny1 = y0<=y1?y1:y0;
 28748               const double
 28749                  cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
 28750                  cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
 28751                  cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
 28752                  cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
 28753               if (y0>=0 && y1>=0)
 28754                 cimg_std::sprintf(message+cimg::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
 28755               else
 28756                 cimg_std::sprintf(message+cimg::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
 28758             text.assign().draw_text(0,0,message,white,ngray,1);
 28759             visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
 28761           visu.display(disp);
 28764         // Test keys.
 28765         switch (okey = key) {
 28766         case cimg::keyCTRLLEFT : okey = 0; break;
 28767         case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 28768           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 28769                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 28770           disp.key = okey = 0;
 28771         } break;
 28772         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 28773           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 28774           disp.key = okey = 0;
 28775         } break;
 28776         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 28777           disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
 28778           disp.key = okey = 0;
 28779         } break;
 28780         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 28781           disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 28782           disp.key = okey = 0;
 28783         } break;
 28784         case cimg::keyS : if (disp.is_keyCTRLLEFT) {
 28785           static unsigned int snap_number = 0;
 28786           if (visu || visu0) {
 28787             CImg<ucharT> &screen = visu?visu:visu0;
 28788             char filename[32] = { 0 };
 28789             cimg_std::FILE *file;
 28790             do {
 28791               cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 28792               if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 28793             } while (file);
 28794             (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
 28795             screen.save(filename);
 28796             screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
 28798           disp.key = okey = 0;
 28799         } break;
 28802         // Handle mouse motion and mouse buttons
 28803         if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
 28804           visu.assign();
 28805           if (disp.mouse_x>=0 && disp.mouse_y>=0) {
 28806             const int
 28807               mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
 28808               cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
 28809               my = mouse_y-16,
 28810               cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
 28811             if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
 28812             else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
 28813             else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
 28814           } else if (!button && obutton) selected = true;
 28815           obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
 28817         if (disp.is_resized) { disp.resize(false); visu0.assign(); }
 28818         if (visu && visu0) disp.wait();
 28820       disp.normalization = onormalization;
 28821       if (x1<x0) cimg::swap(x0,x1);
 28822       if (y1<y0) cimg::swap(y0,y1);
 28823       disp.key = okey;
 28824       return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
 28827     //@}
 28828     //---------------------------
 28829     //
 28830     //! \name Image File Loading
 28831     //@{
 28832     //---------------------------
 28834     //! Load an image from a file.
 28835     /**
 28836        \param filename is the name of the image file to load.
 28837        \note The extension of \c filename defines the file format. If no filename
 28838        extension is provided, CImg<T>::get_load() will try to load a .cimg file.
 28839     **/
 28840     CImg<T>& load(const char *const filename) {
 28841       if (!filename)
 28842         throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
 28843                                     pixel_type());
 28844       const char *ext = cimg::split_filename(filename);
 28845       const unsigned int odebug = cimg::exception_mode();
 28846       cimg::exception_mode() = 0;
 28847       assign();
 28848       try {
 28849 #ifdef cimg_load_plugin
 28850         cimg_load_plugin(filename);
 28851 #endif
 28852 #ifdef cimg_load_plugin1
 28853         cimg_load_plugin1(filename);
 28854 #endif
 28855 #ifdef cimg_load_plugin2
 28856         cimg_load_plugin2(filename);
 28857 #endif
 28858 #ifdef cimg_load_plugin3
 28859         cimg_load_plugin3(filename);
 28860 #endif
 28861 #ifdef cimg_load_plugin4
 28862         cimg_load_plugin4(filename);
 28863 #endif
 28864 #ifdef cimg_load_plugin5
 28865         cimg_load_plugin5(filename);
 28866 #endif
 28867 #ifdef cimg_load_plugin6
 28868         cimg_load_plugin6(filename);
 28869 #endif
 28870 #ifdef cimg_load_plugin7
 28871         cimg_load_plugin7(filename);
 28872 #endif
 28873 #ifdef cimg_load_plugin8
 28874         cimg_load_plugin8(filename);
 28875 #endif
 28876         // ASCII formats
 28877         if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
 28878         if (!cimg::strcasecmp(ext,"dlm") ||
 28879             !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
 28881         // 2D binary formats
 28882         if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
 28883         if (!cimg::strcasecmp(ext,"jpg") ||
 28884             !cimg::strcasecmp(ext,"jpeg") ||
 28885             !cimg::strcasecmp(ext,"jpe") ||
 28886             !cimg::strcasecmp(ext,"jfif") ||
 28887             !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
 28888         if (!cimg::strcasecmp(ext,"png")) load_png(filename);
 28889         if (!cimg::strcasecmp(ext,"ppm") ||
 28890             !cimg::strcasecmp(ext,"pgm") ||
 28891             !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
 28892         if (!cimg::strcasecmp(ext,"tif") ||
 28893             !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
 28894         if (!cimg::strcasecmp(ext,"cr2") ||
 28895             !cimg::strcasecmp(ext,"crw") ||
 28896             !cimg::strcasecmp(ext,"dcr") ||
 28897             !cimg::strcasecmp(ext,"mrw") ||
 28898             !cimg::strcasecmp(ext,"nef") ||
 28899             !cimg::strcasecmp(ext,"orf") ||
 28900             !cimg::strcasecmp(ext,"pix") ||
 28901             !cimg::strcasecmp(ext,"ptx") ||
 28902             !cimg::strcasecmp(ext,"raf") ||
 28903             !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
 28905         // 3D binary formats
 28906         if (!cimg::strcasecmp(ext,"dcm") ||
 28907             !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
 28908         if (!cimg::strcasecmp(ext,"hdr") ||
 28909             !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
 28910         if (!cimg::strcasecmp(ext,"par") ||
 28911             !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
 28912         if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
 28913         if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
 28914         if (!cimg::strcasecmp(ext,"cimg") ||
 28915             !cimg::strcasecmp(ext,"cimgz") ||
 28916             *ext=='\0')  return load_cimg(filename);
 28918         // Archive files
 28919         if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
 28921         // Image sequences
 28922         if (!cimg::strcasecmp(ext,"avi") ||
 28923             !cimg::strcasecmp(ext,"mov") ||
 28924             !cimg::strcasecmp(ext,"asf") ||
 28925             !cimg::strcasecmp(ext,"divx") ||
 28926             !cimg::strcasecmp(ext,"flv") ||
 28927             !cimg::strcasecmp(ext,"mpg") ||
 28928             !cimg::strcasecmp(ext,"m1v") ||
 28929             !cimg::strcasecmp(ext,"m2v") ||
 28930             !cimg::strcasecmp(ext,"m4v") ||
 28931             !cimg::strcasecmp(ext,"mjp") ||
 28932             !cimg::strcasecmp(ext,"mkv") ||
 28933             !cimg::strcasecmp(ext,"mpe") ||
 28934             !cimg::strcasecmp(ext,"movie") ||
 28935             !cimg::strcasecmp(ext,"ogm") ||
 28936             !cimg::strcasecmp(ext,"qt") ||
 28937             !cimg::strcasecmp(ext,"rm") ||
 28938             !cimg::strcasecmp(ext,"vob") ||
 28939             !cimg::strcasecmp(ext,"wmv") ||
 28940             !cimg::strcasecmp(ext,"xvid") ||
 28941             !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
 28942         if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
 28943       } catch (CImgException& e) {
 28944         if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
 28945           cimg::exception_mode() = odebug;
 28946           throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
 28947         } else try {
 28948           const char *const ftype = cimg::file_type(0,filename);
 28949           assign();
 28950           if (!cimg::strcmp(ftype,"pnm")) load_pnm(filename);
 28951           if (!cimg::strcmp(ftype,"bmp")) load_bmp(filename);
 28952           if (!cimg::strcmp(ftype,"jpeg")) load_jpeg(filename);
 28953           if (!cimg::strcmp(ftype,"pan")) load_pandore(filename);
 28954           if (!cimg::strcmp(ftype,"png")) load_png(filename);
 28955           if (!cimg::strcmp(ftype,"tiff")) load_tiff(filename);
 28956           if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
 28957         } catch (CImgException&) {
 28958           try {
 28959             load_other(filename);
 28960           } catch (CImgException&) {
 28961             assign();
 28965       cimg::exception_mode() = odebug;
 28966       if (is_empty())
 28967         throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
 28968       return *this;
 28971     static CImg<T> get_load(const char *const filename) {
 28972       return CImg<T>().load(filename);
 28975     //! Load an image from an ASCII file.
 28976     CImg<T>& load_ascii(const char *const filename) {
 28977       return _load_ascii(0,filename);
 28980     static CImg<T> get_load_ascii(const char *const filename) {
 28981       return CImg<T>().load_ascii(filename);
 28984     //! Load an image from an ASCII file.
 28985     CImg<T>& load_ascii(cimg_std::FILE *const file) {
 28986       return _load_ascii(file,0);
 28989     static CImg<T> get_load_ascii(cimg_std::FILE *const file) {
 28990       return CImg<T>().load_ascii(file);
 28993     CImg<T>& _load_ascii(cimg_std::FILE *const file, const char *const filename) {
 28994       if (!filename && !file)
 28995         throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
 28996                                     pixel_type());
 28997       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 28998       char line[256] = { 0 };
 28999       int err = cimg_std::fscanf(nfile,"%*[^0-9]%255[^\n]",line);
 29000       unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
 29001       cimg_std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
 29002       err = cimg_std::fscanf(nfile,"%*[^0-9.+-]");
 29003       if (!dx || !dy || !dz || !dv) {
 29004         if (!file) cimg::fclose(nfile);
 29005         throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
 29006                               pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
 29008       assign(dx,dy,dz,dv);
 29009       const unsigned long siz = size();
 29010       double val;
 29011       T *ptr = data;
 29012       for (err = 1, off = 0; off<siz && err==1; ++off) {
 29013         err = cimg_std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
 29014         *(ptr++) = (T)val;
 29016       if (err!=1)
 29017         cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
 29018                    pixel_type(),filename?filename:"(FILE*)",off-1,siz);
 29019       if (!file) cimg::fclose(nfile);
 29020       return *this;
 29023     //! Load an image from a DLM file.
 29024     CImg<T>& load_dlm(const char *const filename) {
 29025       return _load_dlm(0,filename);
 29028     static CImg<T> get_load_dlm(const char *const filename) {
 29029       return CImg<T>().load_dlm(filename);
 29032     //! Load an image from a DLM file.
 29033     CImg<T>& load_dlm(cimg_std::FILE *const file) {
 29034       return _load_dlm(file,0);
 29037     static CImg<T> get_load_dlm(cimg_std::FILE *const file) {
 29038       return CImg<T>().load_dlm(file);
 29041     CImg<T>& _load_dlm(cimg_std::FILE *const file, const char *const filename) {
 29042       if (!filename && !file)
 29043         throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
 29044                                     pixel_type());
 29045       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
 29046       assign(256,256);
 29047       char c, delimiter[256] = { 0 }, tmp[256];
 29048       unsigned int cdx = 0, dx = 0, dy = 0;
 29049       int oerr = 0, err;
 29050       double val;
 29051       while ((err = cimg_std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
 29052         oerr = err;
 29053         if (err>0) (*this)(cdx++,dy) = (T)val;
 29054         if (cdx>=width) resize(width+256,1,1,1,0);
 29055         c = 0; if (!cimg_std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
 29056           dx = cimg::max(cdx,dx);
 29057           ++dy;
 29058           if (dy>=height) resize(width,height+256,1,1,0);
 29059           cdx = 0;
 29062       if (cdx && oerr==1) { dx=cdx; ++dy; }
 29063       if (!dx || !dy) {
 29064         if (!file) cimg::fclose(nfile);
 29065         throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file, specified image dimensions are (%u,%u).",
 29066                               pixel_type(),filename?filename:"(FILE*)",dx,dy);
 29068       resize(dx,dy,1,1,0);
 29069       if (!file) cimg::fclose(nfile);
 29070       return *this;
 29073     //! Load an image from a BMP file.
 29074     CImg<T>& load_bmp(const char *const filename) {
 29075       return _load_bmp(0,filename);
 29078     static CImg<T> get_load_bmp(const char *const filename) {
 29079       return CImg<T>().load_bmp(filename);
 29082     //! Load an image from a BMP file.
 29083     CImg<T>& load_bmp(cimg_std::FILE *const file) {
 29084       return _load_bmp(file,0);
 29087     static CImg<T> get_load_bmp(cimg_std::FILE *const file) {
 29088       return CImg<T>().load_bmp(file);
 29091     CImg<T>& _load_bmp(cimg_std::FILE *const file, const char *const filename) {
 29092       if (!filename && !file)
 29093         throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
 29094                                     pixel_type());
 29095       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 29096       unsigned char header[64];
 29097       cimg::fread(header,54,nfile);
 29098       if (header[0]!='B' || header[1]!='M') {
 29099         if (!file) cimg::fclose(nfile);
 29100         throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
 29101                               pixel_type(),filename?filename:"(FILE*)");
 29103       assign();
 29105       // Read header and pixel buffer
 29106       int
 29107         file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
 29108         offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
 29109         dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
 29110         dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
 29111         compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
 29112         nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
 29113         bpp = header[0x1C] + (header[0x1D]<<8),
 29114         *palette = 0;
 29115       const int
 29116         dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
 29117         align = (4-dx_bytes%4)%4,
 29118         buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
 29120       if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
 29121       if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
 29122       const int xoffset = offset-54-4*nb_colors;
 29123       if (xoffset>0) cimg_std::fseek(nfile,xoffset,SEEK_CUR);
 29124       unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
 29125       cimg::fread(buffer,buf_size,nfile);
 29126       if (!file) cimg::fclose(nfile);
 29128       // Decompress buffer (if necessary)
 29129       if (compression) {
 29130         delete[] buffer;
 29131         if (file) {
 29132           throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
 29133                                 pixel_type());
 29134         } else return load_other(filename);
 29137       // Read pixel data
 29138       assign(dx,cimg::abs(dy),1,3);
 29139       switch (bpp) {
 29140       case 1 : { // Monochrome
 29141         for (int y=height-1; y>=0; --y) {
 29142           unsigned char mask = 0x80, val = 0;
 29143           cimg_forX(*this,x) {
 29144             if (mask==0x80) val = *(ptrs++);
 29145             const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
 29146             (*this)(x,y,2) = (T)*(col++);
 29147             (*this)(x,y,1) = (T)*(col++);
 29148             (*this)(x,y,0) = (T)*(col++);
 29149             mask = cimg::ror(mask);
 29150           } ptrs+=align; }
 29151       } break;
 29152       case 4 : { // 16 colors
 29153         for (int y=height-1; y>=0; --y) {
 29154           unsigned char mask = 0xF0, val = 0;
 29155           cimg_forX(*this,x) {
 29156             if (mask==0xF0) val = *(ptrs++);
 29157             const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
 29158             unsigned char *col = (unsigned char*)(palette+color);
 29159             (*this)(x,y,2) = (T)*(col++);
 29160             (*this)(x,y,1) = (T)*(col++);
 29161             (*this)(x,y,0) = (T)*(col++);
 29162             mask = cimg::ror(mask,4);
 29163           } ptrs+=align; }
 29164       } break;
 29165       case 8 : { //  256 colors
 29166         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 29167           const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
 29168           (*this)(x,y,2) = (T)*(col++);
 29169           (*this)(x,y,1) = (T)*(col++);
 29170           (*this)(x,y,0) = (T)*(col++);
 29171         } ptrs+=align; }
 29172       } break;
 29173       case 16 : { // 16 bits colors
 29174         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 29175           const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
 29176           const unsigned short col = (unsigned short)(c1|(c2<<8));
 29177           (*this)(x,y,2) = (T)(col&0x1F);
 29178           (*this)(x,y,1) = (T)((col>>5)&0x1F);
 29179           (*this)(x,y,0) = (T)((col>>10)&0x1F);
 29180         } ptrs+=align; }
 29181       } break;
 29182       case 24 : { // 24 bits colors
 29183         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 29184           (*this)(x,y,2) = (T)*(ptrs++);
 29185           (*this)(x,y,1) = (T)*(ptrs++);
 29186           (*this)(x,y,0) = (T)*(ptrs++);
 29187         } ptrs+=align; }
 29188       } break;
 29189       case 32 : { // 32 bits colors
 29190         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 29191           (*this)(x,y,2) = (T)*(ptrs++);
 29192           (*this)(x,y,1) = (T)*(ptrs++);
 29193           (*this)(x,y,0) = (T)*(ptrs++);
 29194           ++ptrs;
 29195         } ptrs+=align; }
 29196       } break;
 29198       if (palette) delete[] palette;
 29199       delete[] buffer;
 29200       if (dy<0) mirror('y');
 29201       return *this;
 29204     //! Load an image from a JPEG file.
 29205     CImg<T>& load_jpeg(const char *const filename) {
 29206       return _load_jpeg(0,filename);
 29209     static CImg<T> get_load_jpeg(const char *const filename) {
 29210       return CImg<T>().load_jpeg(filename);
 29213     //! Load an image from a JPEG file.
 29214     CImg<T>& load_jpeg(cimg_std::FILE *const file) {
 29215       return _load_jpeg(file,0);
 29218     static CImg<T> get_load_jpeg(cimg_std::FILE *const file) {
 29219       return CImg<T>().load_jpeg(file);
 29222     CImg<T>& _load_jpeg(cimg_std::FILE *const file, const char *const filename) {
 29223       if (!filename && !file)
 29224         throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
 29225                                     pixel_type());
 29226 #ifndef cimg_use_jpeg
 29227       if (file)
 29228         throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
 29229                               pixel_type());
 29230       else return load_other(filename);
 29231 #else
 29232       struct jpeg_decompress_struct cinfo;
 29233       struct jpeg_error_mgr jerr;
 29234       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 29236       cinfo.err = jpeg_std_error(&jerr);
 29237       jpeg_create_decompress(&cinfo);
 29238       jpeg_stdio_src(&cinfo,nfile);
 29239       jpeg_read_header(&cinfo,TRUE);
 29240       jpeg_start_decompress(&cinfo);
 29242       if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
 29243         cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
 29244                    pixel_type(),filename?filename:"(FILE*)");
 29245         if (!file) return load_other(filename);
 29246         else {
 29247           if (!file) cimg::fclose(nfile);
 29248           throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
 29249                                 pixel_type(),filename?filename:"(FILE*)");
 29253       const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
 29254       unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
 29255       JSAMPROW row_pointer[1];
 29256       while (cinfo.output_scanline < cinfo.output_height) {
 29257         row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
 29258         jpeg_read_scanlines(&cinfo,row_pointer,1);
 29260       jpeg_finish_decompress(&cinfo);
 29261       jpeg_destroy_decompress(&cinfo);
 29262       if (!file) cimg::fclose(nfile);
 29264       assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
 29265       switch (dim) {
 29266       case 1 : {
 29267         T *ptr_g = data;
 29268         cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
 29269       } break;
 29270       case 3 : {
 29271         T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 29272         cimg_forXY(*this,x,y) {
 29273           *(ptr_r++) = (T)*(buf2++);
 29274           *(ptr_g++) = (T)*(buf2++);
 29275           *(ptr_b++) = (T)*(buf2++);
 29277       } break;
 29278       case 4 : {
 29279         T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
 29280           *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
 29281         cimg_forXY(*this,x,y) {
 29282           *(ptr_r++) = (T)*(buf2++);
 29283           *(ptr_g++) = (T)*(buf2++);
 29284           *(ptr_b++) = (T)*(buf2++);
 29285           *(ptr_a++) = (T)*(buf2++);
 29287       } break;
 29289       delete[] buf;
 29290       return *this;
 29291 #endif
 29294     //! Load an image from a file, using Magick++ library.
 29295     // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
 29296     //   This is experimental code, not much tested, use with care.
 29297     CImg<T>& load_magick(const char *const filename) {
 29298       if (!filename)
 29299         throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
 29300                                     pixel_type());
 29301 #ifdef cimg_use_magick
 29302       Magick::Image image(filename);
 29303       const unsigned int W = image.size().width(), H = image.size().height();
 29304       switch (image.type()) {
 29305       case Magick::PaletteMatteType :
 29306       case Magick::TrueColorMatteType :
 29307       case Magick::ColorSeparationType : {
 29308         assign(W,H,1,4);
 29309         T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2), *adata = ptr(0,0,0,3);
 29310         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 29311         for (unsigned int off = W*H; off; --off) {
 29312           *(rdata++) = (T)(pixels->red);
 29313           *(gdata++) = (T)(pixels->green);
 29314           *(bdata++) = (T)(pixels->blue);
 29315           *(adata++) = (T)(pixels->opacity);
 29316           ++pixels;
 29318       } break;
 29319       case Magick::PaletteType :
 29320       case Magick::TrueColorType : {
 29321         assign(W,H,1,3);
 29322         T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 29323         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 29324         for (unsigned int off = W*H; off; --off) {
 29325           *(rdata++) = (T)(pixels->red);
 29326           *(gdata++) = (T)(pixels->green);
 29327           *(bdata++) = (T)(pixels->blue);
 29328           ++pixels;
 29330       } break;
 29331       case Magick::GrayscaleMatteType : {
 29332         assign(W,H,1,2);
 29333         T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
 29334         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 29335         for (unsigned int off = W*H; off; --off) {
 29336           *(data++) = (T)(pixels->red);
 29337           *(adata++) = (T)(pixels->opacity);
 29338           ++pixels;
 29340       } break;
 29341       default : {
 29342         assign(W,H,1,1);
 29343         T *data = ptr(0,0,0,0);
 29344         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 29345         for (unsigned int off = W*H; off; --off) {
 29346           *(data++) = (T)(pixels->red);
 29347           ++pixels;
 29351 #else
 29352       throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
 29353                             pixel_type(),filename);
 29354 #endif
 29355       return *this;
 29358     static CImg<T> get_load_magick(const char *const filename) {
 29359       return CImg<T>().load_magick(filename);
 29362     //! Load an image from a PNG file.
 29363     CImg<T>& load_png(const char *const filename) {
 29364       return _load_png(0,filename);
 29367     static CImg<T> get_load_png(const char *const filename) {
 29368       return CImg<T>().load_png(filename);
 29371     //! Load an image from a PNG file.
 29372     CImg<T>& load_png(cimg_std::FILE *const file) {
 29373       return _load_png(file,0);
 29376     static CImg<T> get_load_png(cimg_std::FILE *const file) {
 29377       return CImg<T>().load_png(file);
 29380     // (Note : Most of this function has been written by Eric Fausett)
 29381     CImg<T>& _load_png(cimg_std::FILE *const file, const char *const filename) {
 29382       if (!filename && !file)
 29383         throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
 29384                                     pixel_type());
 29385 #ifndef cimg_use_png
 29386       if (file)
 29387         throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
 29388                               pixel_type());
 29389       else return load_other(filename);
 29390 #else
 29391       // Open file and check for PNG validity
 29392       const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 29393       cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
 29395       unsigned char pngCheck[8];
 29396       cimg::fread(pngCheck,8,(cimg_std::FILE*)nfile);
 29397       if (png_sig_cmp(pngCheck,0,8)) {
 29398         if (!file) cimg::fclose(nfile);
 29399         throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
 29400                               pixel_type(),nfilename?nfilename:"(FILE*)");
 29403       // Setup PNG structures for read
 29404       png_voidp user_error_ptr = 0;
 29405       png_error_ptr user_error_fn = 0, user_warning_fn = 0;
 29406       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
 29407       if (!png_ptr) {
 29408         if (!file) cimg::fclose(nfile);
 29409         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
 29410                               pixel_type(),nfilename?nfilename:"(FILE*)");
 29412       png_infop info_ptr = png_create_info_struct(png_ptr);
 29413       if (!info_ptr) {
 29414         if (!file) cimg::fclose(nfile);
 29415         png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
 29416         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
 29417                               pixel_type(),nfilename?nfilename:"(FILE*)");
 29419       png_infop end_info = png_create_info_struct(png_ptr);
 29420       if (!end_info) {
 29421         if (!file) cimg::fclose(nfile);
 29422         png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
 29423         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
 29424                               pixel_type(),nfilename?nfilename:"(FILE*)");
 29427       // Error handling callback for png file reading
 29428       if (setjmp(png_jmpbuf(png_ptr))) {
 29429         if (!file) cimg::fclose((cimg_std::FILE*)nfile);
 29430         png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
 29431         throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
 29432                               pixel_type(),nfilename?nfilename:"(FILE*)");
 29434       png_init_io(png_ptr, nfile);
 29435       png_set_sig_bytes(png_ptr, 8);
 29437       // Get PNG Header Info up to data block
 29438       png_read_info(png_ptr,info_ptr);
 29439       png_uint_32 W, H;
 29440       int bit_depth, color_type, interlace_type;
 29441       png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
 29442       int new_bit_depth = bit_depth;
 29443       int new_color_type = color_type;
 29445       // Transforms to unify image data
 29446       if (new_color_type == PNG_COLOR_TYPE_PALETTE){
 29447         png_set_palette_to_rgb(png_ptr);
 29448         new_color_type -= PNG_COLOR_MASK_PALETTE;
 29449         new_bit_depth = 8;
 29451       if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
 29452         png_set_gray_1_2_4_to_8(png_ptr);
 29453         new_bit_depth = 8;
 29455       if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
 29456         png_set_tRNS_to_alpha(png_ptr);
 29457       if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
 29458         png_set_gray_to_rgb(png_ptr);
 29459         new_color_type |= PNG_COLOR_MASK_COLOR;
 29461       if (new_color_type == PNG_COLOR_TYPE_RGB)
 29462         png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
 29463       png_read_update_info(png_ptr,info_ptr);
 29464       if (!(new_bit_depth==8 || new_bit_depth==16)) {
 29465         if (!file) cimg::fclose(nfile);
 29466         png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
 29467         throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
 29468                               pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
 29470       const int byte_depth = new_bit_depth>>3;
 29472       // Allocate Memory for Image Read
 29473       png_bytep *imgData = new png_bytep[H];
 29474       for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
 29475       png_read_image(png_ptr,imgData);
 29476       png_read_end(png_ptr,end_info);
 29478       // Read pixel data
 29479       if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
 29480         if (!file) cimg::fclose(nfile);
 29481         png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
 29482         throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
 29483                               pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
 29485       const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
 29486       assign(W,H,1,no_alpha_channel?3:4);
 29487       T *ptr1 = ptr(0,0,0,0), *ptr2 = ptr(0,0,0,1), *ptr3 = ptr(0,0,0,2), *ptr4 = ptr(0,0,0,3);
 29488       switch (new_bit_depth) {
 29489       case 8 : {
 29490         cimg_forY(*this,y){
 29491           const unsigned char *ptrs = (unsigned char*)imgData[y];
 29492           cimg_forX(*this,x){
 29493             *(ptr1++) = (T)*(ptrs++);
 29494             *(ptr2++) = (T)*(ptrs++);
 29495             *(ptr3++) = (T)*(ptrs++);
 29496             if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
 29499       } break;
 29500       case 16 : {
 29501         cimg_forY(*this,y){
 29502           const unsigned short *ptrs = (unsigned short*)(imgData[y]);
 29503           if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
 29504           cimg_forX(*this,x){
 29505             *(ptr1++) = (T)*(ptrs++);
 29506             *(ptr2++) = (T)*(ptrs++);
 29507             *(ptr3++) = (T)*(ptrs++);
 29508             if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
 29511       } break;
 29513       png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 29515       // Deallocate Image Read Memory
 29516       cimg_forY(*this,n) delete[] imgData[n];
 29517       delete[] imgData;
 29518       if (!file) cimg::fclose(nfile);
 29519       return *this;
 29520 #endif
 29523     //! Load an image from a PNM file.
 29524     CImg<T>& load_pnm(const char *const filename) {
 29525       return _load_pnm(0,filename);
 29528     static CImg<T> get_load_pnm(const char *const filename) {
 29529       return CImg<T>().load_pnm(filename);
 29532     //! Load an image from a PNM file.
 29533     CImg<T>& load_pnm(cimg_std::FILE *const file) {
 29534       return _load_pnm(file,0);
 29537     static CImg<T> get_load_pnm(cimg_std::FILE *const file) {
 29538       return CImg<T>().load_pnm(file);
 29541     CImg<T>& _load_pnm(cimg_std::FILE *const file, const char *const filename) {
 29542       if (!filename && !file)
 29543         throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
 29544                                     pixel_type());
 29545       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 29546       unsigned int ppm_type, W, H, colormax = 255;
 29547       char item[1024] = { 0 };
 29548       int err, rval, gval, bval;
 29549       const int cimg_iobuffer = 12*1024*1024;
 29550       while ((err=cimg_std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 29551       if (cimg_std::sscanf(item," P%u",&ppm_type)!=1) {
 29552         if (!file) cimg::fclose(nfile);
 29553         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
 29554                               pixel_type(),filename?filename:"(FILE*)");
 29556       while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 29557       if ((err=cimg_std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
 29558         if (!file) cimg::fclose(nfile);
 29559         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
 29560                               pixel_type(),filename?filename:"(FILE*)");
 29562       if (err==2) {
 29563         while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 29564         if (cimg_std::sscanf(item,"%u",&colormax)!=1)
 29565           cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
 29566                      pixel_type(),filename?filename:"(FILE*)");
 29568       cimg_std::fgetc(nfile);
 29569       assign();
 29571       switch (ppm_type) {
 29572       case 2 : { // Grey Ascii
 29573         assign(W,H,1,1);
 29574         T* rdata = data;
 29575         cimg_foroff(*this,off) { if (cimg_std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
 29576       } break;
 29577       case 3 : { // Color Ascii
 29578         assign(W,H,1,3);
 29579         T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 29580         cimg_forXY(*this,x,y) {
 29581           if (cimg_std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
 29582           else break;
 29584       } break;
 29585       case 5 : { // Grey Binary
 29586         if (colormax<256) { // 8 bits
 29587           CImg<ucharT> raw;
 29588           assign(W,H,1,1);
 29589           T *ptrd = ptr(0,0,0,0);
 29590           for (int toread = (int)size(); toread>0; ) {
 29591             raw.assign(cimg::min(toread,cimg_iobuffer));
 29592             cimg::fread(raw.data,raw.width,nfile);
 29593             toread-=raw.width;
 29594             const unsigned char *ptrs = raw.data;
 29595             for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 29597         } else { // 16 bits
 29598           CImg<ushortT> raw;
 29599           assign(W,H,1,1);
 29600           T *ptrd = ptr(0,0,0,0);
 29601           for (int toread = (int)size(); toread>0; ) {
 29602             raw.assign(cimg::min(toread,cimg_iobuffer/2));
 29603             cimg::fread(raw.data,raw.width,nfile);
 29604             if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
 29605             toread-=raw.width;
 29606             const unsigned short *ptrs = raw.data;
 29607             for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 29610       } break;
 29611       case 6 : { // Color Binary
 29612         if (colormax<256) { // 8 bits
 29613           CImg<ucharT> raw;
 29614           assign(W,H,1,3);
 29616             *ptr_r = ptr(0,0,0,0),
 29617             *ptr_g = ptr(0,0,0,1),
 29618             *ptr_b = ptr(0,0,0,2);
 29619           for (int toread = (int)size(); toread>0; ) {
 29620             raw.assign(cimg::min(toread,cimg_iobuffer));
 29621             cimg::fread(raw.data,raw.width,nfile);
 29622             toread-=raw.width;
 29623             const unsigned char *ptrs = raw.data;
 29624             for (unsigned int off = raw.width/3; off; --off) {
 29625               *(ptr_r++) = (T)*(ptrs++);
 29626               *(ptr_g++) = (T)*(ptrs++);
 29627               *(ptr_b++) = (T)*(ptrs++);
 29630         } else { // 16 bits
 29631           CImg<ushortT> raw;
 29632           assign(W,H,1,3);
 29634             *ptr_r = ptr(0,0,0,0),
 29635             *ptr_g = ptr(0,0,0,1),
 29636             *ptr_b = ptr(0,0,0,2);
 29637           for (int toread = (int)size(); toread>0; ) {
 29638             raw.assign(cimg::min(toread,cimg_iobuffer/2));
 29639             cimg::fread(raw.data,raw.width,nfile);
 29640             if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
 29641             toread-=raw.width;
 29642             const unsigned short *ptrs = raw.data;
 29643             for (unsigned int off = raw.width/3; off; --off) {
 29644               *(ptr_r++) = (T)*(ptrs++);
 29645               *(ptr_g++) = (T)*(ptrs++);
 29646               *(ptr_b++) = (T)*(ptrs++);
 29650       } break;
 29651       default :
 29652         if (!file) cimg::fclose(nfile);
 29653         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
 29654                               pixel_type(),filename?filename:"(FILE*)",ppm_type);
 29656       if (!file) cimg::fclose(nfile);
 29657       return *this;
 29660     //! Load an image from a RGB file.
 29661     CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 29662       return _load_rgb(0,filename,dimw,dimh);
 29665     static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 29666       return CImg<T>().load_rgb(filename,dimw,dimh);
 29669     //! Load an image from a RGB file.
 29670     CImg<T>& load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 29671       return _load_rgb(file,0,dimw,dimh);
 29674     static CImg<T> get_load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 29675       return CImg<T>().load_rgb(file,dimw,dimh);
 29678     CImg<T>& _load_rgb(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 29679       if (!filename && !file)
 29680         throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
 29681                                     pixel_type());
 29682       if (!dimw || !dimh) return assign();
 29683       const int cimg_iobuffer = 12*1024*1024;
 29684       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 29685       CImg<ucharT> raw;
 29686       assign(dimw,dimh,1,3);
 29688         *ptr_r = ptr(0,0,0,0),
 29689         *ptr_g = ptr(0,0,0,1),
 29690         *ptr_b = ptr(0,0,0,2);
 29691       for (int toread = (int)size(); toread>0; ) {
 29692         raw.assign(cimg::min(toread,cimg_iobuffer));
 29693         cimg::fread(raw.data,raw.width,nfile);
 29694         toread-=raw.width;
 29695         const unsigned char *ptrs = raw.data;
 29696         for (unsigned int off = raw.width/3; off; --off) {
 29697           *(ptr_r++) = (T)*(ptrs++);
 29698           *(ptr_g++) = (T)*(ptrs++);
 29699           *(ptr_b++) = (T)*(ptrs++);
 29702       if (!file) cimg::fclose(nfile);
 29703       return *this;
 29706     //! Load an image from a RGBA file.
 29707     CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 29708       return _load_rgba(0,filename,dimw,dimh);
 29711     static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 29712       return CImg<T>().load_rgba(filename,dimw,dimh);
 29715     //! Load an image from a RGBA file.
 29716     CImg<T>& load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 29717       return _load_rgba(file,0,dimw,dimh);
 29720     static CImg<T> get_load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 29721       return CImg<T>().load_rgba(file,dimw,dimh);
 29724     CImg<T>& _load_rgba(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 29725       if (!filename && !file)
 29726         throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
 29727                                     pixel_type());
 29728       if (!dimw || !dimh) return assign();
 29729       const int cimg_iobuffer = 12*1024*1024;
 29730       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 29731       CImg<ucharT> raw;
 29732       assign(dimw,dimh,1,4);
 29734         *ptr_r = ptr(0,0,0,0),
 29735         *ptr_g = ptr(0,0,0,1),
 29736         *ptr_b = ptr(0,0,0,2),
 29737         *ptr_a = ptr(0,0,0,3);
 29738       for (int toread = (int)size(); toread>0; ) {
 29739         raw.assign(cimg::min(toread,cimg_iobuffer));
 29740         cimg::fread(raw.data,raw.width,nfile);
 29741         toread-=raw.width;
 29742         const unsigned char *ptrs = raw.data;
 29743         for (unsigned int off = raw.width/4; off; --off) {
 29744           *(ptr_r++) = (T)*(ptrs++);
 29745           *(ptr_g++) = (T)*(ptrs++);
 29746           *(ptr_b++) = (T)*(ptrs++);
 29747           *(ptr_a++) = (T)*(ptrs++);
 29750       if (!file) cimg::fclose(nfile);
 29751       return *this;
 29754     //! Load an image from a TIFF file.
 29755     CImg<T>& load_tiff(const char *const filename,
 29756                        const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 29757                        const unsigned int step_frame=1) {
 29758       if (!filename)
 29759         throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
 29760                                     pixel_type());
 29761       const unsigned int
 29762         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 29763         nstep_frame = step_frame?step_frame:1;
 29764       unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 29766 #ifndef cimg_use_tiff
 29767       if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
 29768         throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 29769                                     "('cimg_use_tiff' must be defined).",
 29770                                     pixel_type(),filename);
 29771       return load_other(filename);
 29772 #else
 29773       TIFF *tif = TIFFOpen(filename,"r");
 29774       if (tif) {
 29775         unsigned int nb_images = 0;
 29776         do ++nb_images; while (TIFFReadDirectory(tif));
 29777         if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 29778           cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 29779                      pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 29780         if (nfirst_frame>=nb_images) return assign();
 29781         if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 29782         TIFFSetDirectory(tif,0);
 29783         CImg<T> frame;
 29784         for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
 29785           frame._load_tiff(tif,l);
 29786           if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
 29787           if (frame.width>width || frame.height>height || frame.dim>dim)
 29788             resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
 29789           draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
 29791         TIFFClose(tif);
 29792       } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
 29793                                  pixel_type(),filename);
 29794       return *this;
 29795 #endif
 29798     static CImg<T> get_load_tiff(const char *const filename,
 29799                                  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 29800                                  const unsigned int step_frame=1) {
 29801       return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 29804     // (Original contribution by Jerome Boulanger).
 29805 #ifdef cimg_use_tiff
 29806     CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
 29807       if (!TIFFSetDirectory(tif,directory)) return assign();
 29808       uint16 samplesperpixel, bitspersample;
 29809       uint32 nx,ny;
 29810       const char *const filename = TIFFFileName(tif);
 29811       TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
 29812       TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
 29813       TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
 29814       if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
 29815         cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
 29816                    pixel_type(),filename);
 29817         samplesperpixel = 1;
 29819       TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
 29820       assign(nx,ny,1,samplesperpixel);
 29821       if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
 29822         uint16 photo, config;
 29823         TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
 29824         TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
 29825         if (TIFFIsTiled(tif)) {
 29826           uint32 tw, th;
 29827           TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
 29828           TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
 29829           if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 29830             case 8 : {
 29831               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 29832               if (buf) {
 29833                 for (unsigned int row = 0; row<ny; row+=th)
 29834                   for (unsigned int col = 0; col<nx; col+=tw) {
 29835                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 29836                       _TIFFfree(buf); TIFFClose(tif);
 29837                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29838                                           pixel_type(),filename);
 29839                     } else {
 29840                       unsigned char *ptr = buf;
 29841                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29842                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29843                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29844                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 29847                 _TIFFfree(buf);
 29849             } break;
 29850             case 16 : {
 29851               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 29852               if (buf) {
 29853                 for (unsigned int row = 0; row<ny; row+=th)
 29854                   for (unsigned int col = 0; col<nx; col+=tw) {
 29855                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 29856                       _TIFFfree(buf); TIFFClose(tif);
 29857                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29858                                           pixel_type(),filename);
 29859                     } else {
 29860                       unsigned short *ptr = buf;
 29861                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29862                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29863                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29864                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 29867                 _TIFFfree(buf);
 29869             } break;
 29870             case 32 : {
 29871               float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 29872               if (buf) {
 29873                 for (unsigned int row = 0; row<ny; row+=th)
 29874                   for (unsigned int col = 0; col<nx; col+=tw) {
 29875                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 29876                       _TIFFfree(buf); TIFFClose(tif);
 29877                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29878                                           pixel_type(),filename);
 29879                     } else {
 29880                       float *ptr = buf;
 29881                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29882                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29883                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29884                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 29887                 _TIFFfree(buf);
 29889             } break;
 29890             } else switch (bitspersample) {
 29891             case 8 : {
 29892               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 29893               if (buf) {
 29894                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29895                   for (unsigned int row = 0; row<ny; row+=th)
 29896                     for (unsigned int col = 0; col<nx; col+=tw) {
 29897                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 29898                         _TIFFfree(buf); TIFFClose(tif);
 29899                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29900                                             pixel_type(),filename);
 29901                       } else {
 29902                         unsigned char *ptr = buf;
 29903                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29904                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29905                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 29908                 _TIFFfree(buf);
 29910             } break;
 29911             case 16 : {
 29912               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 29913               if (buf) {
 29914                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29915                   for (unsigned int row = 0; row<ny; row+=th)
 29916                     for (unsigned int col = 0; col<nx; col+=tw) {
 29917                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 29918                         _TIFFfree(buf); TIFFClose(tif);
 29919                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29920                                             pixel_type(),filename);
 29921                       } else {
 29922                         unsigned short *ptr = buf;
 29923                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29924                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29925                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 29928                 _TIFFfree(buf);
 29930             } break;
 29931             case 32 : {
 29932               float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 29933               if (buf) {
 29934                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 29935                   for (unsigned int row = 0; row<ny; row+=th)
 29936                     for (unsigned int col = 0; col<nx; col+=tw) {
 29937                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 29938                         _TIFFfree(buf); TIFFClose(tif);
 29939                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 29940                                             pixel_type(),filename);
 29941                       } else {
 29942                         float *ptr = buf;
 29943                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 29944                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 29945                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 29948                 _TIFFfree(buf);
 29950             } break;
 29952         } else {
 29953           if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 29954             case 8 : {
 29955               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 29956               if (buf) {
 29957                 uint32 row, rowsperstrip = (uint32)-1;
 29958                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 29959                 for (row = 0; row<ny; row+= rowsperstrip) {
 29960                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 29961                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 29962                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 29963                     _TIFFfree(buf); TIFFClose(tif);
 29964                     throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
 29965                                         pixel_type(),filename);
 29967                   unsigned char *ptr = buf;
 29968                   for (unsigned int rr = 0; rr<nrow; ++rr)
 29969                     for (unsigned int cc = 0; cc<nx; ++cc)
 29970                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 29972                 _TIFFfree(buf);
 29974             } break;
 29975             case 16 : {
 29976               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 29977               if (buf) {
 29978                 uint32 row, rowsperstrip = (uint32)-1;
 29979                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 29980                 for (row = 0; row<ny; row+= rowsperstrip) {
 29981                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 29982                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 29983                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 29984                     _TIFFfree(buf); TIFFClose(tif);
 29985                     throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 29986                                         pixel_type(),filename);
 29988                   unsigned short *ptr = buf;
 29989                   for (unsigned int rr = 0; rr<nrow; ++rr)
 29990                     for (unsigned int cc = 0; cc<nx; ++cc)
 29991                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 29993                 _TIFFfree(buf);
 29995             } break;
 29996             case 32 : {
 29997               float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 29998               if (buf) {
 29999                 uint32 row, rowsperstrip = (uint32)-1;
 30000                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 30001                 for (row = 0; row<ny; row+= rowsperstrip) {
 30002                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 30003                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 30004                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 30005                     _TIFFfree(buf); TIFFClose(tif);
 30006                     throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 30007                                         pixel_type(),filename);
 30009                   float *ptr = buf;
 30010                   for (unsigned int rr = 0; rr<nrow; ++rr)
 30011                     for (unsigned int cc = 0; cc<nx; ++cc)
 30012                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 30014                 _TIFFfree(buf);
 30016             } break;
 30017             } else switch (bitspersample){
 30018             case 8 : {
 30019               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 30020               if (buf) {
 30021                 uint32 row, rowsperstrip = (uint32)-1;
 30022                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 30023                 for (unsigned int vv=0; vv<samplesperpixel; ++vv)
 30024                   for (row = 0; row<ny; row+= rowsperstrip) {
 30025                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 30026                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 30027                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 30028                       _TIFFfree(buf); TIFFClose(tif);
 30029                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
 30030                                           pixel_type(),filename);
 30032                     unsigned char *ptr = buf;
 30033                     for (unsigned int rr = 0;rr<nrow; ++rr)
 30034                       for (unsigned int cc = 0; cc<nx; ++cc)
 30035                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 30037                 _TIFFfree(buf);
 30039             } break;
 30040             case 16 : {
 30041               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 30042               if (buf) {
 30043                 uint32 row, rowsperstrip = (uint32)-1;
 30044                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 30045                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 30046                   for (row = 0; row<ny; row+= rowsperstrip) {
 30047                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 30048                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 30049                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 30050                       _TIFFfree(buf); TIFFClose(tif);
 30051                       throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 30052                                           pixel_type(),filename);
 30054                     unsigned short *ptr = buf;
 30055                     for (unsigned int rr = 0; rr<nrow; ++rr)
 30056                       for (unsigned int cc = 0; cc<nx; ++cc)
 30057                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 30059                 _TIFFfree(buf);
 30061             } break;
 30062             case 32 : {
 30063               float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 30064               if (buf) {
 30065                 uint32 row, rowsperstrip = (uint32)-1;
 30066                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 30067                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 30068                   for (row = 0; row<ny; row+= rowsperstrip) {
 30069                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 30070                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 30071                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 30072                       _TIFFfree(buf); TIFFClose(tif);
 30073                       throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 30074                                           pixel_type(),filename);
 30076                     float *ptr = buf;
 30077                     for (unsigned int rr = 0; rr<nrow; ++rr)  for (unsigned int cc = 0; cc<nx; ++cc)
 30078                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 30080                 _TIFFfree(buf);
 30082             } break;
 30085       } else {
 30086         uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
 30087         if (!raster) {
 30088           _TIFFfree(raster); TIFFClose(tif);
 30089           throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
 30090                               pixel_type(),filename);
 30092         TIFFReadRGBAImage(tif,nx,ny,raster,0);
 30093         switch (samplesperpixel) {
 30094         case 1 : {
 30095           cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
 30096         } break;
 30097         case 3 : {
 30098           cimg_forXY(*this,x,y) {
 30099             (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 30100             (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 30101             (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 30103         } break;
 30104         case 4 : {
 30105           cimg_forXY(*this,x,y) {
 30106             (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 30107             (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 30108             (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 30109             (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
 30111         } break;
 30113         _TIFFfree(raster);
 30115       return *this;
 30117 #endif
 30119     //! Load an image from an ANALYZE7.5/NIFTI file.
 30120     CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
 30121       return _load_analyze(0,filename,voxsize);
 30124     static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
 30125       return CImg<T>().load_analyze(filename,voxsize);
 30128     //! Load an image from an ANALYZE7.5/NIFTI file.
 30129     CImg<T>& load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
 30130       return _load_analyze(file,0,voxsize);
 30133     static CImg<T> get_load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
 30134       return CImg<T>().load_analyze(file,voxsize);
 30137     CImg<T>& _load_analyze(cimg_std::FILE *const file, const char *const filename, float *const voxsize=0) {
 30138       if (!filename && !file)
 30139         throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
 30140                                     pixel_type());
 30141       cimg_std::FILE *nfile_header = 0, *nfile = 0;
 30142       if (!file) {
 30143         char body[1024];
 30144         const char *ext = cimg::split_filename(filename,body);
 30145         if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
 30146           nfile_header = cimg::fopen(filename,"rb");
 30147           cimg_std::sprintf(body+cimg::strlen(body),".img");
 30148           nfile = cimg::fopen(body,"rb");
 30149         } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
 30150           nfile = cimg::fopen(filename,"rb");
 30151           cimg_std::sprintf(body+cimg::strlen(body),".hdr");
 30152           nfile_header = cimg::fopen(body,"rb");
 30153         } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
 30154       } else nfile_header = nfile = file; // File is a Niftii file.
 30155       if (!nfile || !nfile_header)
 30156         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
 30157                               pixel_type(),filename?filename:"(FILE*)");
 30159       // Read header.
 30160       bool endian = false;
 30161       unsigned int header_size;
 30162       cimg::fread(&header_size,1,nfile_header);
 30163       if (!header_size)
 30164         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
 30165                               pixel_type(),filename?filename:"(FILE*)");
 30166       if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
 30167       unsigned char *header = new unsigned char[header_size];
 30168       cimg::fread(header+4,header_size-4,nfile_header);
 30169       if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
 30170       if (endian) {
 30171         cimg::invert_endianness((short*)(header+40),5);
 30172         cimg::invert_endianness((short*)(header+70),1);
 30173         cimg::invert_endianness((short*)(header+72),1);
 30174         cimg::invert_endianness((float*)(header+76),4);
 30175         cimg::invert_endianness((float*)(header+112),1);
 30177       unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
 30178       if (!dim[0])
 30179         cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
 30180                    pixel_type(),filename?filename:"(FILE*)");
 30181       if (dim[0]>4)
 30182         cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
 30183                    pixel_type(),filename?filename:"(FILE*)",dim[0]);
 30184       if (dim[0]>=1) dimx = dim[1];
 30185       if (dim[0]>=2) dimy = dim[2];
 30186       if (dim[0]>=3) dimz = dim[3];
 30187       if (dim[0]>=4) dimv = dim[4];
 30188       float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
 30189       const unsigned short datatype = *(short*)(header+70);
 30190       if (voxsize) {
 30191         const float *vsize = (float*)(header+76);
 30192         voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
 30194       delete[] header;
 30196       // Read pixel data.
 30197       assign(dimx,dimy,dimz,dimv);
 30198       switch (datatype) {
 30199       case 2 : {
 30200         unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
 30201         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 30202         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 30203         delete[] buffer;
 30204       } break;
 30205       case 4 : {
 30206         short *buffer = new short[dimx*dimy*dimz*dimv];
 30207         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 30208         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 30209         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 30210         delete[] buffer;
 30211       } break;
 30212       case 8 : {
 30213         int *buffer = new int[dimx*dimy*dimz*dimv];
 30214         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 30215         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 30216         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 30217         delete[] buffer;
 30218       } break;
 30219       case 16 : {
 30220         float *buffer = new float[dimx*dimy*dimz*dimv];
 30221         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 30222         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 30223         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 30224         delete[] buffer;
 30225       } break;
 30226       case 64 : {
 30227         double *buffer = new double[dimx*dimy*dimz*dimv];
 30228         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 30229         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 30230         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 30231         delete[] buffer;
 30232       } break;
 30233       default :
 30234         if (!file) cimg::fclose(nfile);
 30235         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
 30236                               pixel_type(),filename?filename:"(FILE*)",datatype);
 30238       if (!file) cimg::fclose(nfile);
 30239       return *this;
 30242     //! Load an image (list) from a .cimg file.
 30243     CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
 30244       CImgList<T> list;
 30245       list.load_cimg(filename);
 30246       if (list.size==1) return list[0].transfer_to(*this);
 30247       return assign(list.get_append(axis,align));
 30250     static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
 30251       return CImg<T>().load_cimg(filename,axis,align);
 30254     //! Load an image (list) from a .cimg file.
 30255     CImg<T>& load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
 30256       CImgList<T> list;
 30257       list.load_cimg(file);
 30258       if (list.size==1) return list[0].transfer_to(*this);
 30259       return assign(list.get_append(axis,align));
 30262     static CImg<T> get_load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
 30263       return CImg<T>().load_cimg(file,axis,align);
 30266     //! Load a sub-image (list) from a .cimg file.
 30267     CImg<T>& load_cimg(const char *const filename,
 30268                        const unsigned int n0, const unsigned int n1,
 30269                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 30270                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 30271                        const char axis='z', const char align='p') {
 30272       CImgList<T> list;
 30273       list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 30274       if (list.size==1) return list[0].transfer_to(*this);
 30275       return assign(list.get_append(axis,align));
 30278     static CImg<T> get_load_cimg(const char *const filename,
 30279                                  const unsigned int n0, const unsigned int n1,
 30280                                  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 30281                                  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 30282                                  const char axis='z', const char align='p') {
 30283       return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 30286     //! Load a sub-image (list) from a non-compressed .cimg file.
 30287     CImg<T>& load_cimg(cimg_std::FILE *const file,
 30288                        const unsigned int n0, const unsigned int n1,
 30289                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 30290                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 30291                        const char axis='z', const char align='p') {
 30292       CImgList<T> list;
 30293       list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 30294       if (list.size==1) return list[0].transfer_to(*this);
 30295       return assign(list.get_append(axis,align));
 30298     static CImg<T> get_load_cimg(cimg_std::FILE *const file,
 30299                                  const unsigned int n0, const unsigned int n1,
 30300                                  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 30301                                  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 30302                                  const char axis='z', const char align='p') {
 30303       return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 30306     //! Load an image from an INRIMAGE-4 file.
 30307     CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
 30308       return _load_inr(0,filename,voxsize);
 30311     static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
 30312       return CImg<T>().load_inr(filename,voxsize);
 30315     //! Load an image from an INRIMAGE-4 file.
 30316     CImg<T>& load_inr(cimg_std::FILE *const file, float *const voxsize=0) {
 30317       return _load_inr(file,0,voxsize);
 30320     static CImg<T> get_load_inr(cimg_std::FILE *const file, float *voxsize=0) {
 30321       return CImg<T>().load_inr(file,voxsize);
 30324     // Load an image from an INRIMAGE-4 file (internal).
 30325     static void _load_inr_header(cimg_std::FILE *file, int out[8], float *const voxsize) {
 30326       char item[1024], tmp1[64], tmp2[64];
 30327       out[0] = cimg_std::fscanf(file,"%63s",item);
 30328       out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
 30329       if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
 30330         throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
 30331                               "(INRIMAGE-4 identifier not found)",
 30332                               pixel_type());
 30333       while (cimg_std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
 30334         cimg_std::sscanf(item," XDIM%*[^0-9]%d",out);
 30335         cimg_std::sscanf(item," YDIM%*[^0-9]%d",out+1);
 30336         cimg_std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
 30337         cimg_std::sscanf(item," VDIM%*[^0-9]%d",out+3);
 30338         cimg_std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
 30339         if (voxsize) {
 30340           cimg_std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
 30341           cimg_std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
 30342           cimg_std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
 30344         if (cimg_std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
 30345         switch (cimg_std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
 30346         case 0 : break;
 30347         case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; cimg_std::strcpy(tmp1,tmp2);
 30348         case 1 :
 30349           if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4] = 0;
 30350           if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
 30351           if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4] = 2;
 30352           if (out[4]>=0) break;
 30353         default :
 30354           throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
 30357       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
 30358         throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
 30359                               pixel_type(),out[0],out[1],out[2],out[3]);
 30360       if(out[4]<0 || out[5]<0)
 30361         throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
 30362                               pixel_type());
 30363       if(out[6]<0)
 30364         throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
 30365                               pixel_type());
 30366       if(out[7]<0)
 30367         throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
 30368                               pixel_type());
 30371     CImg<T>& _load_inr(cimg_std::FILE *const file, const char *const filename, float *const voxsize) {
 30372 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
 30373      if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
 30374         Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
 30375         cimg_forYZ(*this,y,z) { \
 30376             cimg::fread(val,fopt[0]*fopt[3],nfile); \
 30377             if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
 30378             xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
 30379           } \
 30380         delete[] val; \
 30381         loaded = true; \
 30384       if (!filename && !file)
 30385         throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
 30386                                     pixel_type());
 30387       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 30388       int fopt[8], endian=cimg::endianness()?1:0;
 30389       bool loaded = false;
 30390       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
 30391       _load_inr_header(nfile,fopt,voxsize);
 30392       assign(fopt[0],fopt[1],fopt[2],fopt[3]);
 30393       _cimg_load_inr_case(0,0,8, unsigned char);
 30394       _cimg_load_inr_case(0,1,8, char);
 30395       _cimg_load_inr_case(0,0,16,unsigned short);
 30396       _cimg_load_inr_case(0,1,16,short);
 30397       _cimg_load_inr_case(0,0,32,unsigned int);
 30398       _cimg_load_inr_case(0,1,32,int);
 30399       _cimg_load_inr_case(1,0,32,float);
 30400       _cimg_load_inr_case(1,1,32,float);
 30401       _cimg_load_inr_case(1,0,64,double);
 30402       _cimg_load_inr_case(1,1,64,double);
 30403       if (!loaded) {
 30404         if (!file) cimg::fclose(nfile);
 30405         throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
 30406                               pixel_type(),filename?filename:"(FILE*)");
 30408       if (!file) cimg::fclose(nfile);
 30409       return *this;
 30412     //! Load an image from a PANDORE file.
 30413     CImg<T>& load_pandore(const char *const filename) {
 30414       return _load_pandore(0,filename);
 30417     static CImg<T> get_load_pandore(const char *const filename) {
 30418       return CImg<T>().load_pandore(filename);
 30421     //! Load an image from a PANDORE file.
 30422     CImg<T>& load_pandore(cimg_std::FILE *const file) {
 30423       return _load_pandore(file,0);
 30426     static CImg<T> get_load_pandore(cimg_std::FILE *const file) {
 30427       return CImg<T>().load_pandore(file);
 30430     CImg<T>& _load_pandore(cimg_std::FILE *const file, const char *const filename) {
 30431 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
 30432         cimg::fread(dims,nbdim,nfile); \
 30433         if (endian) cimg::invert_endianness(dims,nbdim); \
 30434         assign(nwidth,nheight,ndepth,ndim); \
 30435         const unsigned int siz = size(); \
 30436         stype *buffer = new stype[siz]; \
 30437         cimg::fread(buffer,siz,nfile); \
 30438         if (endian) cimg::invert_endianness(buffer,siz); \
 30439         T *ptrd = data; \
 30440         cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
 30441         buffer-=siz; \
 30442         delete[] buffer
 30444 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
 30445         if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
 30446         else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
 30447         else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
 30448         else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
 30449                                    pixel_type(),filename?filename:"(FILE*)"); }
 30451       if (!filename && !file)
 30452         throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
 30453                                     pixel_type());
 30454       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 30455       typedef unsigned char uchar;
 30456       typedef unsigned short ushort;
 30457       typedef unsigned int uint;
 30458       typedef unsigned long ulong;
 30459       char header[32];
 30460       cimg::fread(header,12,nfile);
 30461       if (cimg::strncasecmp("PANDORE",header,7)) {
 30462         if (!file) cimg::fclose(nfile);
 30463         throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
 30464                               "(PANDORE identifier not found).",
 30465                               pixel_type(),filename?filename:"(FILE*)");
 30467       unsigned int imageid, dims[8];
 30468       cimg::fread(&imageid,1,nfile);
 30469       const bool endian = (imageid>255);
 30470       if (endian) cimg::invert_endianness(imageid);
 30471       cimg::fread(header,20,nfile);
 30473       switch (imageid) {
 30474       case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
 30475       case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
 30476       case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
 30477       case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
 30478       case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
 30479       case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
 30480       case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
 30481       case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
 30482       case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
 30483       case 11 : { // Region 1D
 30484         cimg::fread(dims,3,nfile);
 30485         if (endian) cimg::invert_endianness(dims,3);
 30486         assign(dims[1],1,1,1);
 30487         const unsigned siz = size();
 30488         if (dims[2]<256) {
 30489           unsigned char *buffer = new unsigned char[siz];
 30490           cimg::fread(buffer,siz,nfile);
 30491           T *ptrd = data;
 30492           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30493           buffer-=siz;
 30494           delete[] buffer;
 30495         } else {
 30496           if (dims[2]<65536) {
 30497             unsigned short *buffer = new unsigned short[siz];
 30498             cimg::fread(buffer,siz,nfile);
 30499             if (endian) cimg::invert_endianness(buffer,siz);
 30500             T *ptrd = data;
 30501             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30502             buffer-=siz;
 30503             delete[] buffer;
 30504           } else {
 30505             unsigned int *buffer = new unsigned int[siz];
 30506             cimg::fread(buffer,siz,nfile);
 30507             if (endian) cimg::invert_endianness(buffer,siz);
 30508             T *ptrd = data;
 30509             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30510             buffer-=siz;
 30511             delete[] buffer;
 30515         break;
 30516       case 12 : { // Region 2D
 30517         cimg::fread(dims,4,nfile);
 30518         if (endian) cimg::invert_endianness(dims,4);
 30519         assign(dims[2],dims[1],1,1);
 30520         const unsigned int siz = size();
 30521         if (dims[3]<256) {
 30522           unsigned char *buffer = new unsigned char[siz];
 30523           cimg::fread(buffer,siz,nfile);
 30524           T *ptrd = data;
 30525           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30526           buffer-=siz;
 30527           delete[] buffer;
 30528         } else {
 30529           if (dims[3]<65536) {
 30530             unsigned short *buffer = new unsigned short[siz];
 30531             cimg::fread(buffer,siz,nfile);
 30532             if (endian) cimg::invert_endianness(buffer,siz);
 30533             T *ptrd = data;
 30534             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30535             buffer-=siz;
 30536             delete[] buffer;
 30537           } else {
 30538             unsigned long *buffer = new unsigned long[siz];
 30539             cimg::fread(buffer,siz,nfile);
 30540             if (endian) cimg::invert_endianness(buffer,siz);
 30541             T *ptrd = data;
 30542             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30543             buffer-=siz;
 30544             delete[] buffer;
 30548         break;
 30549       case 13 : { // Region 3D
 30550         cimg::fread(dims,5,nfile);
 30551         if (endian) cimg::invert_endianness(dims,5);
 30552         assign(dims[3],dims[2],dims[1],1);
 30553         const unsigned int siz = size();
 30554         if (dims[4]<256) {
 30555           unsigned char *buffer = new unsigned char[siz];
 30556           cimg::fread(buffer,siz,nfile);
 30557           T *ptrd = data;
 30558           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30559           buffer-=siz;
 30560           delete[] buffer;
 30561         } else {
 30562           if (dims[4]<65536) {
 30563             unsigned short *buffer = new unsigned short[siz];
 30564             cimg::fread(buffer,siz,nfile);
 30565             if (endian) cimg::invert_endianness(buffer,siz);
 30566             T *ptrd = data;
 30567             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30568             buffer-=siz;
 30569             delete[] buffer;
 30570           } else {
 30571             unsigned int *buffer = new unsigned int[siz];
 30572             cimg::fread(buffer,siz,nfile);
 30573             if (endian) cimg::invert_endianness(buffer,siz);
 30574             T *ptrd = data;
 30575             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 30576             buffer-=siz;
 30577             delete[] buffer;
 30581         break;
 30582       case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
 30583       case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
 30584       case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
 30585       case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
 30586       case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
 30587       case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
 30588       case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
 30589       case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
 30590       case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
 30591       case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
 30592       case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
 30593       case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
 30594       case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
 30595       case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
 30596       case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
 30597       case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
 30598       case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
 30599       case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
 30600       case 34 : { // Points 1D
 30601         int ptbuf[4];
 30602         cimg::fread(ptbuf,1,nfile);
 30603         if (endian) cimg::invert_endianness(ptbuf,1);
 30604         assign(1); (*this)(0) = (T)ptbuf[0];
 30605       } break;
 30606       case 35 : { // Points 2D
 30607         int ptbuf[4];
 30608         cimg::fread(ptbuf,2,nfile);
 30609         if (endian) cimg::invert_endianness(ptbuf,2);
 30610         assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
 30611       } break;
 30612       case 36 : { // Points 3D
 30613         int ptbuf[4];
 30614         cimg::fread(ptbuf,3,nfile);
 30615         if (endian) cimg::invert_endianness(ptbuf,3);
 30616         assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
 30617       } break;
 30618       default :
 30619         if (!file) cimg::fclose(nfile);
 30620         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
 30621                               pixel_type(),filename?filename:"(FILE*)",imageid);
 30623       if (!file) cimg::fclose(nfile);
 30624       return *this;
 30627     //! Load an image from a PAR-REC (Philips) file.
 30628     CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
 30629       CImgList<T> list;
 30630       list.load_parrec(filename);
 30631       if (list.size==1) return list[0].transfer_to(*this);
 30632       return assign(list.get_append(axis,align));
 30635     static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
 30636       return CImg<T>().load_parrec(filename,axis,align);
 30639     //! Load an image from a .RAW file.
 30640     CImg<T>& load_raw(const char *const filename,
 30641                       const unsigned int sizex, const unsigned int sizey=1,
 30642                       const unsigned int sizez=1, const unsigned int sizev=1,
 30643                       const bool multiplexed=false, const bool invert_endianness=false) {
 30644       return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 30647     static CImg<T> get_load_raw(const char *const filename,
 30648                                 const unsigned int sizex, const unsigned int sizey=1,
 30649                                 const unsigned int sizez=1, const unsigned int sizev=1,
 30650                                 const bool multiplexed=false, const bool invert_endianness=false) {
 30651       return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 30654     //! Load an image from a .RAW file.
 30655     CImg<T>& load_raw(cimg_std::FILE *const file,
 30656                       const unsigned int sizex, const unsigned int sizey=1,
 30657                       const unsigned int sizez=1, const unsigned int sizev=1,
 30658                       const bool multiplexed=false, const bool invert_endianness=false) {
 30659       return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 30662     static CImg<T> get_load_raw(cimg_std::FILE *const file,
 30663                                 const unsigned int sizex, const unsigned int sizey=1,
 30664                                 const unsigned int sizez=1, const unsigned int sizev=1,
 30665                                 const bool multiplexed=false, const bool invert_endianness=false) {
 30666       return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 30669     CImg<T>& _load_raw(cimg_std::FILE *const file, const char *const filename,
 30670                        const unsigned int sizex, const unsigned int sizey,
 30671                        const unsigned int sizez, const unsigned int sizev,
 30672                        const bool multiplexed, const bool invert_endianness) {
 30673       if (!filename && !file)
 30674         throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
 30675                                     pixel_type());
 30676       assign(sizex,sizey,sizez,sizev,0);
 30677       const unsigned int siz = size();
 30678       if (siz) {
 30679         cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 30680         if (!multiplexed) {
 30681           cimg::fread(data,siz,nfile);
 30682           if (invert_endianness) cimg::invert_endianness(data,siz);
 30684         else {
 30685           CImg<T> buf(1,1,1,sizev);
 30686           cimg_forXYZ(*this,x,y,z) {
 30687             cimg::fread(buf.data,sizev,nfile);
 30688             if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
 30689             set_vector_at(buf,x,y,z); }
 30691         if (!file) cimg::fclose(nfile);
 30693       return *this;
 30696     //! Load a video sequence using FFMPEG av's libraries.
 30697     CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30698                          const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 30699                          const char axis='z', const char align='p') {
 30700       return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
 30703     static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30704                                    const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 30705                                    const char axis='z', const char align='p') {
 30706       return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
 30709     //! Load an image sequence from a YUV file.
 30710     CImg<T>& load_yuv(const char *const filename,
 30711                       const unsigned int sizex, const unsigned int sizey=1,
 30712                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30713                       const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 30714       return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 30717     static CImg<T> get_load_yuv(const char *const filename,
 30718                                 const unsigned int sizex, const unsigned int sizey=1,
 30719                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30720                                 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 30721       return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 30724     //! Load an image sequence from a YUV file.
 30725     CImg<T>& load_yuv(cimg_std::FILE *const file,
 30726                       const unsigned int sizex, const unsigned int sizey=1,
 30727                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30728                       const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 30729       return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 30732     static CImg<T> get_load_yuv(cimg_std::FILE *const file,
 30733                                 const unsigned int sizex, const unsigned int sizey=1,
 30734                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 30735                                 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 30736       return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 30739     //! Load a 3D object from a .OFF file.
 30740     template<typename tf, typename tc>
 30741     CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 30742       return _load_off(0,filename,primitives,colors,invert_faces);
 30745     template<typename tf, typename tc>
 30746     static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
 30747                                 const bool invert_faces=false) {
 30748       return CImg<T>().load_off(filename,primitives,colors,invert_faces);
 30751     //! Load a 3D object from a .OFF file.
 30752     template<typename tf, typename tc>
 30753     CImg<T>& load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 30754       return _load_off(file,0,primitives,colors,invert_faces);
 30757     template<typename tf, typename tc>
 30758     static CImg<T> get_load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
 30759                                 const bool invert_faces=false) {
 30760       return CImg<T>().load_off(file,primitives,colors,invert_faces);
 30763     template<typename tf, typename tc>
 30764     CImg<T>& _load_off(cimg_std::FILE *const file, const char *const filename,
 30765                        CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
 30766       if (!filename && !file)
 30767         throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
 30768                                     pixel_type());
 30769       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
 30770       unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
 30771       char line[256] = { 0 };
 30772       int err;
 30774       // Skip comments, and read magic string OFF
 30775       do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 30776       if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
 30777         if (!file) cimg::fclose(nfile);
 30778         throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
 30779                               pixel_type(),filename?filename:"(FILE*)");
 30781       do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 30782       if ((err = cimg_std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
 30783         if (!file) cimg::fclose(nfile);
 30784         throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
 30785                               pixel_type(),filename?filename:"(FILE*)");
 30788       // Read points data
 30789       assign(nb_points,3);
 30790       float X = 0, Y = 0, Z = 0;
 30791       cimg_forX(*this,l) {
 30792         do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 30793         if ((err = cimg_std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
 30794           if (!file) cimg::fclose(nfile);
 30795           throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
 30796                                 pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
 30798         (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
 30801       // Read primitive data
 30802       primitives.assign();
 30803       colors.assign();
 30804       bool stopflag = false;
 30805       while (!stopflag) {
 30806         float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
 30807         unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
 30808         line[0]='\0';
 30809         if ((err = cimg_std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
 30810         else {
 30811           ++nb_read;
 30812           switch (prim) {
 30813           case 1 : {
 30814             if ((err = cimg_std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
 30815               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30816                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30817               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30818             } else {
 30819               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30820               primitives.insert(CImg<tf>::vector(i0));
 30821               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 30823           } break;
 30824           case 2 : {
 30825             if ((err = cimg_std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
 30826               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30827                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30828               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30829             } else {
 30830               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30831               primitives.insert(CImg<tf>::vector(i0,i1));
 30832               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 30834           } break;
 30835           case 3 : {
 30836             if ((err = cimg_std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
 30837               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30838                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30839               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30840             } else {
 30841               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30842               if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
 30843               else primitives.insert(CImg<tf>::vector(i0,i2,i1));
 30844               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 30846           } break;
 30847           case 4 : {
 30848             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
 30849               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30850                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30851               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30852             } else {
 30853               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30854               if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 30855               else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 30856               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 30858           } break;
 30859           case 5 : {
 30860             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
 30861               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30862                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30863               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30864             } else {
 30865               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30866               if (invert_faces) {
 30867                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 30868                 primitives.insert(CImg<tf>::vector(i0,i3,i4));
 30870               else {
 30871                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 30872                 primitives.insert(CImg<tf>::vector(i0,i4,i3));
 30874               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 30875               ++nb_primitives;
 30877           } break;
 30878           case 6 : {
 30879             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
 30880               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30881                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30882               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30883             } else {
 30884               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30885               if (invert_faces) {
 30886                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 30887                 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
 30889               else {
 30890                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 30891                 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
 30893               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 30894               ++nb_primitives;
 30896           } break;
 30897           case 7 : {
 30898             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
 30899               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30900                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30901               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30902             } else {
 30903               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30904               if (invert_faces) {
 30905                 primitives.insert(CImg<tf>::vector(i0,i1,i3,i4));
 30906                 primitives.insert(CImg<tf>::vector(i0,i4,i5,i6));
 30907                 primitives.insert(CImg<tf>::vector(i1,i2,i3));
 30909               else {
 30910                 primitives.insert(CImg<tf>::vector(i0,i4,i3,i1));
 30911                 primitives.insert(CImg<tf>::vector(i0,i6,i5,i4));
 30912                 primitives.insert(CImg<tf>::vector(i3,i2,i1));
 30914               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 30915               ++(++nb_primitives);
 30917           } break;
 30918           case 8 : {
 30919             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
 30920               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 30921                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 30922               err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30923             } else {
 30924               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 30925               if (invert_faces) {
 30926                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 30927                 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
 30928                 primitives.insert(CImg<tf>::vector(i0,i5,i6,i7));
 30930               else {
 30931                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 30932                 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
 30933                 primitives.insert(CImg<tf>::vector(i0,i7,i6,i5));
 30935               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 30936               ++(++nb_primitives);
 30938           } break;
 30939           default :
 30940             cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
 30941                        pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
 30942             err = cimg_std::fscanf(nfile,"%*[^\n] ");
 30946       if (!file) cimg::fclose(nfile);
 30947       if (primitives.size!=nb_primitives)
 30948         cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
 30949                    pixel_type(),filename?filename:"(FILE*)",primitives.size,nb_primitives);
 30950       return *this;
 30953     //! Load a video sequence using FFMPEG's external tool 'ffmpeg'.
 30954     CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 30955       return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
 30958     static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 30959       return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
 30962     //! Load an image using GraphicsMagick's external tool 'gm'.
 30963     CImg<T>& load_graphicsmagick_external(const char *const filename) {
 30964       if (!filename)
 30965         throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
 30966                                     pixel_type());
 30967       char command[1024], filetmp[512];
 30968       cimg_std::FILE *file = 0;
 30969 #if cimg_OS==1
 30970       cimg_std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
 30971       file = popen(command,"r");
 30972       if (file) { load_pnm(file); pclose(file); return *this; }
 30973 #endif
 30974       do {
 30975         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 30976         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 30977       } while (file);
 30978       cimg_std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
 30979       cimg::system(command,cimg::graphicsmagick_path());
 30980       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 30981         cimg::fclose(cimg::fopen(filename,"r"));
 30982         throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
 30983                               "Path of 'GraphicsMagick's gm' : \"%s\"\n"
 30984                               "Path of temporary filename : \"%s\"",
 30985                               pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 30986       } else cimg::fclose(file);
 30987       load_pnm(filetmp);
 30988       cimg_std::remove(filetmp);
 30989       return *this;
 30992     static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
 30993       return CImg<T>().load_graphicsmagick_external(filename);
 30996     //! Load a gzipped image file, using external tool 'gunzip'.
 30997     CImg<T>& load_gzip_external(const char *const filename) {
 30998       if (!filename)
 30999         throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
 31000                               pixel_type());
 31001       char command[1024], filetmp[512], body[512];
 31002       const char
 31003         *ext = cimg::split_filename(filename,body),
 31004         *ext2 = cimg::split_filename(body,0);
 31005       cimg_std::FILE *file = 0;
 31006       do {
 31007         if (!cimg::strcasecmp(ext,"gz")) {
 31008           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 31009                                   cimg::filenamerand(),ext2);
 31010           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 31011                                   cimg::filenamerand());
 31012         } else {
 31013            if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 31014                                   cimg::filenamerand(),ext);
 31015            else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 31016                              cimg::filenamerand());
 31018         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 31019       } while (file);
 31020       cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 31021       cimg::system(command);
 31022       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 31023         cimg::fclose(cimg::fopen(filename,"r"));
 31024         throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
 31025                               pixel_type(),filename);
 31026       } else cimg::fclose(file);
 31027       load(filetmp);
 31028       cimg_std::remove(filetmp);
 31029       return *this;
 31032     static CImg<T> get_load_gzip_external(const char *const filename) {
 31033       return CImg<T>().load_gzip_external(filename);
 31036     //! Load an image using ImageMagick's external tool 'convert'.
 31037     CImg<T>& load_imagemagick_external(const char *const filename) {
 31038       if (!filename)
 31039         throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
 31040                                     pixel_type());
 31041       char command[1024], filetmp[512];
 31042       cimg_std::FILE *file = 0;
 31043 #if cimg_OS==1
 31044       cimg_std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
 31045       file = popen(command,"r");
 31046       if (file) { load_pnm(file); pclose(file); return *this; }
 31047 #endif
 31048       do {
 31049         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 31050         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 31051       } while (file);
 31052       cimg_std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
 31053       cimg::system(command,cimg::imagemagick_path());
 31054       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 31055         cimg::fclose(cimg::fopen(filename,"r"));
 31056         throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
 31057                               "Path of 'ImageMagick's convert' : \"%s\"\n"
 31058                               "Path of temporary filename : \"%s\"",
 31059                               pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 31060       } else cimg::fclose(file);
 31061       load_pnm(filetmp);
 31062       cimg_std::remove(filetmp);
 31063       return *this;
 31066     static CImg<T> get_load_imagemagick_external(const char *const filename) {
 31067       return CImg<T>().load_imagemagick_external(filename);
 31070     //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
 31071     CImg<T>& load_medcon_external(const char *const filename) {
 31072       if (!filename)
 31073         throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
 31074                                     pixel_type());
 31075       char command[1024], filetmp[512], body[512];
 31076       cimg::fclose(cimg::fopen(filename,"r"));
 31077       cimg_std::FILE *file = 0;
 31078       do {
 31079         cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
 31080         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 31081       } while (file);
 31082       cimg_std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
 31083       cimg::system(command);
 31084       cimg::split_filename(filetmp,body);
 31085       cimg_std::sprintf(command,"m000-%s.hdr",body);
 31086       file = cimg_std::fopen(command,"rb");
 31087       if (!file) {
 31088         throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
 31089                               "Path of 'medcon' : \"%s\"\n"
 31090                               "Path of temporary filename : \"%s\"",
 31091                               pixel_type(),filename,cimg::medcon_path(),filetmp);
 31092       } else cimg::fclose(file);
 31093       load_analyze(command);
 31094       cimg_std::remove(command);
 31095       cimg_std::sprintf(command,"m000-%s.img",body);
 31096       cimg_std::remove(command);
 31097       return *this;
 31100     static CImg<T> get_load_medcon_external(const char *const filename) {
 31101       return CImg<T>().load_medcon_external(filename);
 31104     //! Load a RAW Color Camera image file, using external tool 'dcraw'.
 31105     CImg<T>& load_dcraw_external(const char *const filename) {
 31106       if (!filename)
 31107         throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
 31108                                     pixel_type());
 31109       char command[1024], filetmp[512];
 31110       cimg_std::FILE *file = 0;
 31111 #if cimg_OS==1
 31112       cimg_std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
 31113       file = popen(command,"r");
 31114       if (file) { load_pnm(file); pclose(file); return *this; }
 31115 #endif
 31116       do {
 31117         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 31118         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 31119       } while (file);
 31120       cimg_std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
 31121       cimg::system(command,cimg::dcraw_path());
 31122       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 31123         cimg::fclose(cimg::fopen(filename,"r"));
 31124         throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
 31125                               "Path of 'dcraw' : \"%s\"\n"
 31126                               "Path of temporary filename : \"%s\"",
 31127                               pixel_type(),filename,cimg::dcraw_path(),filetmp);
 31128       } else cimg::fclose(file);
 31129       load_pnm(filetmp);
 31130       cimg_std::remove(filetmp);
 31131       return *this;
 31134     static CImg<T> get_load_dcraw_external(const char *const filename) {
 31135       return CImg<T>().load_dcraw_external(filename);
 31138     //! Load an image using ImageMagick's or GraphicsMagick's executables.
 31139     CImg<T>& load_other(const char *const filename) {
 31140       if (!filename)
 31141         throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
 31142                                     pixel_type());
 31143       const unsigned int odebug = cimg::exception_mode();
 31144       cimg::exception_mode() = 0;
 31145       try { load_magick(filename); }
 31146       catch (CImgException&) {
 31147         try { load_imagemagick_external(filename); }
 31148         catch (CImgException&) {
 31149           try { load_graphicsmagick_external(filename); }
 31150           catch (CImgException&) {
 31151             assign();
 31155       cimg::exception_mode() = odebug;
 31156       if (is_empty())
 31157         throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
 31158                               pixel_type(),filename);
 31159       return *this;
 31162     static CImg<T> get_load_other(const char *const filename) {
 31163       return CImg<T>().load_other(filename);
 31166     //@}
 31167     //---------------------------
 31168     //
 31169     //! \name Image File Saving
 31170     //@{
 31171     //---------------------------
 31173     //! Save the image as a file.
 31174     /**
 31175        The used file format is defined by the file extension in the filename \p filename.
 31176        Parameter \p number can be used to add a 6-digit number to the filename before saving.
 31177     **/
 31178     const CImg<T>& save(const char *const filename, const int number=-1) const {
 31179       if (is_empty())
 31180         throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31181                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 31182       if (!filename)
 31183         throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
 31184                                     pixel_type(),width,height,depth,dim,data);
 31185       const char *ext = cimg::split_filename(filename);
 31186       char nfilename[1024];
 31187       const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
 31188 #ifdef cimg_save_plugin
 31189       cimg_save_plugin(fn);
 31190 #endif
 31191 #ifdef cimg_save_plugin1
 31192       cimg_save_plugin1(fn);
 31193 #endif
 31194 #ifdef cimg_save_plugin2
 31195       cimg_save_plugin2(fn);
 31196 #endif
 31197 #ifdef cimg_save_plugin3
 31198       cimg_save_plugin3(fn);
 31199 #endif
 31200 #ifdef cimg_save_plugin4
 31201       cimg_save_plugin4(fn);
 31202 #endif
 31203 #ifdef cimg_save_plugin5
 31204       cimg_save_plugin5(fn);
 31205 #endif
 31206 #ifdef cimg_save_plugin6
 31207       cimg_save_plugin6(fn);
 31208 #endif
 31209 #ifdef cimg_save_plugin7
 31210       cimg_save_plugin7(fn);
 31211 #endif
 31212 #ifdef cimg_save_plugin8
 31213       cimg_save_plugin8(fn);
 31214 #endif
 31215       // ASCII formats
 31216       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
 31217       if (!cimg::strcasecmp(ext,"dlm") ||
 31218           !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
 31219       if (!cimg::strcasecmp(ext,"cpp") ||
 31220           !cimg::strcasecmp(ext,"hpp") ||
 31221           !cimg::strcasecmp(ext,"h") ||
 31222           !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
 31224       // 2D binary formats
 31225       if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
 31226       if (!cimg::strcasecmp(ext,"jpg") ||
 31227           !cimg::strcasecmp(ext,"jpeg") ||
 31228           !cimg::strcasecmp(ext,"jpe") ||
 31229           !cimg::strcasecmp(ext,"jfif") ||
 31230           !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
 31231       if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
 31232       if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
 31233       if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
 31234       if (!cimg::strcasecmp(ext,"pgm") ||
 31235           !cimg::strcasecmp(ext,"ppm") ||
 31236           !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
 31237       if (!cimg::strcasecmp(ext,"tif") ||
 31238           !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
 31240       // 3D binary formats
 31241       if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 31242       if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
 31243       if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
 31244       if (!cimg::strcasecmp(ext,"hdr") ||
 31245           !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
 31246       if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
 31247       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
 31248       if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
 31250       // Archive files
 31251       if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 31253       // Image sequences
 31254       if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 31255       if (!cimg::strcasecmp(ext,"avi") ||
 31256           !cimg::strcasecmp(ext,"mov") ||
 31257           !cimg::strcasecmp(ext,"asf") ||
 31258           !cimg::strcasecmp(ext,"divx") ||
 31259           !cimg::strcasecmp(ext,"flv") ||
 31260           !cimg::strcasecmp(ext,"mpg") ||
 31261           !cimg::strcasecmp(ext,"m1v") ||
 31262           !cimg::strcasecmp(ext,"m2v") ||
 31263           !cimg::strcasecmp(ext,"m4v") ||
 31264           !cimg::strcasecmp(ext,"mjp") ||
 31265           !cimg::strcasecmp(ext,"mkv") ||
 31266           !cimg::strcasecmp(ext,"mpe") ||
 31267           !cimg::strcasecmp(ext,"movie") ||
 31268           !cimg::strcasecmp(ext,"ogm") ||
 31269           !cimg::strcasecmp(ext,"qt") ||
 31270           !cimg::strcasecmp(ext,"rm") ||
 31271           !cimg::strcasecmp(ext,"vob") ||
 31272           !cimg::strcasecmp(ext,"wmv") ||
 31273           !cimg::strcasecmp(ext,"xvid") ||
 31274           !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
 31275       return save_other(fn);
 31278     // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
 31279     const CImg<T>& _save_ascii(cimg_std::FILE *const file, const char *const filename) const {
 31280       if (is_empty())
 31281         throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31282                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31283       if (!file && !filename)
 31284         throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31285                                     pixel_type(),width,height,depth,dim,data);
 31286       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 31287       cimg_std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
 31288       const T* ptrs = data;
 31289       cimg_forYZV(*this,y,z,v) {
 31290         cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g ",(double)*(ptrs++));
 31291         cimg_std::fputc('\n',nfile);
 31293       if (!file) cimg::fclose(nfile);
 31294       return *this;
 31297     //! Save the image as an ASCII file (ASCII Raw + simple header).
 31298     const CImg<T>& save_ascii(const char *const filename) const {
 31299       return _save_ascii(0,filename);
 31302     //! Save the image as an ASCII file (ASCII Raw + simple header).
 31303     const CImg<T>& save_ascii(cimg_std::FILE *const file) const {
 31304       return _save_ascii(file,0);
 31307     // Save the image as a C or CPP source file (internal).
 31308     const CImg<T>& _save_cpp(cimg_std::FILE *const file, const char *const filename) const {
 31309       if (!file && !filename)
 31310         throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31311                                     pixel_type(),width,height,depth,dim,data);
 31312       if (is_empty())
 31313         throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31314                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31315       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 31316       char varname[1024] = { 0 };
 31317       if (filename) cimg_std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
 31318       if (varname[0]=='\0') cimg_std::sprintf(varname,"unnamed");
 31319       cimg_std::fprintf(nfile,
 31320                    "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
 31321                    "%s data_%s[] = { \n  ",
 31322                    varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
 31323       for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
 31324         cimg_std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
 31325         if (off==siz) cimg_std::fprintf(nfile," };\n");
 31326         else if (!((off+1)%16)) cimg_std::fprintf(nfile,",\n  ");
 31327         else cimg_std::fprintf(nfile,", ");
 31329       if (!file) cimg::fclose(nfile);
 31330       return *this;
 31333     //! Save the image as a CPP source file.
 31334     const CImg<T>& save_cpp(const char *const filename) const {
 31335       return _save_cpp(0,filename);
 31338     //! Save the image as a CPP source file.
 31339     const CImg<T>& save_cpp(cimg_std::FILE *const file) const {
 31340       return _save_cpp(file,0);
 31343     // Save the image as a DLM file (internal).
 31344     const CImg<T>& _save_dlm(cimg_std::FILE *const file, const char *const filename) const {
 31345       if (is_empty())
 31346         throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31347                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31348       if (!file && !filename)
 31349         throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31350                                     pixel_type(),width,height,depth,dim,data);
 31351       if (depth>1)
 31352         cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
 31353                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31354       if (dim>1)
 31355         cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
 31356                    "Pixel values along V will be unrolled.",
 31357                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31359       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 31360       const T* ptrs = data;
 31361       cimg_forYZV(*this,y,z,v) {
 31362         cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
 31363         cimg_std::fputc('\n',nfile);
 31365       if (!file) cimg::fclose(nfile);
 31366       return *this;
 31369     //! Save the image as a DLM file.
 31370     const CImg<T>& save_dlm(const char *const filename) const {
 31371       return _save_dlm(0,filename);
 31374     //! Save the image as a DLM file.
 31375     const CImg<T>& save_dlm(cimg_std::FILE *const file) const {
 31376       return _save_dlm(file,0);
 31379    // Save the image as a BMP file (internal).
 31380     const CImg<T>& _save_bmp(cimg_std::FILE *const file, const char *const filename) const {
 31381       if (is_empty())
 31382         throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31383                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31384       if (!file && !filename)
 31385         throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31386                                     pixel_type(),width,height,depth,dim,data);
 31387       if (depth>1)
 31388         cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 31389                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31390       if (dim>3)
 31391         cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
 31392                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31394       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 31395       unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
 31396       const unsigned int
 31397         align = (4 - (3*width)%4)%4,
 31398         buf_size = (3*width+align)*dimy(),
 31399         file_size = 54 + buf_size;
 31400       header[0] = 'B'; header[1] = 'M';
 31401       header[0x02] = file_size&0xFF;
 31402       header[0x03] = (file_size>>8)&0xFF;
 31403       header[0x04] = (file_size>>16)&0xFF;
 31404       header[0x05] = (file_size>>24)&0xFF;
 31405       header[0x0A] = 0x36;
 31406       header[0x0E] = 0x28;
 31407       header[0x12] = width&0xFF;
 31408       header[0x13] = (width>>8)&0xFF;
 31409       header[0x14] = (width>>16)&0xFF;
 31410       header[0x15] = (width>>24)&0xFF;
 31411       header[0x16] = height&0xFF;
 31412       header[0x17] = (height>>8)&0xFF;
 31413       header[0x18] = (height>>16)&0xFF;
 31414       header[0x19] = (height>>24)&0xFF;
 31415       header[0x1A] = 1;
 31416       header[0x1B] = 0;
 31417       header[0x1C] = 24;
 31418       header[0x1D] = 0;
 31419       header[0x22] = buf_size&0xFF;
 31420       header[0x23] = (buf_size>>8)&0xFF;
 31421       header[0x24] = (buf_size>>16)&0xFF;
 31422       header[0x25] = (buf_size>>24)&0xFF;
 31423       header[0x27] = 0x1;
 31424       header[0x2B] = 0x1;
 31425       cimg::fwrite(header,54,nfile);
 31427       const T
 31428         *pR = ptr(0,height-1,0,0),
 31429         *pG = (dim>=2)?ptr(0,height-1,0,1):0,
 31430         *pB = (dim>=3)?ptr(0,height-1,0,2):0;
 31432       switch (dim) {
 31433       case 1 : {
 31434         cimg_forY(*this,y) { cimg_forX(*this,x) {
 31435           const unsigned char val = (unsigned char)*(pR++);
 31436           cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile);
 31438         cimg::fwrite(align_buf,align,nfile);
 31439         pR-=2*width;
 31440         }} break;
 31441       case 2 : {
 31442         cimg_forY(*this,y) { cimg_forX(*this,x) {
 31443           cimg_std::fputc(0,nfile);
 31444           cimg_std::fputc((unsigned char)(*(pG++)),nfile);
 31445           cimg_std::fputc((unsigned char)(*(pR++)),nfile);
 31447         cimg::fwrite(align_buf,align,nfile);
 31448         pR-=2*width; pG-=2*width;
 31449         }} break;
 31450       default : {
 31451         cimg_forY(*this,y) { cimg_forX(*this,x) {
 31452           cimg_std::fputc((unsigned char)(*(pB++)),nfile);
 31453           cimg_std::fputc((unsigned char)(*(pG++)),nfile);
 31454           cimg_std::fputc((unsigned char)(*(pR++)),nfile);
 31456         cimg::fwrite(align_buf,align,nfile);
 31457         pR-=2*width; pG-=2*width; pB-=2*width;
 31461       if (!file) cimg::fclose(nfile);
 31462       return *this;
 31465     //! Save the image as a BMP file.
 31466     const CImg<T>& save_bmp(const char *const filename) const {
 31467       return _save_bmp(0,filename);
 31470     //! Save the image as a BMP file.
 31471     const CImg<T>& save_bmp(cimg_std::FILE *const file) const {
 31472       return _save_bmp(file,0);
 31475     // Save a file in JPEG format (internal).
 31476     const CImg<T>& _save_jpeg(cimg_std::FILE *const file, const char *const filename, const unsigned int quality) const {
 31477       if (is_empty())
 31478         throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31479                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31480       if (!file && !filename)
 31481         throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 31482                                     pixel_type(),width,height,depth,dim,data);
 31483       if (depth>1)
 31484         cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 31485                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31486 #ifndef cimg_use_jpeg
 31487       if (!file) return save_other(filename,quality);
 31488       else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
 31489                                  pixel_type());
 31490 #else
 31491       // Fill pixel buffer
 31492       unsigned char *buf;
 31493       unsigned int dimbuf = 0;
 31494       J_COLOR_SPACE colortype = JCS_RGB;
 31495       switch (dim) {
 31496       case 1 : { // Greyscale images
 31497         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
 31498         colortype = JCS_GRAYSCALE;
 31499         const T *ptr_g = data;
 31500         cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
 31501       } break;
 31502       case 2 : { // RG images
 31503         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 31504         const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
 31505         colortype = JCS_RGB;
 31506         cimg_forXY(*this,x,y) {
 31507           *(buf2++) = (unsigned char)*(ptr_r++);
 31508           *(buf2++) = (unsigned char)*(ptr_g++);
 31509           *(buf2++) = 0;
 31511       } break;
 31512       case 3 : { // RGB images
 31513         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 31514         const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 31515         colortype = JCS_RGB;
 31516         cimg_forXY(*this,x,y) {
 31517           *(buf2++) = (unsigned char)*(ptr_r++);
 31518           *(buf2++) = (unsigned char)*(ptr_g++);
 31519           *(buf2++) = (unsigned char)*(ptr_b++);
 31521       } break;
 31522       default : { // CMYK images
 31523         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
 31524         const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
 31525         colortype = JCS_CMYK;
 31526         cimg_forXY(*this,x,y) {
 31527           *(buf2++) = (unsigned char)*(ptr_r++);
 31528           *(buf2++) = (unsigned char)*(ptr_g++);
 31529           *(buf2++) = (unsigned char)*(ptr_b++);
 31530           *(buf2++) = (unsigned char)*(ptr_a++);
 31535       // Call libjpeg functions
 31536       struct jpeg_compress_struct cinfo;
 31537       struct jpeg_error_mgr jerr;
 31538       cinfo.err = jpeg_std_error(&jerr);
 31539       jpeg_create_compress(&cinfo);
 31540       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 31541       jpeg_stdio_dest(&cinfo,nfile);
 31542       cinfo.image_width = width;
 31543       cinfo.image_height = height;
 31544       cinfo.input_components = dimbuf;
 31545       cinfo.in_color_space = colortype;
 31546       jpeg_set_defaults(&cinfo);
 31547       jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
 31548       jpeg_start_compress(&cinfo,TRUE);
 31550       const unsigned int row_stride = width*dimbuf;
 31551       JSAMPROW row_pointer[1];
 31552       while (cinfo.next_scanline < cinfo.image_height) {
 31553         row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
 31554         jpeg_write_scanlines(&cinfo,row_pointer,1);
 31556       jpeg_finish_compress(&cinfo);
 31558       delete[] buf;
 31559       if (!file) cimg::fclose(nfile);
 31560       jpeg_destroy_compress(&cinfo);
 31561       return *this;
 31562 #endif
 31565     //! Save a file in JPEG format.
 31566     const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
 31567       return _save_jpeg(0,filename,quality);
 31570     //! Save a file in JPEG format.
 31571     const CImg<T>& save_jpeg(cimg_std::FILE *const file, const unsigned int quality=100) const {
 31572       return _save_jpeg(file,0,quality);
 31575     //! Save the image using built-in ImageMagick++ library.
 31576     const CImg<T>& save_magick(const char *const filename) const {
 31577       if (is_empty())
 31578         throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31579                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 31580       if (!filename)
 31581         throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31582                                     pixel_type(),width,height,depth,dim,data);
 31583 #ifdef cimg_use_magick
 31584       Magick::Image image(Magick::Geometry(width,height),"black");
 31585       image.type(Magick::TrueColorType);
 31586       const T
 31587         *rdata = ptr(0,0,0,0),
 31588         *gdata = dim>1?ptr(0,0,0,1):0,
 31589         *bdata = dim>2?ptr(0,0,0,2):0;
 31590       Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
 31591       switch (dim) {
 31592       case 1 : // Scalar images
 31593         for (unsigned int off = width*height; off; --off) {
 31594           pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 31595           ++pixels;
 31597         break;
 31598       case 2 : // RG images
 31599         for (unsigned int off = width*height; off; --off) {
 31600           pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 31601           pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 31602           pixels->blue = 0;
 31603           ++pixels;
 31605         break;
 31606       default : // RGB images
 31607         for (unsigned int off = width*height; off; --off) {
 31608           pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 31609           pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 31610           pixels->blue = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
 31611           ++pixels;
 31614       image.syncPixels();
 31615       image.write(filename);
 31616 #else
 31617       throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
 31618                             pixel_type(),filename);
 31619 #endif
 31620       return *this;
 31623     // Save an image to a PNG file (internal).
 31624     // Most of this function has been written by Eric Fausett
 31625     const CImg<T>& _save_png(cimg_std::FILE *const file, const char *const filename) const {
 31626       if (is_empty())
 31627         throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31628                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31629       if (!filename)
 31630         throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 31631                                     pixel_type(),width,height,depth,dim,data);
 31632       if (depth>1)
 31633         cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 31634                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31635 #ifndef cimg_use_png
 31636       if (!file) return save_other(filename);
 31637       else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
 31638                                  pixel_type());
 31639 #else
 31640       const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 31641       cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
 31643       // Setup PNG structures for write
 31644       png_voidp user_error_ptr = 0;
 31645       png_error_ptr user_error_fn = 0, user_warning_fn = 0;
 31646       png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
 31647       if(!png_ptr){
 31648         if (!file) cimg::fclose(nfile);
 31649         throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
 31650                               pixel_type(),nfilename?nfilename:"(FILE*)");
 31652       png_infop info_ptr = png_create_info_struct(png_ptr);
 31653       if (!info_ptr) {
 31654         png_destroy_write_struct(&png_ptr,(png_infopp)0);
 31655         if (!file) cimg::fclose(nfile);
 31656         throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
 31657                               pixel_type(),nfilename?nfilename:"(FILE*)");
 31659       if (setjmp(png_jmpbuf(png_ptr))) {
 31660         png_destroy_write_struct(&png_ptr, &info_ptr);
 31661         if (!file) cimg::fclose(nfile);
 31662         throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 31663                               pixel_type(),nfilename?nfilename:"(FILE*)");
 31665       png_init_io(png_ptr, nfile);
 31666       png_uint_32 width = dimx(), height = dimy();
 31667       float vmin, vmax = (float)maxmin(vmin);
 31668       const int bit_depth = (vmin<0 || vmax>=256)?16:8;
 31669       int color_type;
 31670       switch (dimv()) {
 31671       case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
 31672       case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
 31673       case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
 31674       default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 31676       const int interlace_type = PNG_INTERLACE_NONE;
 31677       const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
 31678       const int filter_method = PNG_FILTER_TYPE_DEFAULT;
 31679       png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
 31680       png_write_info(png_ptr, info_ptr);
 31681       const int byte_depth = bit_depth>>3;
 31682       const int numChan = dimv()>4?4:dimv();
 31683       const int pixel_bit_depth_flag = numChan * (bit_depth-1);
 31685       // Allocate Memory for Image Save and Fill pixel data
 31686       png_bytep *imgData = new png_byte*[height];
 31687       for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
 31688       const T *pC0 = ptr(0,0,0,0);
 31689       switch (pixel_bit_depth_flag) {
 31690       case 7 :  { // Gray 8-bit
 31691         cimg_forY(*this,y) {
 31692           unsigned char *ptrd = imgData[y];
 31693           cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
 31695       } break;
 31696       case 14 : { // Gray w/ Alpha 8-bit
 31697         const T *pC1 = ptr(0,0,0,1);
 31698         cimg_forY(*this,y) {
 31699           unsigned char *ptrd = imgData[y];
 31700           cimg_forX(*this,x) {
 31701             *(ptrd++) = (unsigned char)*(pC0++);
 31702             *(ptrd++) = (unsigned char)*(pC1++);
 31705       } break;
 31706       case 21 :  { // RGB 8-bit
 31707         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 31708         cimg_forY(*this,y) {
 31709           unsigned char *ptrd = imgData[y];
 31710           cimg_forX(*this,x) {
 31711             *(ptrd++) = (unsigned char)*(pC0++);
 31712             *(ptrd++) = (unsigned char)*(pC1++);
 31713             *(ptrd++) = (unsigned char)*(pC2++);
 31716       } break;
 31717       case 28 : { // RGB x/ Alpha 8-bit
 31718         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 31719         cimg_forY(*this,y){
 31720           unsigned char *ptrd = imgData[y];
 31721           cimg_forX(*this,x){
 31722             *(ptrd++) = (unsigned char)*(pC0++);
 31723             *(ptrd++) = (unsigned char)*(pC1++);
 31724             *(ptrd++) = (unsigned char)*(pC2++);
 31725             *(ptrd++) = (unsigned char)*(pC3++);
 31728       } break;
 31729       case 15 : { // Gray 16-bit
 31730         cimg_forY(*this,y){
 31731           unsigned short *ptrd = (unsigned short*)(imgData[y]);
 31732           cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
 31733           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
 31735       } break;
 31736       case 30 : { // Gray w/ Alpha 16-bit
 31737         const T *pC1 = ptr(0,0,0,1);
 31738         cimg_forY(*this,y){
 31739           unsigned short *ptrd = (unsigned short*)(imgData[y]);
 31740           cimg_forX(*this,x) {
 31741             *(ptrd++) = (unsigned short)*(pC0++);
 31742             *(ptrd++) = (unsigned short)*(pC1++);
 31744           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
 31746       } break;
 31747       case 45 : { // RGB 16-bit
 31748         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 31749         cimg_forY(*this,y) {
 31750           unsigned short *ptrd = (unsigned short*)(imgData[y]);
 31751           cimg_forX(*this,x) {
 31752             *(ptrd++) = (unsigned short)*(pC0++);
 31753             *(ptrd++) = (unsigned short)*(pC1++);
 31754             *(ptrd++) = (unsigned short)*(pC2++);
 31756           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
 31758       } break;
 31759       case 60 : { // RGB w/ Alpha 16-bit
 31760         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 31761         cimg_forY(*this,y) {
 31762           unsigned short *ptrd = (unsigned short*)(imgData[y]);
 31763           cimg_forX(*this,x) {
 31764             *(ptrd++) = (unsigned short)*(pC0++);
 31765             *(ptrd++) = (unsigned short)*(pC1++);
 31766             *(ptrd++) = (unsigned short)*(pC2++);
 31767             *(ptrd++) = (unsigned short)*(pC3++);
 31769           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
 31771       } break;
 31772       default :
 31773         if (!file) cimg::fclose(nfile);
 31774         throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 31775                               pixel_type(),nfilename?nfilename:"(FILE*)");
 31777       png_write_image(png_ptr, imgData);
 31778       png_write_end(png_ptr, info_ptr);
 31779       png_destroy_write_struct(&png_ptr, &info_ptr);
 31781       // Deallocate Image Write Memory
 31782       cimg_forY(*this,n) delete[] imgData[n];
 31783       delete[] imgData;
 31784       if (!file) cimg::fclose(nfile);
 31785       return *this;
 31786 #endif
 31789     //! Save a file in PNG format
 31790     const CImg<T>& save_png(const char *const filename) const {
 31791       return _save_png(0,filename);
 31794     //! Save a file in PNG format
 31795     const CImg<T>& save_png(cimg_std::FILE *const file) const {
 31796       return _save_png(file,0);
 31799     // Save the image as a PNM file (internal function).
 31800     const CImg<T>& _save_pnm(cimg_std::FILE *const file, const char *const filename) const {
 31801       if (!file && !filename)
 31802         throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31803                                     pixel_type(),width,height,depth,dim,data);
 31804       if (is_empty())
 31805         throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31806                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31807       double stmin, stmax = (double)maxmin(stmin);
 31808       if (depth>1)
 31809         cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 31810                  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31811       if (dim>3)
 31812         cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
 31813                  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31814       if (stmin<0 || stmax>65535)
 31815         cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
 31816                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
 31817       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 31818       const T
 31819         *ptrR = ptr(0,0,0,0),
 31820         *ptrG = (dim>=2)?ptr(0,0,0,1):0,
 31821         *ptrB = (dim>=3)?ptr(0,0,0,2):0;
 31822       const unsigned int buf_size = width*height*(dim==1?1:3);
 31824       cimg_std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
 31825                    (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
 31827       switch (dim) {
 31828       case 1 : { // Scalar image
 31829         if (stmax<256) { // Binary PGM 8 bits
 31830           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 31831           cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
 31832           cimg::fwrite(ptrd,buf_size,nfile);
 31833           delete[] ptrd;
 31834         } else {             // Binary PGM 16 bits
 31835           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 31836           cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
 31837           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 31838           cimg::fwrite(ptrd,buf_size,nfile);
 31839           delete[] ptrd;
 31841       } break;
 31842       case 2 : { // RG image
 31843         if (stmax<256) { // Binary PPM 8 bits
 31844           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 31845           cimg_forXY(*this,x,y) {
 31846             *(xptrd++) = (unsigned char)*(ptrR++);
 31847             *(xptrd++) = (unsigned char)*(ptrG++);
 31848             *(xptrd++) = 0;
 31850           cimg::fwrite(ptrd,buf_size,nfile);
 31851           delete[] ptrd;
 31852         } else {             // Binary PPM 16 bits
 31853           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 31854           cimg_forXY(*this,x,y) {
 31855             *(xptrd++) = (unsigned short)*(ptrR++);
 31856             *(xptrd++) = (unsigned short)*(ptrG++);
 31857             *(xptrd++) = 0;
 31859           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 31860           cimg::fwrite(ptrd,buf_size,nfile);
 31861           delete[] ptrd;
 31863       } break;
 31864       default : { // RGB image
 31865         if (stmax<256) { // Binary PPM 8 bits
 31866           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 31867           cimg_forXY(*this,x,y) {
 31868             *(xptrd++) = (unsigned char)*(ptrR++);
 31869             *(xptrd++) = (unsigned char)*(ptrG++);
 31870             *(xptrd++) = (unsigned char)*(ptrB++);
 31872           cimg::fwrite(ptrd,buf_size,nfile);
 31873           delete[] ptrd;
 31874         } else {             // Binary PPM 16 bits
 31875           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 31876           cimg_forXY(*this,x,y) {
 31877             *(xptrd++) = (unsigned short)*(ptrR++);
 31878             *(xptrd++) = (unsigned short)*(ptrG++);
 31879             *(xptrd++) = (unsigned short)*(ptrB++);
 31881           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 31882           cimg::fwrite(ptrd,buf_size,nfile);
 31883           delete[] ptrd;
 31887       if (!file) cimg::fclose(nfile);
 31888       return *this;
 31891     //! Save the image as a PNM file.
 31892     const CImg<T>& save_pnm(const char *const filename) const {
 31893       return _save_pnm(0,filename);
 31896     //! Save the image as a PNM file.
 31897     const CImg<T>& save_pnm(cimg_std::FILE *const file) const {
 31898       return _save_pnm(file,0);
 31901     // Save the image as a RGB file (internal).
 31902     const CImg<T>& _save_rgb(cimg_std::FILE *const file, const char *const filename) const {
 31903       if (is_empty())
 31904         throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31905                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31906       if (!file && !filename)
 31907         throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31908                                     pixel_type(),width,height,depth,dim,data);
 31909       if (dim!=3)
 31910         cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
 31911                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31912       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 31913       const unsigned int wh = width*height;
 31914       unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
 31915       const T
 31916         *ptr1 = ptr(0,0,0,0),
 31917         *ptr2 = dim>1?ptr(0,0,0,1):0,
 31918         *ptr3 = dim>2?ptr(0,0,0,2):0;
 31919       switch (dim) {
 31920       case 1 : { // Scalar image
 31921         for (unsigned int k=0; k<wh; ++k) {
 31922           const unsigned char val = (unsigned char)*(ptr1++);
 31923           *(nbuffer++) = val;
 31924           *(nbuffer++) = val;
 31925           *(nbuffer++) = val;
 31926         }} break;
 31927       case 2 : { // RG image
 31928         for (unsigned int k=0; k<wh; ++k) {
 31929           *(nbuffer++) = (unsigned char)(*(ptr1++));
 31930           *(nbuffer++) = (unsigned char)(*(ptr2++));
 31931           *(nbuffer++) = 0;
 31932         }} break;
 31933       default : { // RGB image
 31934         for (unsigned int k=0; k<wh; ++k) {
 31935           *(nbuffer++) = (unsigned char)(*(ptr1++));
 31936           *(nbuffer++) = (unsigned char)(*(ptr2++));
 31937           *(nbuffer++) = (unsigned char)(*(ptr3++));
 31941       cimg::fwrite(buffer,3*wh,nfile);
 31942       if (!file) cimg::fclose(nfile);
 31943       delete[] buffer;
 31944       return *this;
 31947     //! Save the image as a RGB file.
 31948     const CImg<T>& save_rgb(const char *const filename) const {
 31949       return _save_rgb(0,filename);
 31952     //! Save the image as a RGB file.
 31953     const CImg<T>& save_rgb(cimg_std::FILE *const file) const {
 31954       return _save_rgb(file,0);
 31957     // Save the image as a RGBA file (internal).
 31958     const CImg<T>& _save_rgba(cimg_std::FILE *const file, const char *const filename) const {
 31959       if (is_empty())
 31960         throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 31961                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31962       if (!file && !filename)
 31963         throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 31964                                     pixel_type(),width,height,depth,dim,data);
 31965       if (dim!=4)
 31966         cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
 31967                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 31968       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 31969       const unsigned int wh = width*height;
 31970       unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
 31971       const T
 31972         *ptr1 = ptr(0,0,0,0),
 31973         *ptr2 = dim>1?ptr(0,0,0,1):0,
 31974         *ptr3 = dim>2?ptr(0,0,0,2):0,
 31975         *ptr4 = dim>3?ptr(0,0,0,3):0;
 31976       switch (dim) {
 31977       case 1 : { // Scalar images
 31978         for (unsigned int k=0; k<wh; ++k) {
 31979           const unsigned char val = (unsigned char)*(ptr1++);
 31980           *(nbuffer++) = val;
 31981           *(nbuffer++) = val;
 31982           *(nbuffer++) = val;
 31983           *(nbuffer++) = 255;
 31984         }} break;
 31985       case 2 : { // RG images
 31986         for (unsigned int k=0; k<wh; ++k) {
 31987           *(nbuffer++) = (unsigned char)(*(ptr1++));
 31988           *(nbuffer++) = (unsigned char)(*(ptr2++));
 31989           *(nbuffer++) = 0;
 31990           *(nbuffer++) = 255;
 31991         }} break;
 31992       case 3 : { // RGB images
 31993         for (unsigned int k=0; k<wh; ++k) {
 31994           *(nbuffer++) = (unsigned char)(*(ptr1++));
 31995           *(nbuffer++) = (unsigned char)(*(ptr2++));
 31996           *(nbuffer++) = (unsigned char)(*(ptr3++));
 31997           *(nbuffer++) = 255;
 31998         }} break;
 31999       default : { // RGBA images
 32000         for (unsigned int k=0; k<wh; ++k) {
 32001           *(nbuffer++) = (unsigned char)(*(ptr1++));
 32002           *(nbuffer++) = (unsigned char)(*(ptr2++));
 32003           *(nbuffer++) = (unsigned char)(*(ptr3++));
 32004           *(nbuffer++) = (unsigned char)(*(ptr4++));
 32008       cimg::fwrite(buffer,4*wh,nfile);
 32009       if (!file) cimg::fclose(nfile);
 32010       delete[] buffer;
 32011       return *this;
 32014     //! Save the image as a RGBA file.
 32015     const CImg<T>& save_rgba(const char *const filename) const {
 32016       return _save_rgba(0,filename);
 32019     //! Save the image as a RGBA file.
 32020     const CImg<T>& save_rgba(cimg_std::FILE *const file) const {
 32021       return _save_rgba(file,0);
 32024     // Save a plane into a tiff file
 32025 #ifdef cimg_use_tiff
 32026     const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
 32027       if (is_empty() || !tif) return *this;
 32028       const char *const filename = TIFFFileName(tif);
 32029       uint32 rowsperstrip = (uint32)-1;
 32030       uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
 32031       if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
 32032       else photometric = PHOTOMETRIC_MINISBLACK;
 32033       TIFFSetDirectory(tif,directory);
 32034       TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
 32035       TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
 32036       TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
 32037       TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
 32038       if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
 32039       else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
 32040       else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
 32041       TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
 32042       TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
 32043       TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
 32044       TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
 32045       rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
 32046       TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
 32047       TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
 32048       TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
 32049       T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
 32050       if (buf){
 32051         for (unsigned int row = 0; row<height; row+=rowsperstrip) {
 32052           uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
 32053           tstrip_t strip = TIFFComputeStrip(tif,row,0);
 32054           tsize_t i = 0;
 32055           for (unsigned int rr = 0; rr<nrow; ++rr)
 32056             for (unsigned int cc = 0; cc<width; ++cc)
 32057               for (unsigned int vv = 0; vv<spp; ++vv)
 32058                 buf[i++] = (*this)(cc,row+rr,vv);
 32059           if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
 32060             throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occured while writing a strip.",
 32061                                 pixel_type(),filename?filename:"(FILE*)");
 32063         _TIFFfree(buf);
 32065       TIFFWriteDirectory(tif);
 32066       return (*this);
 32068 #endif
 32070     //! Save a file in TIFF format.
 32071     const CImg<T>& save_tiff(const char *const filename) const {
 32072       if (is_empty())
 32073         throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32074                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32075       if (!filename)
 32076         throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
 32077                                     pixel_type(),width,height,depth,dim,data);
 32078 #ifdef cimg_use_tiff
 32079       TIFF *tif = TIFFOpen(filename,"w");
 32080       if (tif) {
 32081         cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
 32082         TIFFClose(tif);
 32083       } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
 32084                                  pixel_type(),filename);
 32085 #else
 32086       return save_other(filename);
 32087 #endif
 32088       return *this;
 32091     //! Save the image as an ANALYZE7.5 or NIFTI file.
 32092     const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
 32093       if (is_empty())
 32094         throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32095                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32096       if (!filename)
 32097         throw CImgArgumentException("CImg<%s>::save_analyze() :  Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32098                                     pixel_type(),width,height,depth,dim,data);
 32099       cimg_std::FILE *file;
 32100       char header[348], hname[1024], iname[1024];
 32101       const char *ext = cimg::split_filename(filename);
 32102       short datatype=-1;
 32103       cimg_std::memset(header,0,348);
 32104       if (!ext[0]) { cimg_std::sprintf(hname,"%s.hdr",filename); cimg_std::sprintf(iname,"%s.img",filename); }
 32105       if (!cimg::strncasecmp(ext,"hdr",3)) {
 32106         cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(iname+cimg::strlen(iname)-3,"img");
 32108       if (!cimg::strncasecmp(ext,"img",3)) {
 32109         cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
 32111       if (!cimg::strncasecmp(ext,"nii",3)) {
 32112         cimg_std::strcpy(hname,filename); iname[0] = 0;
 32114       ((int*)(header))[0] = 348;
 32115       cimg_std::sprintf(header+4,"CImg");
 32116       cimg_std::sprintf(header+14," ");
 32117       ((short*)(header+36))[0] = 4096;
 32118       ((char*)(header+38))[0] = 114;
 32119       ((short*)(header+40))[0] = 4;
 32120       ((short*)(header+40))[1] = width;
 32121       ((short*)(header+40))[2] = height;
 32122       ((short*)(header+40))[3] = depth;
 32123       ((short*)(header+40))[4] = dim;
 32124       if (!cimg::strcasecmp(pixel_type(),"bool"))           datatype = 2;
 32125       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
 32126       if (!cimg::strcasecmp(pixel_type(),"char"))           datatype = 2;
 32127       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
 32128       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
 32129       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   datatype = 8;
 32130       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
 32131       if (!cimg::strcasecmp(pixel_type(),"unsigned long"))  datatype = 8;
 32132       if (!cimg::strcasecmp(pixel_type(),"long"))           datatype = 8;
 32133       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
 32134       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
 32135       if (datatype<0)
 32136         throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
 32137                               "is not handled in Analyze7.5 specifications.\n",
 32138                               pixel_type(),filename,pixel_type());
 32139       ((short*)(header+70))[0] = datatype;
 32140       ((short*)(header+72))[0] = sizeof(T);
 32141       ((float*)(header+112))[0] = 1;
 32142       ((float*)(header+76))[0] = 0;
 32143       if (voxsize) {
 32144         ((float*)(header+76))[1] = voxsize[0];
 32145         ((float*)(header+76))[2] = voxsize[1];
 32146         ((float*)(header+76))[3] = voxsize[2];
 32147       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
 32148       file = cimg::fopen(hname,"wb");
 32149       cimg::fwrite(header,348,file);
 32150       if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
 32151       cimg::fwrite(data,size(),file);
 32152       cimg::fclose(file);
 32153       return *this;
 32156     //! Save the image as a .cimg file.
 32157     const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
 32158       CImgList<T>(*this,true).save_cimg(filename,compress);
 32159       return *this;
 32162     // Save the image as a .cimg file.
 32163     const CImg<T>& save_cimg(cimg_std::FILE *const file, const bool compress=false) const {
 32164       CImgList<T>(*this,true).save_cimg(file,compress);
 32165       return *this;
 32168     //! Insert the image into an existing .cimg file, at specified coordinates.
 32169     const CImg<T>& save_cimg(const char *const filename,
 32170                              const unsigned int n0,
 32171                              const unsigned int x0, const unsigned int y0,
 32172                              const unsigned int z0, const unsigned int v0) const {
 32173       CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
 32174       return *this;
 32177     //! Insert the image into an existing .cimg file, at specified coordinates.
 32178     const CImg<T>& save_cimg(cimg_std::FILE *const file,
 32179                              const unsigned int n0,
 32180                              const unsigned int x0, const unsigned int y0,
 32181                              const unsigned int z0, const unsigned int v0) const {
 32182       CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
 32183       return *this;
 32186     //! Save an empty .cimg file with specified dimensions.
 32187     static void save_empty_cimg(const char *const filename,
 32188                                 const unsigned int dx, const unsigned int dy=1,
 32189                                 const unsigned int dz=1, const unsigned int dv=1) {
 32190       return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
 32193     //! Save an empty .cimg file with specified dimensions.
 32194     static void save_empty_cimg(cimg_std::FILE *const file,
 32195                                 const unsigned int dx, const unsigned int dy=1,
 32196                                 const unsigned int dz=1, const unsigned int dv=1) {
 32197       return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
 32200     // Save the image as an INRIMAGE-4 file (internal).
 32201     const CImg<T>& _save_inr(cimg_std::FILE *const file, const char *const filename, const float *const voxsize) const {
 32202       if (is_empty())
 32203         throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32204                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 32205       if (!filename)
 32206         throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 32207                                     pixel_type(),width,height,depth,dim,data);
 32208       int inrpixsize=-1;
 32209       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
 32210       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
 32211       if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
 32212       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
 32213       if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
 32214       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
 32215       if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
 32216       if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
 32217       if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
 32218       if (inrpixsize<=0)
 32219         throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
 32220                               pixel_type(),pixel_type());
 32221       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 32222       char header[257];
 32223       int err = cimg_std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
 32224       if (voxsize) err += cimg_std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
 32225       err += cimg_std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
 32226       cimg_std::memset(header+err,'\n',252-err);
 32227       cimg_std::memcpy(header+252,"##}\n",4);
 32228       cimg::fwrite(header,256,nfile);
 32229       cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
 32230       if (!file) cimg::fclose(nfile);
 32231       return *this;
 32234     //! Save the image as an INRIMAGE-4 file.
 32235     const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
 32236       return _save_inr(0,filename,voxsize);
 32239     //! Save the image as an INRIMAGE-4 file.
 32240     const CImg<T>& save_inr(cimg_std::FILE *const file, const float *const voxsize=0) const {
 32241       return _save_inr(file,0,voxsize);
 32244     // Save the image as a PANDORE-5 file (internal).
 32245     unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
 32246       unsigned int nbdims = 0;
 32247       if (id==2 || id==3 || id==4)    { dims[0] = 1;   dims[1] = width;  nbdims = 2; }
 32248       if (id==5 || id==6 || id==7)    { dims[0] = 1;   dims[1] = height; dims[2] = width;  nbdims=3; }
 32249       if (id==8 || id==9 || id==10)   { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
 32250       if (id==16 || id==17 || id==18) { dims[0] = 3;   dims[1] = height; dims[2] = width;  dims[3] = colorspace; nbdims = 4; }
 32251       if (id==19 || id==20 || id==21) { dims[0] = 3;   dims[1] = depth;  dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
 32252       if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width;  nbdims = 2; }
 32253       if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width;  nbdims=3; }
 32254       if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
 32255       return nbdims;
 32258     const CImg<T>& _save_pandore(cimg_std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
 32259       typedef unsigned char uchar;
 32260       typedef unsigned short ushort;
 32261       typedef unsigned int uint;
 32262       typedef unsigned long ulong;
 32264 #define __cimg_save_pandore_case(dtype) \
 32265        dtype *buffer = new dtype[size()]; \
 32266        const T *ptrs = data; \
 32267        cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
 32268        buffer-=size(); \
 32269        cimg::fwrite(buffer,size(),nfile); \
 32270        delete[] buffer
 32272 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
 32273       if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !cimg::strcmp(stype,pixel_type())) { \
 32274         unsigned int *iheader = (unsigned int*)(header+12); \
 32275         nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
 32276         cimg::fwrite(header,36,nfile); \
 32277         if (sizeof(ulong)==4) { ulong ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
 32278         else if (sizeof(uint)==4) { uint ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (uint)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
 32279         else if (sizeof(ushort)==4) { ushort ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ushort)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
 32280         else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 32281                                    "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 32282                                    depth,dim,data); \
 32283         if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
 32284           __cimg_save_pandore_case(uchar); \
 32285         } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
 32286           if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
 32287           else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
 32288           else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
 32289           else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 32290                                      "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 32291                                      depth,dim,data); \
 32292         } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
 32293           if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
 32294           else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
 32295           else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 32296                                      "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 32297                                      depth,dim,data); \
 32298         } \
 32299         saved = true; \
 32302       if (is_empty())
 32303         throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32304                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 32305       if (!file && !filename)
 32306         throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 32307                                     pixel_type(),width,height,depth,dim,data);
 32308       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 32309       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
 32310                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
 32311       unsigned int nbdims, dims[5];
 32312       bool saved = false;
 32313       _cimg_save_pandore_case(1,1,1,"unsigned char",2);
 32314       _cimg_save_pandore_case(1,1,1,"char",3);
 32315       _cimg_save_pandore_case(1,1,1,"short",3);
 32316       _cimg_save_pandore_case(1,1,1,"unsigned short",3);
 32317       _cimg_save_pandore_case(1,1,1,"unsigned int",3);
 32318       _cimg_save_pandore_case(1,1,1,"int",3);
 32319       _cimg_save_pandore_case(1,1,1,"unsigned long",4);
 32320       _cimg_save_pandore_case(1,1,1,"long",3);
 32321       _cimg_save_pandore_case(1,1,1,"float",4);
 32322       _cimg_save_pandore_case(1,1,1,"double",4);
 32324       _cimg_save_pandore_case(0,1,1,"unsigned char",5);
 32325       _cimg_save_pandore_case(0,1,1,"char",6);
 32326       _cimg_save_pandore_case(0,1,1,"short",6);
 32327       _cimg_save_pandore_case(0,1,1,"unsigned short",6);
 32328       _cimg_save_pandore_case(0,1,1,"unsigned int",6);
 32329       _cimg_save_pandore_case(0,1,1,"int",6);
 32330       _cimg_save_pandore_case(0,1,1,"unsigned long",7);
 32331       _cimg_save_pandore_case(0,1,1,"long",6);
 32332       _cimg_save_pandore_case(0,1,1,"float",7);
 32333       _cimg_save_pandore_case(0,1,1,"double",7);
 32335       _cimg_save_pandore_case(0,0,1,"unsigned char",8);
 32336       _cimg_save_pandore_case(0,0,1,"char",9);
 32337       _cimg_save_pandore_case(0,0,1,"short",9);
 32338       _cimg_save_pandore_case(0,0,1,"unsigned short",9);
 32339       _cimg_save_pandore_case(0,0,1,"unsigned int",9);
 32340       _cimg_save_pandore_case(0,0,1,"int",9);
 32341       _cimg_save_pandore_case(0,0,1,"unsigned long",10);
 32342       _cimg_save_pandore_case(0,0,1,"long",9);
 32343       _cimg_save_pandore_case(0,0,1,"float",10);
 32344       _cimg_save_pandore_case(0,0,1,"double",10);
 32346       _cimg_save_pandore_case(0,1,3,"unsigned char",16);
 32347       _cimg_save_pandore_case(0,1,3,"char",17);
 32348       _cimg_save_pandore_case(0,1,3,"short",17);
 32349       _cimg_save_pandore_case(0,1,3,"unsigned short",17);
 32350       _cimg_save_pandore_case(0,1,3,"unsigned int",17);
 32351       _cimg_save_pandore_case(0,1,3,"int",17);
 32352       _cimg_save_pandore_case(0,1,3,"unsigned long",18);
 32353       _cimg_save_pandore_case(0,1,3,"long",17);
 32354       _cimg_save_pandore_case(0,1,3,"float",18);
 32355       _cimg_save_pandore_case(0,1,3,"double",18);
 32357       _cimg_save_pandore_case(0,0,3,"unsigned char",19);
 32358       _cimg_save_pandore_case(0,0,3,"char",20);
 32359       _cimg_save_pandore_case(0,0,3,"short",20);
 32360       _cimg_save_pandore_case(0,0,3,"unsigned short",20);
 32361       _cimg_save_pandore_case(0,0,3,"unsigned int",20);
 32362       _cimg_save_pandore_case(0,0,3,"int",20);
 32363       _cimg_save_pandore_case(0,0,3,"unsigned long",21);
 32364       _cimg_save_pandore_case(0,0,3,"long",20);
 32365       _cimg_save_pandore_case(0,0,3,"float",21);
 32366       _cimg_save_pandore_case(0,0,3,"double",21);
 32368       _cimg_save_pandore_case(1,1,0,"unsigned char",22);
 32369       _cimg_save_pandore_case(1,1,0,"char",23);
 32370       _cimg_save_pandore_case(1,1,0,"short",23);
 32371       _cimg_save_pandore_case(1,1,0,"unsigned short",23);
 32372       _cimg_save_pandore_case(1,1,0,"unsigned int",23);
 32373       _cimg_save_pandore_case(1,1,0,"int",23);
 32374       _cimg_save_pandore_case(1,1,0,"unsigned long",25);
 32375       _cimg_save_pandore_case(1,1,0,"long",23);
 32376       _cimg_save_pandore_case(1,1,0,"float",25);
 32377       _cimg_save_pandore_case(1,1,0,"double",25);
 32379       _cimg_save_pandore_case(0,1,0,"unsigned char",26);
 32380       _cimg_save_pandore_case(0,1,0,"char",27);
 32381       _cimg_save_pandore_case(0,1,0,"short",27);
 32382       _cimg_save_pandore_case(0,1,0,"unsigned short",27);
 32383       _cimg_save_pandore_case(0,1,0,"unsigned int",27);
 32384       _cimg_save_pandore_case(0,1,0,"int",27);
 32385       _cimg_save_pandore_case(0,1,0,"unsigned long",29);
 32386       _cimg_save_pandore_case(0,1,0,"long",27);
 32387       _cimg_save_pandore_case(0,1,0,"float",29);
 32388       _cimg_save_pandore_case(0,1,0,"double",29);
 32390       _cimg_save_pandore_case(0,0,0,"unsigned char",30);
 32391       _cimg_save_pandore_case(0,0,0,"char",31);
 32392       _cimg_save_pandore_case(0,0,0,"short",31);
 32393       _cimg_save_pandore_case(0,0,0,"unsigned short",31);
 32394       _cimg_save_pandore_case(0,0,0,"unsigned int",31);
 32395       _cimg_save_pandore_case(0,0,0,"int",31);
 32396       _cimg_save_pandore_case(0,0,0,"unsigned long",33);
 32397       _cimg_save_pandore_case(0,0,0,"long",31);
 32398       _cimg_save_pandore_case(0,0,0,"float",33);
 32399       _cimg_save_pandore_case(0,0,0,"double",33);
 32401       if (!file) cimg::fclose(nfile);
 32402       return *this;
 32405     //! Save the image as a PANDORE-5 file.
 32406     const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
 32407       return _save_pandore(0,filename,colorspace);
 32410     //! Save the image as a PANDORE-5 file.
 32411     const CImg<T>& save_pandore(cimg_std::FILE *const file, const unsigned int colorspace=0) const {
 32412       return _save_pandore(file,0,colorspace);
 32415    // Save the image as a RAW file (internal).
 32416     const CImg<T>& _save_raw(cimg_std::FILE *const file, const char *const filename, const bool multiplexed) const {
 32417       if (is_empty())
 32418         throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32419                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 32420       if (!file && !filename)
 32421         throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 32422                                     pixel_type(),width,height,depth,dim,data);
 32423       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 32424       if (!multiplexed) cimg::fwrite(data,size(),nfile);
 32425       else {
 32426         CImg<T> buf(dim);
 32427         cimg_forXYZ(*this,x,y,z) {
 32428           cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
 32429           cimg::fwrite(buf.data,dim,nfile);
 32432       if (!file) cimg::fclose(nfile);
 32433       return *this;
 32436     //! Save the image as a RAW file.
 32437     const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
 32438       return _save_raw(0,filename,multiplexed);
 32441     //! Save the image as a RAW file.
 32442     const CImg<T>& save_raw(cimg_std::FILE *const file, const bool multiplexed=false) const {
 32443       return _save_raw(file,0,multiplexed);
 32446     //! Save the image as a video sequence file, using FFMPEG library.
 32447     const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 32448                                const unsigned int fps=25) const {
 32449       if (is_empty())
 32450         throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32451                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32452       if (!filename)
 32453         throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32454                                     pixel_type(),width,height,depth,dim,data);
 32455       if (!fps)
 32456         throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
 32457                                     pixel_type(),filename);
 32458 #ifndef cimg_use_ffmpeg
 32459       return save_ffmpeg_external(filename,first_frame,last_frame);
 32460 #else
 32461       get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
 32462 #endif
 32463       return *this;
 32466     //! Save the image as a YUV video sequence file.
 32467     const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
 32468       get_split('z').save_yuv(filename,rgb2yuv);
 32469       return *this;
 32472     //! Save the image as a YUV video sequence file.
 32473     const CImg<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
 32474       get_split('z').save_yuv(file,rgb2yuv);
 32475       return *this;
 32478    // Save OFF files (internal).
 32479     template<typename tf, typename tc>
 32480     const CImg<T>& _save_off(cimg_std::FILE *const file, const char *const filename,
 32481                              const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
 32482       if (is_empty())
 32483         throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32484                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 32485       if (!file && !filename)
 32486         throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
 32487                                     pixel_type());
 32488       if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
 32489       CImgList<tc> _colors;
 32490       if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
 32491       const CImgList<tc>& ncolors = colors?colors:_colors;
 32493       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 32494       cimg_std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
 32495       cimg_forX(*this,i) cimg_std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
 32496       cimglist_for(primitives,l) {
 32497         const unsigned int prim = primitives[l].size();
 32498         const bool textured = (prim>4);
 32499         const CImg<tc>& color = ncolors[l];
 32500         const unsigned int s = textured?color.dimv():color.size();
 32501         const float
 32502           r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
 32503           g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r)   :(s>1?(float)(color(1)/255.0f):r),
 32504           b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r)   :(s>2?(float)(color(2)/255.0f):r);
 32506         switch (prim) {
 32507         case 1 :
 32508           cimg_std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
 32509           break;
 32510         case 2 : case 6 :
 32511           cimg_std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
 32512           break;
 32513         case 3 : case 9 :
 32514           if (invert_faces)
 32515             cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),r,g,b);
 32516           else
 32517             cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
 32518           break;
 32519         case 4 : case 12 :
 32520           if (invert_faces)
 32521             cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
 32522                          (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b);
 32523           else
 32524             cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
 32525                          (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
 32526           break;
 32529       if (!file) cimg::fclose(nfile);
 32530       return *this;
 32533     //! Save OFF files.
 32534     template<typename tf, typename tc>
 32535     const CImg<T>& save_off(const char *const filename,
 32536                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 32537       return _save_off(0,filename,primitives,colors,invert_faces);
 32540     //! Save OFF files.
 32541     template<typename tf, typename tc>
 32542     const CImg<T>& save_off(cimg_std::FILE *const file,
 32543                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 32544       return _save_off(file,0,primitives,colors,invert_faces);
 32547     //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
 32548     const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 32549                                         const char *const codec="mpeg2video") const {
 32550       if (is_empty())
 32551         throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32552                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32553       if (!filename)
 32554         throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32555                                     pixel_type(),width,height,depth,dim,data);
 32556       get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
 32557       return *this;
 32560     //! Save the image using GraphicsMagick's gm.
 32561     /** Function that saves the image for other file formats that are not natively handled by CImg,
 32562         using the tool 'gm' from the GraphicsMagick package.\n
 32563         This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 32564         the GraphicsMagick package in order to get
 32565         this function working properly (see http://www.graphicsmagick.org ).
 32566     **/
 32567     const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
 32568       if (is_empty())
 32569         throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32570                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32571       if (!filename)
 32572         throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32573                                     pixel_type(),width,height,depth,dim,data);
 32574       char command[1024],filetmp[512];
 32575       cimg_std::FILE *file;
 32576       do {
 32577         if (dim==1) cimg_std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 32578         else cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 32579         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 32580       } while (file);
 32581       save_pnm(filetmp);
 32582       cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
 32583       cimg::system(command);
 32584       file = cimg_std::fopen(filename,"rb");
 32585       if (!file)
 32586         throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
 32587                               "Path of 'gm' : \"%s\"\n"
 32588                               "Path of temporary filename : \"%s\"\n",
 32589                               pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 32590       if (file) cimg::fclose(file);
 32591       cimg_std::remove(filetmp);
 32592       return *this;
 32595     //! Save an image as a gzipped file, using external tool 'gzip'.
 32596     const CImg<T>& save_gzip_external(const char *const filename) const {
 32597       if (!filename)
 32598         throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 32599                               pixel_type());
 32600       char command[1024], filetmp[512], body[512];
 32601       const char
 32602         *ext = cimg::split_filename(filename,body),
 32603         *ext2 = cimg::split_filename(body,0);
 32604       cimg_std::FILE *file;
 32605       do {
 32606         if (!cimg::strcasecmp(ext,"gz")) {
 32607           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 32608                                   cimg::filenamerand(),ext2);
 32609           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 32610                             cimg::filenamerand());
 32611         } else {
 32612           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 32613                                  cimg::filenamerand(),ext);
 32614           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 32615                                  cimg::filenamerand());
 32617         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 32618       } while (file);
 32619       save(filetmp);
 32620       cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 32621       cimg::system(command);
 32622       file = cimg_std::fopen(filename,"rb");
 32623       if (!file)
 32624         throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
 32625                               pixel_type(),filename);
 32626       else cimg::fclose(file);
 32627       cimg_std::remove(filetmp);
 32628       return *this;
 32631     //! Save the image using ImageMagick's convert.
 32632     /** Function that saves the image for other file formats that are not natively handled by CImg,
 32633         using the tool 'convert' from the ImageMagick package.\n
 32634         This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 32635         the ImageMagick package in order to get
 32636         this function working properly (see http://www.imagemagick.org ).
 32637     **/
 32638     const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
 32639       if (is_empty())
 32640         throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32641                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32642       if (!filename)
 32643         throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32644                                     pixel_type(),width,height,depth,dim,data);
 32645       char command[1024], filetmp[512];
 32646       cimg_std::FILE *file;
 32647       do {
 32648         cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
 32649         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 32650       } while (file);
 32651       save_pnm(filetmp);
 32652       cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
 32653       cimg::system(command);
 32654       file = cimg_std::fopen(filename,"rb");
 32655       if (!file)
 32656         throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
 32657                               "Path of 'convert' : \"%s\"\n"
 32658                               "Path of temporary filename : \"%s\"\n",
 32659                               pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 32660       if (file) cimg::fclose(file);
 32661       cimg_std::remove(filetmp);
 32662       return *this;
 32665     //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
 32666     const CImg<T>& save_medcon_external(const char *const filename) const {
 32667       if (is_empty())
 32668         throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32669                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32670       if (!filename)
 32671         throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32672                                     pixel_type(),width,height,depth,dim,data);
 32674       char command[1024], filetmp[512], body[512];
 32675       cimg_std::FILE *file;
 32676       do {
 32677         cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
 32678         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 32679       } while (file);
 32680       save_analyze(filetmp);
 32681       cimg_std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
 32682       cimg::system(command);
 32683       cimg_std::remove(filetmp);
 32684       cimg::split_filename(filetmp,body);
 32685       cimg_std::sprintf(filetmp,"%s.img",body);
 32686       cimg_std::remove(filetmp);
 32687       cimg_std::sprintf(command,"m000-%s",filename);
 32688       file = cimg_std::fopen(command,"rb");
 32689       if (!file) {
 32690         cimg::fclose(cimg::fopen(filename,"r"));
 32691         throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
 32692                               "Path of 'medcon' : \"%s\"\n"
 32693                               "Path of temporary filename : \"%s\"",
 32694                               pixel_type(),filename,cimg::medcon_path(),filetmp);
 32695       } else cimg::fclose(file);
 32696       cimg_std::rename(command,filename);
 32697       return *this;
 32700     // Try to save the image if other extension is provided.
 32701     const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
 32702       if (is_empty())
 32703         throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 32704                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 32705       if (!filename)
 32706         throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 32707                               pixel_type());
 32708       const unsigned int odebug = cimg::exception_mode();
 32709       bool is_saved = true;
 32710       cimg::exception_mode() = 0;
 32711       try { save_magick(filename); }
 32712       catch (CImgException&) {
 32713         try { save_imagemagick_external(filename,quality); }
 32714         catch (CImgException&) {
 32715           try { save_graphicsmagick_external(filename,quality); }
 32716           catch (CImgException&) {
 32717             is_saved = false;
 32721       cimg::exception_mode() = odebug;
 32722       if (!is_saved)
 32723         throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
 32724                               "Check you have either the ImageMagick or GraphicsMagick package installed.",
 32725                               pixel_type(),filename);
 32726       return *this;
 32729     // Get a 40x38 color logo of a 'danger' item (internal).
 32730     static CImg<T> logo40x38() {
 32731       static bool first_time = true;
 32732       static CImg<T> res(40,38,1,3);
 32733       if (first_time) {
 32734         const unsigned char *ptrs = cimg::logo40x38;
 32735         T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
 32736         for (unsigned int off = 0; off<res.width*res.height;) {
 32737           const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
 32738           for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
 32740         first_time = false;
 32742       return res;
 32745   };
 32747   /*
 32748    #-----------------------------------------
 32752    # Definition of the CImgList<> structure
 32756    #------------------------------------------
 32757    */
 32759   //! Class representing list of images CImg<T>.
 32760   template<typename T>
 32761   struct CImgList {
 32763     //! Size of the list (number of elements inside).
 32764     unsigned int size;
 32766     //! Allocation size of the list.
 32767     unsigned int allocsize;
 32769     //! Pointer to the first list element.
 32770     CImg<T> *data;
 32772     //! Define a CImgList<T>::iterator.
 32773     typedef CImg<T>* iterator;
 32775     //! Define a CImgList<T>::const_iterator.
 32776     typedef const CImg<T>* const_iterator;
 32778     //! Get value type.
 32779     typedef T value_type;
 32781     // Define common T-dependant types.
 32782     typedef typename cimg::superset<T,bool>::type Tbool;
 32783     typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 32784     typedef typename cimg::superset<T,char>::type Tchar;
 32785     typedef typename cimg::superset<T,unsigned short>::type Tushort;
 32786     typedef typename cimg::superset<T,short>::type Tshort;
 32787     typedef typename cimg::superset<T,unsigned int>::type Tuint;
 32788     typedef typename cimg::superset<T,int>::type Tint;
 32789     typedef typename cimg::superset<T,unsigned long>::type Tulong;
 32790     typedef typename cimg::superset<T,long>::type Tlong;
 32791     typedef typename cimg::superset<T,float>::type Tfloat;
 32792     typedef typename cimg::superset<T,double>::type Tdouble;
 32793     typedef typename cimg::last<T,bool>::type boolT;
 32794     typedef typename cimg::last<T,unsigned char>::type ucharT;
 32795     typedef typename cimg::last<T,char>::type charT;
 32796     typedef typename cimg::last<T,unsigned short>::type ushortT;
 32797     typedef typename cimg::last<T,short>::type shortT;
 32798     typedef typename cimg::last<T,unsigned int>::type uintT;
 32799     typedef typename cimg::last<T,int>::type intT;
 32800     typedef typename cimg::last<T,unsigned long>::type ulongT;
 32801     typedef typename cimg::last<T,long>::type longT;
 32802     typedef typename cimg::last<T,float>::type floatT;
 32803     typedef typename cimg::last<T,double>::type doubleT;
 32805     //@}
 32806     //---------------------------
 32807     //
 32808     //! \name Plugins
 32809     //@{
 32810     //---------------------------
 32811 #ifdef cimglist_plugin
 32812 #include cimglist_plugin
 32813 #endif
 32814 #ifdef cimglist_plugin1
 32815 #include cimglist_plugin1
 32816 #endif
 32817 #ifdef cimglist_plugin2
 32818 #include cimglist_plugin2
 32819 #endif
 32820 #ifdef cimglist_plugin3
 32821 #include cimglist_plugin3
 32822 #endif
 32823 #ifdef cimglist_plugin4
 32824 #include cimglist_plugin4
 32825 #endif
 32826 #ifdef cimglist_plugin5
 32827 #include cimglist_plugin5
 32828 #endif
 32829 #ifdef cimglist_plugin6
 32830 #include cimglist_plugin6
 32831 #endif
 32832 #ifdef cimglist_plugin7
 32833 #include cimglist_plugin7
 32834 #endif
 32835 #ifdef cimglist_plugin8
 32836 #include cimglist_plugin8
 32837 #endif
 32838     //@}
 32840     //------------------------------------------
 32841     //
 32842     //! \name Constructors - Destructor - Copy
 32843     //@{
 32844     //------------------------------------------
 32846     //! Destructor.
 32847     ~CImgList() {
 32848       if (data) delete[] data;
 32851     //! Default constructor.
 32852     CImgList():
 32853       size(0),allocsize(0),data(0) {}
 32855     //! Construct an image list containing n empty images.
 32856     explicit CImgList(const unsigned int n):
 32857       size(n) {
 32858       data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
 32861     //! Default copy constructor.
 32862     template<typename t>
 32863     CImgList(const CImgList<t>& list):
 32864       size(0),allocsize(0),data(0) {
 32865       assign(list.size);
 32866       cimglist_for(*this,l) data[l].assign(list[l],false);
 32869     CImgList(const CImgList<T>& list):
 32870       size(0),allocsize(0),data(0) {
 32871       assign(list.size);
 32872       cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
 32875     //! Advanced copy constructor.
 32876     template<typename t>
 32877     CImgList(const CImgList<t>& list, const bool shared):
 32878       size(0),allocsize(0),data(0) {
 32879       assign(list.size);
 32880       if (shared)
 32881         throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
 32882                                     "a CImgList<%s> (different pixel types).",
 32883                                     pixel_type(),CImgList<t>::pixel_type());
 32884       cimglist_for(*this,l) data[l].assign(list[l],false);
 32887     CImgList(const CImgList<T>& list, const bool shared):
 32888       size(0),allocsize(0),data(0) {
 32889       assign(list.size);
 32890       cimglist_for(*this,l) data[l].assign(list[l],shared);
 32893     //! Construct an image list containing n images with specified size.
 32894     CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
 32895              const unsigned int depth=1, const unsigned int dim=1):
 32896       size(0),allocsize(0),data(0) {
 32897       assign(n);
 32898       cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 32901     //! Construct an image list containing n images with specified size, filled with specified value.
 32902     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 32903              const unsigned int depth, const unsigned int dim, const T val):
 32904       size(0),allocsize(0),data(0) {
 32905       assign(n);
 32906       cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
 32909     //! Construct an image list containing n images with specified size and specified pixel values (int version).
 32910     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 32911              const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
 32912       size(0),allocsize(0),data(0) {
 32913 #define _CImgList_stdarg(t) { \
 32914         assign(n,width,height,depth,dim); \
 32915         const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
 32916         T *ptrd = data->data; \
 32917         va_list ap; \
 32918         va_start(ap,val1); \
 32919         for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
 32920           *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
 32921           if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
 32922         } \
 32923         va_end(ap); \
 32925       _CImgList_stdarg(int);
 32928     //! Construct an image list containing n images with specified size and specified pixel values (double version).
 32929     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 32930              const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
 32931       size(0),allocsize(0),data(0) {
 32932       _CImgList_stdarg(double);
 32935     //! Construct a list containing n copies of the image img.
 32936     template<typename t>
 32937     CImgList(const unsigned int n, const CImg<t>& img):
 32938       size(0),allocsize(0),data(0) {
 32939       assign(n);
 32940       cimglist_for(*this,l) data[l].assign(img,img.is_shared);
 32943     //! Construct a list containing n copies of the image img, forcing the shared state.
 32944     template<typename t>
 32945     CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
 32946       size(0),allocsize(0),data(0) {
 32947       assign(n);
 32948       cimglist_for(*this,l) data[l].assign(img,shared);
 32951     //! Construct an image list from one image.
 32952     template<typename t>
 32953     explicit CImgList(const CImg<t>& img):
 32954       size(0),allocsize(0),data(0) {
 32955       assign(1);
 32956       data[0].assign(img,img.is_shared);
 32959     //! Construct an image list from one image, forcing the shared state.
 32960     template<typename t>
 32961     explicit CImgList(const CImg<t>& img, const bool shared):
 32962       size(0),allocsize(0),data(0) {
 32963       assign(1);
 32964       data[0].assign(img,shared);
 32967     //! Construct an image list from two images.
 32968     template<typename t1, typename t2>
 32969     CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
 32970       size(0),allocsize(0),data(0) {
 32971       assign(2);
 32972       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
 32975     //! Construct an image list from two images, forcing the shared state.
 32976     template<typename t1, typename t2>
 32977     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
 32978       size(0),allocsize(0),data(0) {
 32979       assign(2);
 32980       data[0].assign(img1,shared); data[1].assign(img2,shared);
 32983     //! Construct an image list from three images.
 32984     template<typename t1, typename t2, typename t3>
 32985     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
 32986       size(0),allocsize(0),data(0) {
 32987       assign(3);
 32988       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
 32991     //! Construct an image list from three images, forcing the shared state.
 32992     template<typename t1, typename t2, typename t3>
 32993     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
 32994       size(0),allocsize(0),data(0) {
 32995       assign(3);
 32996       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
 32999     //! Construct an image list from four images.
 33000     template<typename t1, typename t2, typename t3, typename t4>
 33001     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
 33002       size(0),allocsize(0),data(0) {
 33003       assign(4);
 33004       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
 33007     //! Construct an image list from four images, forcing the shared state.
 33008     template<typename t1, typename t2, typename t3, typename t4>
 33009     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
 33010       size(0),allocsize(0),data(0) {
 33011       assign(4);
 33012       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33015     //! Construct an image list from five images.
 33016     template<typename t1, typename t2, typename t3, typename t4, typename t5>
 33017     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33018              const CImg<t5>& img5):
 33019       size(0),allocsize(0),data(0) {
 33020       assign(5);
 33021       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
 33022       data[4].assign(img5,img5.is_shared);
 33025     //! Construct an image list from five images, forcing the shared state.
 33026     template<typename t1, typename t2, typename t3, typename t4, typename t5>
 33027     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33028              const CImg<t5>& img5, const bool shared):
 33029       size(0),allocsize(0),data(0) {
 33030       assign(5);
 33031       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33032       data[4].assign(img5,shared);
 33035     //! Construct an image list from six images.
 33036     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 33037     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33038              const CImg<t5>& img5, const CImg<t6>& img6):
 33039       size(0),allocsize(0),data(0) {
 33040       assign(6);
 33041       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
 33042       data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
 33045     //! Construct an image list from six images, forcing the shared state.
 33046     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 33047     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33048              const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
 33049       size(0),allocsize(0),data(0) {
 33050       assign(6);
 33051       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33052       data[4].assign(img5,shared); data[5].assign(img6,shared);
 33055     //! Construct an image list from seven images.
 33056     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 33057     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33058              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
 33059       size(0),allocsize(0),data(0) {
 33060       assign(7);
 33061       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
 33062       data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
 33065     //! Construct an image list from seven images, forcing the shared state.
 33066     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 33067     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33068              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
 33069       size(0),allocsize(0),data(0) {
 33070       assign(7);
 33071       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33072       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
 33075     //! Construct an image list from eight images.
 33076     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 33077     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33078              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
 33079       size(0),allocsize(0),data(0) {
 33080       assign(8);
 33081       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
 33082       data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared); data[7].assign(img8,img8.is_shared);
 33085     //! Construct an image list from eight images, forcing the shared state.
 33086     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 33087     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33088              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
 33089       size(0),allocsize(0),data(0) {
 33090       assign(8);
 33091       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33092       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
 33095     //! Construct an image list from a filename.
 33096     CImgList(const char *const filename):
 33097       size(0),allocsize(0),data(0) {
 33098       assign(filename);
 33101     //! In-place version of the default constructor and default destructor.
 33102     CImgList<T>& assign() {
 33103       if (data) delete[] data;
 33104       size = allocsize = 0;
 33105       data = 0;
 33106       return *this;
 33109     //! Equivalent to assign() (STL-compliant name).
 33110     CImgList<T>& clear() {
 33111       return assign();
 33114     //! In-place version of the corresponding constructor.
 33115     CImgList<T>& assign(const unsigned int n) {
 33116       if (n) {
 33117         if (allocsize<n || allocsize>(n<<2)) {
 33118           if (data) delete[] data;
 33119           data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
 33121         size = n;
 33122       } else assign();
 33123       return *this;
 33126     //! In-place version of the corresponding constructor.
 33127     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
 33128                         const unsigned int depth=1, const unsigned int dim=1) {
 33129       assign(n);
 33130       cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 33131       return *this;
 33134     //! In-place version of the corresponding constructor.
 33135     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 33136                         const unsigned int depth, const unsigned int dim, const T val) {
 33137       assign(n);
 33138       cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
 33139       return *this;
 33142     //! In-place version of the corresponding constructor.
 33143     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 33144                         const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
 33145       _CImgList_stdarg(int);
 33146       return *this;
 33149     //! In-place version of the corresponding constructor.
 33150     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 33151                         const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
 33152       _CImgList_stdarg(double);
 33153       return *this;
 33156     //! In-place version of the copy constructor.
 33157     template<typename t>
 33158     CImgList<T>& assign(const CImgList<t>& list) {
 33159       assign(list.size);
 33160       cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
 33161       return *this;
 33164     //! In-place version of the copy constructor.
 33165     template<typename t>
 33166     CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
 33167       assign(list.size);
 33168       cimglist_for(*this,l) data[l].assign(list[l],shared);
 33169       return *this;
 33172     //! In-place version of the corresponding constructor.
 33173     template<typename t>
 33174     CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
 33175       assign(n);
 33176       cimglist_for(*this,l) data[l].assign(img,shared);
 33177       return *this;
 33180     //! In-place version of the corresponding constructor.
 33181     template<typename t>
 33182     CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
 33183       assign(1);
 33184       data[0].assign(img,shared);
 33185       return *this;
 33188     //! In-place version of the corresponding constructor.
 33189     template<typename t1, typename t2>
 33190     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
 33191       assign(2);
 33192       data[0].assign(img1,shared); data[1].assign(img2,shared);
 33193       return *this;
 33196     //! In-place version of the corresponding constructor.
 33197     template<typename t1, typename t2, typename t3>
 33198     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
 33199       assign(3);
 33200       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
 33201       return *this;
 33204     //! In-place version of the corresponding constructor.
 33205     template<typename t1, typename t2, typename t3, typename t4>
 33206     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33207                         const bool shared=false) {
 33208       assign(4);
 33209       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33210       return *this;
 33213     //! In-place version of the corresponding constructor.
 33214     template<typename t1, typename t2, typename t3, typename t4, typename t5>
 33215     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33216                         const CImg<t5>& img5, const bool shared=false) {
 33217       assign(5);
 33218       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33219       data[4].assign(img5,shared);
 33220       return *this;
 33223     //! In-place version of the corresponding constructor.
 33224     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 33225     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33226                         const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
 33227       assign(6);
 33228       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33229       data[4].assign(img5,shared); data[5].assign(img6,shared);
 33230       return *this;
 33233     //! In-place version of the corresponding constructor.
 33234     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 33235     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33236                         const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
 33237       assign(7);
 33238       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33239       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
 33240       return *this;
 33243     //! In-place version of the corresponding constructor.
 33244     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 33245     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 33246                         const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
 33247       assign(8);
 33248       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 33249       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
 33250       return *this;
 33253     //! In-place version of the corresponding constructor.
 33254     CImgList<T>& assign(const char *const filename) {
 33255       return load(filename);
 33258     //! Transfer the content of the instance image list into another one.
 33259     template<typename t>
 33260     CImgList<T>& transfer_to(CImgList<t>& list) {
 33261       list.assign(*this);
 33262       assign();
 33263       return list;
 33266     CImgList<T>& transfer_to(CImgList<T>& list) {
 33267       list.assign();
 33268       return swap(list);
 33271     //! Swap all fields of two CImgList instances (use with care !)
 33272     CImgList<T>& swap(CImgList<T>& list) {
 33273       cimg::swap(size,list.size);
 33274       cimg::swap(allocsize,list.allocsize);
 33275       cimg::swap(data,list.data);
 33276       return list;
 33279     //! Return a string describing the type of the image pixels in the list (template parameter \p T).
 33280     static const char* pixel_type() {
 33281       return cimg::type<T>::string();
 33284     //! Return \p true if list is empty.
 33285     bool is_empty() const {
 33286       return (!data || !size);
 33289     //! Return \p true if list is not empty.
 33290     operator bool() const {
 33291       return !is_empty();
 33294     //! Return \p true if list if of specified size.
 33295     bool is_sameN(const unsigned int n) const {
 33296       return (size==n);
 33299     //! Return \p true if list if of specified size.
 33300     template<typename t>
 33301     bool is_sameN(const CImgList<t>& list) const {
 33302       return (size==list.size);
 33305     // Define useful dimension check functions.
 33306     // (not documented because they are macro-generated).
 33307 #define _cimglist_def_is_same1(axis) \
 33308     bool is_same##axis(const unsigned int val) const { \
 33309       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(val); return res; \
 33310     } \
 33311     bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
 33312       return is_sameN(n) && is_same##axis(val); \
 33313     } \
 33315 #define _cimglist_def_is_same2(axis1,axis2) \
 33316     bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
 33317       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
 33318     } \
 33319     bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
 33320       return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
 33321     } \
 33323 #define _cimglist_def_is_same3(axis1,axis2,axis3) \
 33324     bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
 33325       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2##axis3(val1,val2,val3); return res; \
 33326     } \
 33327     bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
 33328       return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
 33329     } \
 33331 #define _cimglist_def_is_same(axis) \
 33332     template<typename t> bool is_same##axis(const CImg<t>& img) const { \
 33333       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(img); return res; \
 33334     } \
 33335     template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
 33336       const unsigned int lmin = cimg::min(size,list.size); \
 33337       bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
 33338     } \
 33339     template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
 33340       return (is_sameN(n) && is_same##axis(img)); \
 33341     } \
 33342     template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
 33343       return (is_sameN(list) && is_same##axis(list)); \
 33346     _cimglist_def_is_same(XY)
 33347     _cimglist_def_is_same(XZ)
 33348     _cimglist_def_is_same(XV)
 33349     _cimglist_def_is_same(YZ)
 33350     _cimglist_def_is_same(YV)
 33351     _cimglist_def_is_same(XYZ)
 33352     _cimglist_def_is_same(XYV)
 33353     _cimglist_def_is_same(YZV)
 33354     _cimglist_def_is_same(XYZV)
 33355     _cimglist_def_is_same1(X)
 33356     _cimglist_def_is_same1(Y)
 33357     _cimglist_def_is_same1(Z)
 33358     _cimglist_def_is_same1(V)
 33359     _cimglist_def_is_same2(X,Y)
 33360     _cimglist_def_is_same2(X,Z)
 33361     _cimglist_def_is_same2(X,V)
 33362     _cimglist_def_is_same2(Y,Z)
 33363     _cimglist_def_is_same2(Y,V)
 33364     _cimglist_def_is_same2(Z,V)
 33365     _cimglist_def_is_same3(X,Y,Z)
 33366     _cimglist_def_is_same3(X,Y,V)
 33367     _cimglist_def_is_same3(X,Z,V)
 33368     _cimglist_def_is_same3(Y,Z,V)
 33370     bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 33371       bool res = true;
 33372       for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
 33373       return res;
 33376     bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 33377       return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
 33380     //! Return \c true if the list contains the pixel (n,x,y,z,v).
 33381     bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
 33382       if (is_empty()) return false;
 33383       return n>=0 && n<(int)size && x>=0 && x<data[n].dimx() && y>=0 && y<data[n].dimy() && z>=0 && z<data[n].dimz() && v>=0 && v<data[n].dimv();
 33386     //! Return \c true if the list contains the image (n).
 33387     bool containsN(const int n) const {
 33388       if (is_empty()) return false;
 33389       return n>=0 && n<(int)size;
 33392     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
 33393     template<typename t>
 33394     bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
 33395       if (is_empty()) return false;
 33396       cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
 33397       return false;
 33400     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
 33401     template<typename t>
 33402     bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
 33403       t v;
 33404       return contains(pixel,n,x,y,z,v);
 33407     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
 33408     template<typename t>
 33409     bool contains(const T& pixel, t& n, t& x, t&y) const {
 33410       t z,v;
 33411       return contains(pixel,n,x,y,z,v);
 33414     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
 33415     template<typename t>
 33416     bool contains(const T& pixel, t& n, t& x) const {
 33417       t y,z,v;
 33418       return contains(pixel,n,x,y,z,v);
 33421     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n).
 33422     template<typename t>
 33423     bool contains(const T& pixel, t& n) const {
 33424       t x,y,z,v;
 33425       return contains(pixel,n,x,y,z,v);
 33428     //! Return \c true if one of the image list contains the specified referenced value.
 33429     bool contains(const T& pixel) const {
 33430       unsigned int n,x,y,z,v;
 33431       return contains(pixel,n,x,y,z,v);
 33434     //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
 33435     template<typename t>
 33436     bool contains(const CImg<T>& img, t& n) const {
 33437       if (is_empty()) return false;
 33438       const CImg<T> *const ptr = &img;
 33439       cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
 33440       return false;
 33443     //! Return \c true if the list contains the image img.
 33444     bool contains(const CImg<T>& img) const {
 33445       unsigned int n;
 33446       return contains(img,n);
 33449     //@}
 33450     //------------------------------
 33451     //
 33452     //! \name Arithmetics Operators
 33453     //@{
 33454     //------------------------------
 33456     //! Assignment operator
 33457     template<typename t>
 33458     CImgList<T>& operator=(const CImgList<t>& list) {
 33459       return assign(list);
 33462     CImgList<T>& operator=(const CImgList<T>& list) {
 33463       return assign(list);
 33466     //! Assignment operator.
 33467     template<typename t>
 33468     CImgList<T>& operator=(const CImg<t>& img) {
 33469       cimglist_for(*this,l) data[l] = img;
 33470       return *this;
 33473     //! Assignment operator.
 33474     CImgList<T>& operator=(const T val) {
 33475       cimglist_for(*this,l) data[l].fill(val);
 33476       return *this;
 33479     //! Operator+.
 33480     CImgList<T> operator+() const {
 33481       return CImgList<T>(*this);
 33484     //! Operator+=.
 33485 #ifdef cimg_use_visualcpp6
 33486     CImgList<T>& operator+=(const T val)
 33487 #else
 33488     template<typename t>
 33489     CImgList<T>& operator+=(const t val)
 33490 #endif
 33492       cimglist_for(*this,l) (*this)[l]+=val;
 33493       return *this;
 33496     //! Operator+=.
 33497     template<typename t>
 33498     CImgList<T>& operator+=(const CImgList<t>& list) {
 33499       const unsigned int sizemax = cimg::min(size,list.size);
 33500       for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
 33501       return *this;
 33504     //! Operator++ (prefix).
 33505     CImgList<T>& operator++() {
 33506       cimglist_for(*this,l) ++(*this)[l];
 33507       return *this;
 33510     //! Operator++ (postfix).
 33511     CImgList<T> operator++(int) {
 33512       CImgList<T> copy(*this);
 33513       ++*this;
 33514       return copy;
 33517     //! Operator-.
 33518     CImgList<T> operator-() const {
 33519       CImgList<T> res(size);
 33520       cimglist_for(res,l) res[l].assign(-data[l]);
 33521       return res;
 33524     //! Operator-=.
 33525 #ifdef cimg_use_visualcpp6
 33526     CImgList<T>& operator-=(const T val)
 33527 #else
 33528       template<typename t>
 33529     CImgList<T>& operator-=(const t val)
 33530 #endif
 33532       cimglist_for(*this,l) (*this)[l]-=val;
 33533       return *this;
 33536     //! Operator-=.
 33537     template<typename t>
 33538     CImgList<T>& operator-=(const CImgList<t>& list) {
 33539       const unsigned int sizemax = min(size,list.size);
 33540       for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
 33541       return *this;
 33544     //! Operator-- (prefix).
 33545     CImgList<T>& operator--() {
 33546       cimglist_for(*this,l) --(*this)[l];
 33547       return *this;
 33550     //! Operator-- (postfix).
 33551     CImgList<T> operator--(int) {
 33552       CImgList<T> copy(*this);
 33553       --*this;
 33554       return copy;
 33557     //! Operator*=.
 33558 #ifdef cimg_use_visualcpp6
 33559     CImgList<T>& operator*=(const double val)
 33560 #else
 33561     template<typename t>
 33562     CImgList<T>& operator*=(const t val)
 33563 #endif
 33565       cimglist_for(*this,l) (*this)[l]*=val;
 33566       return *this;
 33569     //! Operator*=.
 33570     template<typename t>
 33571     CImgList<T>& operator*=(const CImgList<t>& list) {
 33572       const unsigned int N = cimg::min(size,list.size);
 33573       for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
 33574       return this;
 33577     //! Operator/=.
 33578 #ifdef cimg_use_visualcpp6
 33579     CImgList<T>& operator/=(const double val)
 33580 #else
 33581     template<typename t>
 33582     CImgList<T>& operator/=(const t val)
 33583 #endif
 33585       cimglist_for(*this,l) (*this)[l]/=val;
 33586       return *this;
 33589     //! Operator/=.
 33590     template<typename t>
 33591     CImgList<T>& operator/=(const CImgList<t>& list) {
 33592       const unsigned int N = cimg::min(size,list.size);
 33593       for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
 33594       return this;
 33597     //! Return a reference to the maximum pixel value of the instance list.
 33598     const T& max() const {
 33599       if (is_empty())
 33600         throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
 33601                                     pixel_type());
 33602       const T *ptrmax = data->data;
 33603       T max_value = *ptrmax;
 33604       cimglist_for(*this,l) {
 33605         const CImg<T>& img = data[l];
 33606         cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 33608       return *ptrmax;
 33611     //! Return a reference to the maximum pixel value of the instance list.
 33612     T& max() {
 33613       if (is_empty())
 33614         throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
 33615                                     pixel_type());
 33616       T *ptrmax = data->data;
 33617       T max_value = *ptrmax;
 33618       cimglist_for(*this,l) {
 33619         const CImg<T>& img = data[l];
 33620         cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 33622       return *ptrmax;
 33625     //! Return a reference to the minimum pixel value of the instance list.
 33626     const T& min() const {
 33627       if (is_empty())
 33628         throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
 33629                                     pixel_type());
 33630       const T *ptrmin = data->data;
 33631       T min_value = *ptrmin;
 33632       cimglist_for(*this,l) {
 33633         const CImg<T>& img = data[l];
 33634         cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 33636       return *ptrmin;
 33639     //! Return a reference to the minimum pixel value of the instance list.
 33640     T& min() {
 33641       if (is_empty())
 33642         throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
 33643                                     pixel_type());
 33644       T *ptrmin = data->data;
 33645       T min_value = *ptrmin;
 33646       cimglist_for(*this,l) {
 33647         const CImg<T>& img = data[l];
 33648         cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 33650       return *ptrmin;
 33653     //! Return a reference to the minimum pixel value of the instance list.
 33654     template<typename t>
 33655     const T& minmax(t& max_val) const {
 33656       if (is_empty())
 33657         throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
 33658                                     pixel_type());
 33659       const T *ptrmin = data->data;
 33660       T min_value = *ptrmin, max_value = min_value;
 33661       cimglist_for(*this,l) {
 33662         const CImg<T>& img = data[l];
 33663         cimg_for(img,ptr,T) {
 33664           const T val = *ptr;
 33665           if (val<min_value) { min_value = val; ptrmin = ptr; }
 33666           if (val>max_value) max_value = val;
 33669       max_val = (t)max_value;
 33670       return *ptrmin;
 33673     //! Return a reference to the minimum pixel value of the instance list.
 33674     template<typename t>
 33675     T& minmax(t& max_val) {
 33676       if (is_empty())
 33677         throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
 33678                                     pixel_type());
 33679       T *ptrmin = data->data;
 33680       T min_value = *ptrmin, max_value = min_value;
 33681       cimglist_for(*this,l) {
 33682         const CImg<T>& img = data[l];
 33683         cimg_for(img,ptr,T) {
 33684           const T val = *ptr;
 33685           if (val<min_value) { min_value = val; ptrmin = ptr; }
 33686           if (val>max_value) max_value = val;
 33689       max_val = (t)max_value;
 33690       return *ptrmin;
 33693     //! Return a reference to the minimum pixel value of the instance list.
 33694     template<typename t>
 33695     const T& maxmin(t& min_val) const {
 33696       if (is_empty())
 33697         throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
 33698                                     pixel_type());
 33699       const T *ptrmax = data->data;
 33700       T min_value = *ptrmax, max_value = min_value;
 33701       cimglist_for(*this,l) {
 33702         const CImg<T>& img = data[l];
 33703         cimg_for(img,ptr,T) {
 33704           const T val = *ptr;
 33705           if (val>max_value) { max_value = val; ptrmax = ptr; }
 33706           if (val<min_value) min_value = val;
 33709       min_val = (t)min_value;
 33710       return *ptrmax;
 33713     //! Return a reference to the minimum pixel value of the instance list.
 33714     template<typename t>
 33715     T& maxmin(t& min_val) {
 33716       if (is_empty())
 33717         throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
 33718                                     pixel_type());
 33719       T *ptrmax = data->data;
 33720       T min_value = *ptrmax, max_value = min_value;
 33721       cimglist_for(*this,l) {
 33722         const CImg<T>& img = data[l];
 33723         cimg_for(img,ptr,T) {
 33724           const T val = *ptr;
 33725           if (val>max_value) { max_value = val; ptrmax = ptr; }
 33726           if (val<min_value) min_value = val;
 33729       min_val = (t)min_value;
 33730       return *ptrmax;
 33733     //! Return the mean pixel value of the instance list.
 33734     double mean() const {
 33735       if (is_empty())
 33736         throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",
 33737                                     pixel_type());
 33738       double val = 0;
 33739       unsigned int siz = 0;
 33740       cimglist_for(*this,l) {
 33741         const CImg<T>& img = data[l];
 33742         cimg_for(img,ptr,T) val+=(double)*ptr;
 33743         siz+=img.size();
 33745       return val/siz;
 33748     //! Return the variance of the instance list.
 33749     double variance() {
 33750       if (is_empty())
 33751         throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",
 33752                                     pixel_type());
 33753       double res = 0;
 33754       unsigned int siz = 0;
 33755       double S = 0, S2 = 0;
 33756       cimglist_for(*this,l) {
 33757         const CImg<T>& img = data[l];
 33758         cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
 33759         siz+=img.size();
 33761       res = (S2 - S*S/siz)/siz;
 33762       return res;
 33765     //! Compute a list of statistics vectors (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
 33766     CImgList<T>& stats(const unsigned int variance_method=1) {
 33767       if (is_empty()) return *this;
 33768       cimglist_for(*this,l) data[l].stats(variance_method);
 33769       return *this;
 33772     CImgList<Tfloat> get_stats(const unsigned int variance_method=1) const {
 33773       CImgList<Tfloat> res(size);
 33774       cimglist_for(*this,l) res[l] = data[l].get_stats(variance_method);
 33775       return res;
 33778     //@}
 33779     //-------------------------
 33780     //
 33781     //! \name List Manipulation
 33782     //@{
 33783     //-------------------------
 33785     //! Return a reference to the i-th element of the image list.
 33786     CImg<T>& operator[](const unsigned int pos) {
 33787 #if cimg_debug>=3
 33788       if (pos>=size) {
 33789         cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
 33790                    pixel_type(),pos,size);
 33791         return *data;
 33793 #endif
 33794       return data[pos];
 33797     const CImg<T>& operator[](const unsigned int pos) const {
 33798 #if cimg_debug>=3
 33799       if (pos>=size) {
 33800         cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
 33801                    pixel_type(),pos,size);
 33802         return *data;
 33804 #endif
 33805       return data[pos];
 33808     //! Equivalent to CImgList<T>::operator[]
 33809     CImg<T>& operator()(const unsigned int pos) {
 33810       return (*this)[pos];
 33813     const CImg<T>& operator()(const unsigned int pos) const {
 33814       return (*this)[pos];
 33817     //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list
 33818     T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
 33819                   const unsigned int z=0, const unsigned int v=0) {
 33820       return (*this)[pos](x,y,z,v);
 33822     const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
 33823                         const unsigned int z=0, const unsigned int v=0) const {
 33824       return (*this)[pos](x,y,z,v);
 33827     // This function is only here for template tricks.
 33828     T _display_object3d_at2(const int i, const int j) const {
 33829       return atNXY(i,0,j,0,0,0);
 33832     //! Read an image in specified position.
 33833     CImg<T>& at(const int pos) {
 33834       if (is_empty())
 33835         throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
 33836                                     pixel_type());
 33837       return data[pos<0?0:pos>=(int)size?(int)size-1:pos];
 33840     //! Read a pixel value with Dirichlet boundary conditions.
 33841     T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 33842       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
 33845     T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 33846       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
 33849     //! Read a pixel value with Neumann boundary conditions.
 33850     T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
 33851       if (is_empty())
 33852         throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
 33853                                     pixel_type());
 33854       return _atNXYZV(pos,x,y,z,v);
 33857     T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
 33858       if (is_empty())
 33859         throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
 33860                                     pixel_type());
 33861       return _atNXYZV(pos,x,y,z,v);
 33864     T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
 33865       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
 33868     T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
 33869       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
 33872     //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
 33873     T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 33874       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
 33877     T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 33878       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
 33881     //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
 33882     T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
 33883       if (is_empty())
 33884         throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
 33885                                     pixel_type());
 33886       return _atNXYZ(pos,x,y,z,v);
 33889     T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
 33890       if (is_empty())
 33891         throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
 33892                                     pixel_type());
 33893       return _atNXYZ(pos,x,y,z,v);
 33896     T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
 33897       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
 33900     T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
 33901       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
 33904     //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y).
 33905     T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 33906       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
 33909     T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 33910       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXY(x,y,z,v,out_val);
 33913     //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y).
 33914     T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
 33915       if (is_empty())
 33916         throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
 33917                                     pixel_type());
 33918       return _atNXY(pos,x,y,z,v);
 33921     T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
 33922       if (is_empty())
 33923         throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
 33924                                     pixel_type());
 33925       return _atNXY(pos,x,y,z,v);
 33928     T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
 33929       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
 33932     T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
 33933       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
 33936     //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x).
 33937     T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 33938       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
 33941     T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 33942       return (pos<0 || pos>=(int)size)?out_val:data[pos].atX(x,y,z,v,out_val);
 33945     //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x).
 33946     T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
 33947       if (is_empty())
 33948         throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
 33949                                     pixel_type());
 33950       return _atNX(pos,x,y,z,v);
 33953     T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
 33954       if (is_empty())
 33955         throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
 33956                                     pixel_type());
 33957       return _atNX(pos,x,y,z,v);
 33960     T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
 33961       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
 33964     T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
 33965       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
 33968     //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos).
 33969     T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 33970       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
 33973     T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 33974       return (pos<0 || pos>=(int)size)?out_val:(*this)(pos,x,y,z,v);
 33977     //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos).
 33978     T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
 33979       if (is_empty())
 33980         throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
 33981                                     pixel_type());
 33982       return _atN(pos,x,y,z,v);
 33985     T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
 33986       if (is_empty())
 33987         throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
 33988                                     pixel_type());
 33989       return _atN(pos,x,y,z,v);
 33992     T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
 33993       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
 33996     T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
 33997       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
 34000     //! Returns a reference to the last element.
 34001     CImg<T>& back() {
 34002       return (*this)(size-1);
 34005     const CImg<T>& back() const {
 34006       return (*this)(size-1);
 34009     //! Returns a reference to the first element.
 34010     CImg<T>& front() {
 34011       return *data;
 34014     const CImg<T>& front() const {
 34015       return *data;
 34018     //! Returns an iterator to the beginning of the vector.
 34019     iterator begin() {
 34020       return data;
 34023     const_iterator begin() const {
 34024       return data;
 34027     //! Return a reference to the first image.
 34028     const CImg<T>& first() const {
 34029       return *data;
 34032     CImg<T>& first() {
 34033       return *data;
 34036     //! Returns an iterator just past the last element.
 34037     iterator end() {
 34038       return data + size;
 34041     const_iterator end() const {
 34042       return data + size;
 34045     //! Return a reference to the last image.
 34046     const CImg<T>& last() const {
 34047       return data[size - 1];
 34050     CImg<T>& last() {
 34051       return data[size - 1];
 34054     //! Insert a copy of the image \p img into the current image list, at position \p pos.
 34055     template<typename t>
 34056     CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
 34057       const unsigned int npos = pos==~0U?size:pos;
 34058       if (npos>size)
 34059         throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
 34060                                     pixel_type(),npos,size);
 34061       if (shared)
 34062         throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
 34063                                     pixel_type(),img.pixel_type(),pixel_type());
 34064       CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
 34065       if (!size || !data) {
 34066         data = new_data;
 34067         *data = img;
 34068       } else {
 34069         if (new_data) {
 34070           if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
 34071           if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 34072           cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
 34073           delete[] data;
 34074           data = new_data;
 34076         else if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 34077         data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
 34078         data[npos] = img;
 34080       return *this;
 34083     CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
 34084       const unsigned int npos = pos==~0U?size:pos;
 34085       if (npos>size)
 34086         throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
 34087                                     pixel_type(),npos,size);
 34088       if (&img>=data && &img<data+size) return insert(+img,pos,shared);
 34089       CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
 34090       if (!size || !data) {
 34091         data = new_data;
 34092         if (shared && img) {
 34093           data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
 34094           data->is_shared = true; data->data = img.data;
 34095         } else *data = img;
 34097       else {
 34098         if (new_data) {
 34099           if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
 34100           if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 34101           if (shared && img) {
 34102             new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
 34103             new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
 34104           } else {
 34105             new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
 34106             new_data[npos] = img;
 34108           cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
 34109           delete[] data;
 34110           data = new_data;
 34111         } else {
 34112           if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 34113           if (shared && img) {
 34114             data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
 34115             data[npos].is_shared = true; data[npos].data = img.data;
 34116           } else {
 34117             data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
 34118             data[npos] = img;
 34122       return *this;
 34125     // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
 34126     // default parameters are used in function signatures.
 34127     template<typename t>
 34128     CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
 34129       return insert(img,pos,false);
 34132     //! Insert a copy of the image \p img into the current image list, at position \p pos.
 34133     template<typename t>
 34134     CImgList<T>& insert(const CImg<t>& img) {
 34135       return insert(img,~0U,false);
 34138     template<typename t>
 34139     CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 34140       return (+*this).insert(img,pos,shared);
 34143     //! Insert n empty images img into the current image list, at position \p pos.
 34144     CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
 34145       CImg<T> foo;
 34146       if (!n) return *this;
 34147       const unsigned int npos = pos==~0U?size:pos;
 34148       for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
 34149       return *this;
 34152     CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
 34153       return (+*this).insert(n,pos);
 34156     //! Insert n copies of the image \p img into the current image list, at position \p pos.
 34157     template<typename t>
 34158     CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
 34159       if (!n) return *this;
 34160       const unsigned int npos = pos==~0U?size:pos;
 34161       insert(img,npos,shared);
 34162       for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
 34163       return *this;
 34166     template<typename t>
 34167     CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 34168       return (+*this).insert(n,img,pos,shared);
 34171     //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
 34172     template<typename t>
 34173     CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
 34174       const unsigned int npos = pos==~0U?size:pos;
 34175       if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
 34176       else insert(CImgList<T>(list),npos,shared);
 34177       return *this;
 34180     template<typename t>
 34181     CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 34182       return (+*this).insert(list,pos,shared);
 34185     //! Insert n copies of the list \p list at position \p pos of the current list.
 34186     template<typename t>
 34187     CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
 34188       if (!n) return *this;
 34189       const unsigned int npos = pos==~0U?size:pos;
 34190       for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
 34191       return *this;
 34194     template<typename t>
 34195     CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 34196       return (+*this).insert(n,list,pos,shared);
 34199     //! Insert a copy of the image \p img at the end of the current image list.
 34200     template<typename t>
 34201     CImgList<T>& operator<<(const CImg<t>& img) {
 34202       return insert(img);
 34205     //! Insert a copy of the image list \p list at the end of the current image list.
 34206     template<typename t>
 34207     CImgList<T>& operator<<(const CImgList<t>& list) {
 34208       return insert(list);
 34211     //! Return a copy of the current image list, where the image \p img has been inserted at the end.
 34212     template<typename t>
 34213     CImgList<T>& operator>>(CImg<t>& img) const {
 34214       typedef typename cimg::superset<T,t>::type Tt;
 34215       return CImgList<Tt>(*this).insert(img);
 34218     //! Insert a copy of the current image list at the beginning of the image list \p list.
 34219     template<typename t>
 34220     CImgList<T>& operator>>(CImgList<t>& list) const {
 34221       return list.insert(*this,0);
 34224     //! Remove the images at positions \p pos1 to \p pos2 from the image list.
 34225     CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
 34226       const unsigned int
 34227         npos1 = pos1<pos2?pos1:pos2,
 34228         tpos2 = pos1<pos2?pos2:pos1,
 34229         npos2 = tpos2<size?tpos2:size-1;
 34230       if (npos1>=size)
 34231         cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
 34232                    pixel_type(),data,size,npos1,tpos2);
 34233       else {
 34234         if (tpos2>=size)
 34235           cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
 34236                      pixel_type(),data,size,npos1,tpos2);
 34237         for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
 34238         const unsigned int nb = 1 + npos2 - npos1;
 34239         if (!(size-=nb)) return assign();
 34240         if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
 34241           if (npos1!=size) cimg_std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 34242           cimg_std::memset(data+size,0,sizeof(CImg<T>)*nb);
 34243         } else { // Removing items with reallocation.
 34244           allocsize>>=2;
 34245           while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
 34246           CImg<T> *new_data = new CImg<T>[allocsize];
 34247           if (npos1) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
 34248           if (npos1!=size) cimg_std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 34249           if (size!=allocsize) cimg_std::memset(new_data+size,0,sizeof(allocsize-size));
 34250           cimg_std::memset(data,0,sizeof(CImg<T>)*(size+nb));
 34251           delete[] data;
 34252           data = new_data;
 34255       return *this;
 34258     CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
 34259       return (+*this).remove(pos1,pos2);
 34262     //! Remove the image at position \p pos from the image list.
 34263     CImgList<T>& remove(const unsigned int pos) {
 34264       return remove(pos,pos);
 34267     CImgList<T> get_remove(const unsigned int pos) const {
 34268       return (+*this).remove(pos);
 34271     //! Remove the last image from the image list.
 34272     CImgList<T>& remove() {
 34273       if (size) return remove(size-1);
 34274       else cimg::warn("CImgList<%s>::remove() : List is empty",
 34275                       pixel_type());
 34276       return *this;
 34279     CImgList<T> get_remove() const {
 34280       return (+*this).remove();
 34283     //! Reverse list order.
 34284     CImgList<T>& reverse() {
 34285       for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
 34286       return *this;
 34289     CImgList<T> get_reverse() const {
 34290       return (+*this).reverse();
 34293     //! Get a sub-list.
 34294     CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
 34295       return get_crop(i0,i1,shared).transfer_to(*this);
 34298     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
 34299       if (i0>i1 || i1>=size)
 34300         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 34301                                     pixel_type(),i0,i1,size,data);
 34302       CImgList<T> res(i1-i0+1);
 34303       cimglist_for(res,l) res[l].assign((*this)[i0+l],shared);
 34304       return res;
 34307     //! Get sub-images of a sublist.
 34308     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 34309                       const int x0, const int y0, const int z0, const int v0,
 34310                       const int x1, const int y1, const int z1, const int v1) {
 34311       return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
 34314     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 34315                          const int x0, const int y0, const int z0, const int v0,
 34316                          const int x1, const int y1, const int z1, const int v1) const {
 34317       if (i0>i1 || i1>=size)
 34318         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 34319                                     pixel_type(),i0,i1,size,data);
 34320       CImgList<T> res(i1-i0+1);
 34321       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
 34322       return res;
 34325     //! Get sub-images of a sublist.
 34326     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 34327                       const int x0, const int y0, const int z0,
 34328                       const int x1, const int y1, const int z1) {
 34329       return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
 34332     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 34333                          const int x0, const int y0, const int z0,
 34334                          const int x1, const int y1, const int z1) const {
 34335       if (i0>i1 || i1>=size)
 34336         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 34337                                     pixel_type(),i0,i1,size,data);
 34338       CImgList<T> res(i1-i0+1);
 34339       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
 34340       return res;
 34343     //! Get sub-images of a sublist.
 34344     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 34345                       const int x0, const int y0,
 34346                       const int x1, const int y1) {
 34347       return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
 34350     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 34351                          const int x0, const int y0,
 34352                          const int x1, const int y1) const {
 34353       if (i0>i1 || i1>=size)
 34354         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 34355                                     pixel_type(),i0,i1,size,data);
 34356       CImgList<T> res(i1-i0+1);
 34357       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
 34358       return res;
 34361     //! Get sub-images of a sublist.
 34362     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 34363                       const int x0, const int x1) {
 34364       return get_crop(i0,i1,x0,x1).transfer_to(*this);
 34367     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 34368                          const int x0, const int x1) const {
 34369       if (i0>i1 || i1>=size)
 34370         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 34371                                     pixel_type(),i0,i1,size,data);
 34372       CImgList<T> res(i1-i0+1);
 34373       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,x1);
 34374       return res;
 34377     //! Display an image list into a CImgDisplay.
 34378     const CImgList<T>& operator>>(CImgDisplay& disp) const {
 34379       return display(disp);
 34382     //! Insert image \p img at the end of the list.
 34383     template<typename t>
 34384     CImgList<T>& push_back(const CImg<t>& img) {
 34385       return insert(img);
 34388     //! Insert image \p img at the front of the list.
 34389     template<typename t>
 34390     CImgList<T>& push_front(const CImg<t>& img) {
 34391       return insert(img,0);
 34394     //! Insert list \p list at the end of the current list.
 34395     template<typename t>
 34396     CImgList<T>& push_back(const CImgList<t>& list) {
 34397       return insert(list);
 34400     //! Insert list \p list at the front of the current list.
 34401     template<typename t>
 34402     CImgList<T>& push_front(const CImgList<t>& list) {
 34403       return insert(list,0);
 34406     //! Remove last element of the list.
 34407     CImgList<T>& pop_back() {
 34408       return remove(size-1);
 34411     //! Remove first element of the list.
 34412     CImgList<T>& pop_front() {
 34413       return remove(0);
 34416     //! Remove the element pointed by iterator \p iter.
 34417     CImgList<T>& erase(const iterator iter) {
 34418       return remove(iter-data);
 34421     //@}
 34422     //----------------------------
 34423     //
 34424     //! \name Fourier Transforms
 34425     //@{
 34426     //----------------------------
 34428     //! Compute the Fast Fourier Transform (along the specified axis).
 34429     CImgList<T>& FFT(const char axis, const bool invert=false) {
 34430       if (is_empty())
 34431         throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
 34432                                     pixel_type(),size,data);
 34433       if (!data[0])
 34434         throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
 34435                                                 pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
 34436       if (size>2)
 34437         cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
 34438                    pixel_type(),size,data);
 34439       if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
 34440       CImg<T> &Ir = data[0], &Ii = data[1];
 34441       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
 34442         throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)"
 34443                                     "have different dimensions",
 34444                                     pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
 34446 #ifdef cimg_use_fftw3
 34447       fftw_complex *data_in;
 34448       fftw_plan data_plan;
 34450       switch (cimg::uncase(axis)) {
 34451       case 'x' : {
 34452         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Ir.width);
 34453         data_plan = fftw_plan_dft_1d(Ir.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 34454         cimg_forYZV(Ir,y,z,k) {
 34455           T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
 34456           double *ptrd = (double*)data_in;
 34457           cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
 34458           fftw_execute(data_plan);
 34459           const unsigned int fact = Ir.width;
 34460           if (invert) { cimg_forX(Ir,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }}
 34461           else { cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }}
 34463       } break;
 34465       case 'y' : {
 34466         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
 34467         data_plan = fftw_plan_dft_1d(Ir.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 34468         const unsigned int off = Ir.width;
 34469         cimg_forXZV(Ir,x,z,k) {
 34470           T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
 34471           double *ptrd = (double*)data_in;
 34472           cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 34473           fftw_execute(data_plan);
 34474           const unsigned int fact = Ir.height;
 34475           if (invert) { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 34476           else { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 34478       } break;
 34480       case 'z' : {
 34481         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
 34482         data_plan = fftw_plan_dft_1d(Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 34483         const unsigned int off = Ir.width*Ir.height;
 34484         cimg_forXYV(Ir,x,y,k) {
 34485           T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
 34486           double *ptrd = (double*)data_in;
 34487           cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 34488           fftw_execute(data_plan);
 34489           const unsigned int fact = Ir.depth;
 34490           if (invert) { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 34491           else { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 34493       } break;
 34495       case 'v' : {
 34496         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
 34497         data_plan = fftw_plan_dft_1d(Ir.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 34498         const unsigned int off = Ir.width*Ir.height*Ir.depth;
 34499         cimg_forXYZ(Ir,x,y,z) {
 34500           T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
 34501           double *ptrd = (double*)data_in;
 34502           cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 34503           fftw_execute(data_plan);
 34504           const unsigned int fact = Ir.dim;
 34505           if (invert) { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 34506           else { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 34508       } break;
 34511       fftw_destroy_plan(data_plan);
 34512       fftw_free(data_in);
 34513 #else
 34514       switch (cimg::uncase(axis)) {
 34515       case 'x' : { // Fourier along X
 34516         const unsigned int N = Ir.width, N2 = (N>>1);
 34517         if (((N-1)&N) && N!=1)
 34518           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
 34519                                       pixel_type(),N);
 34520         for (unsigned int i=0, j=0; i<N2; ++i) {
 34521           if (j>i) cimg_forYZV(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));
 34522           if (j<N2) {
 34523             const unsigned int ri = N-1-i, rj = N-1-j;
 34524             cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
 34525           }}
 34526           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 34528         for (unsigned int delta=2; delta<=N; delta<<=1) {
 34529           const unsigned int delta2 = (delta>>1);
 34530           for (unsigned int i=0; i<N; i+=delta) {
 34531             float wr = 1, wi = 0;
 34532             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 34533                         ca = (float)cimg_std::cos(angle),
 34534                         sa = (float)cimg_std::sin(angle);
 34535             for (unsigned int k=0; k<delta2; ++k) {
 34536               const unsigned int j = i + k, nj = j + delta2;
 34537               cimg_forYZV(Ir,y,z,k) {
 34538                 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);
 34539                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 34540                 nir = (T)(ir - tmpr);
 34541                 nii = (T)(ii - tmpi);
 34542                 ir += (T)tmpr;
 34543                 ii += (T)tmpi;
 34545               const float nwr = wr*ca-wi*sa;
 34546               wi = wi*ca + wr*sa;
 34547               wr = nwr;
 34551         if (invert) (*this)/=N;
 34552       } break;
 34554       case 'y' : { // Fourier along Y
 34555         const unsigned int N = Ir.height, N2 = (N>>1);
 34556         if (((N-1)&N) && N!=1)
 34557           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
 34558                                       pixel_type(),N);
 34559         for (unsigned int i=0, j=0; i<N2; ++i) {
 34560           if (j>i) cimg_forXZV(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));
 34561           if (j<N2) {
 34562             const unsigned int ri = N-1-i, rj = N-1-j;
 34563             cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
 34564           }}
 34565           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 34567         for (unsigned int delta=2; delta<=N; delta<<=1) {
 34568           const unsigned int delta2 = (delta>>1);
 34569           for (unsigned int i=0; i<N; i+=delta) {
 34570             float wr = 1, wi = 0;
 34571             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 34572                         ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
 34573             for (unsigned int k=0; k<delta2; ++k) {
 34574               const unsigned int j = i + k, nj = j + delta2;
 34575               cimg_forXZV(Ir,x,z,k) {
 34576                 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);
 34577                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 34578                 nir = (T)(ir - tmpr);
 34579                 nii = (T)(ii - tmpi);
 34580                 ir += (T)tmpr;
 34581                 ii += (T)tmpi;
 34583               const float nwr = wr*ca-wi*sa;
 34584               wi = wi*ca + wr*sa;
 34585               wr = nwr;
 34589         if (invert) (*this)/=N;
 34590       } break;
 34592       case 'z' : { // Fourier along Z
 34593         const unsigned int N = Ir.depth, N2 = (N>>1);
 34594         if (((N-1)&N) && N!=1)
 34595           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
 34596                                       pixel_type(),N);
 34597         for (unsigned int i=0, j=0; i<N2; ++i) {
 34598           if (j>i) cimg_forXYV(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));
 34599           if (j<N2) {
 34600             const unsigned int ri = N-1-i, rj = N-1-j;
 34601             cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
 34602           }}
 34603           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 34605         for (unsigned int delta=2; delta<=N; delta<<=1) {
 34606           const unsigned int delta2 = (delta>>1);
 34607           for (unsigned int i=0; i<N; i+=delta) {
 34608             float wr = 1, wi = 0;
 34609             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 34610                         ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
 34611             for (unsigned int k=0; k<delta2; ++k) {
 34612               const unsigned int j = i + k, nj = j + delta2;
 34613               cimg_forXYV(Ir,x,y,k) {
 34614                 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);
 34615                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 34616                 nir = (T)(ir - tmpr);
 34617                 nii = (T)(ii - tmpi);
 34618                 ir += (T)tmpr;
 34619                 ii += (T)tmpi;
 34621               const float nwr = wr*ca-wi*sa;
 34622               wi = wi*ca + wr*sa;
 34623               wr = nwr;
 34627         if (invert) (*this)/=N;
 34628       } break;
 34630       default :
 34631         throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
 34633 #endif
 34634       return *this;
 34637     CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
 34638       return CImgList<Tfloat>(*this).FFT(axis,invert);
 34641     //! Compute the Fast Fourier Transform of a complex image.
 34642     CImgList<T>& FFT(const bool invert=false) {
 34643       if (is_empty())
 34644         throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
 34645                                     pixel_type(),size,data);
 34646       if (size>2)
 34647         cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
 34648                    pixel_type(),size,data);
 34649       if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
 34650       CImg<T> &Ir = data[0], &Ii = data[1];
 34651       if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
 34652         throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
 34653                                     "of the instance image have different dimensions",
 34654                                     pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
 34655                                     Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
 34656 #ifdef cimg_use_fftw3
 34657       fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
 34658       fftw_plan data_plan;
 34659       const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
 34660       data_plan = fftw_plan_dft_3d(Ir.width,Ir.height,Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 34661       cimg_forV(Ir,k) {
 34662         T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
 34663         double *ptrd = (double*)data_in;
 34664         for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 34665           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 34666             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 34667               *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
 34669         fftw_execute(data_plan);
 34670         ptrd = (double*)data_in;
 34671         ptrr = Ir.ptr(0,0,0,k);
 34672         ptri = Ii.ptr(0,0,0,k);
 34673         if (!invert) for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 34674           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 34675             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 34676               *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
 34678         else for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 34679           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 34680             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 34681               *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
 34684       fftw_destroy_plan(data_plan);
 34685       fftw_free(data_in);
 34686 #else
 34687       if (Ir.depth>1)  FFT('z',invert);
 34688       if (Ir.height>1) FFT('y',invert);
 34689       if (Ir.width>1)  FFT('x',invert);
 34690 #endif
 34691       return *this;
 34694     CImgList<Tfloat> get_FFT(const bool invert=false) const {
 34695       return CImgList<Tfloat>(*this).FFT(invert);
 34698     // Return a list where each image has been split along the specified axis.
 34699     CImgList<T>& split(const char axis) {
 34700       return get_split(axis).transfer_to(*this);
 34703     CImgList<T> get_split(const char axis) const {
 34704       CImgList<T> res;
 34705       cimglist_for(*this,l) {
 34706         CImgList<T> tmp = data[l].get_split(axis);
 34707         const unsigned int pos = res.size;
 34708         res.insert(tmp.size);
 34709         cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
 34711       return res;
 34714     //! Return a single image which is the concatenation of all images of the current CImgList instance.
 34715     /**
 34716        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 34717        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 34718        \return A CImg<T> image corresponding to the concatenation is returned.
 34719     **/
 34720     CImg<T> get_append(const char axis, const char align='p') const {
 34721       if (is_empty()) return CImg<T>();
 34722       if (size==1) return +((*this)[0]);
 34723       unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
 34724       CImg<T> res;
 34725       switch (cimg::uncase(axis)) {
 34726       case 'x' : {
 34727         switch (cimg::uncase(align)) {
 34728         case 'x' : { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
 34729         case 'y' : { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
 34730         case 'z' : { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 34731         case 'v' : { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 34732         default :
 34733           cimglist_for(*this,l) {
 34734             const CImg<T>& img = (*this)[l];
 34735             dx += img.width;
 34736             dy = cimg::max(dy,img.height);
 34737             dz = cimg::max(dz,img.depth);
 34738             dv = cimg::max(dv,img.dim);
 34741         res.assign(dx,dy,dz,dv,0);
 34742         switch (cimg::uncase(align)) {
 34743         case 'x' : {
 34744           cimglist_for(*this,l) {
 34745             res.draw_image(pos,CImg<T>((*this)[l],true).unroll('x'));
 34746             pos+=(*this)[l].size();
 34748         } break;
 34749         case 'y' : {
 34750           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('y'));
 34751         } break;
 34752         case 'z' : {
 34753           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('z'));
 34754         } break;
 34755         case 'v' : {
 34756           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('v'));
 34757         } break;
 34758         case 'p' : {
 34759           cimglist_for(*this,l) { res.draw_image(pos,(*this)[l]); pos+=(*this)[l].width; }
 34760         } break;
 34761         case 'n' : {
 34762           cimglist_for(*this,l) {
 34763             res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
 34764             pos+=(*this)[l].width;
 34766         } break;
 34767         default : {
 34768           cimglist_for(*this,l) {
 34769             res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
 34770             pos+=(*this)[l].width;
 34772         } break;
 34774       } break;
 34776       case 'y' : {
 34777         switch (cimg::uncase(align)) {
 34778         case 'x' : { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 34779         case 'y' : { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
 34780         case 'z' : { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 34781         case 'v' : { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 34782         default :
 34783           cimglist_for(*this,l) {
 34784             const CImg<T>& img = (*this)[l];
 34785             dx = cimg::max(dx,img.width);
 34786             dy += img.height;
 34787             dz = cimg::max(dz,img.depth);
 34788             dv = cimg::max(dv,img.dim);
 34791         res.assign(dx,dy,dz,dv,0);
 34792         switch (cimg::uncase(align)) {
 34793         case 'x' : {
 34794           cimglist_for(*this,l) res.draw_image(0,++pos,CImg<T>((*this)[l],true).unroll('x'));
 34795         } break;
 34796         case 'y' : {
 34797           cimglist_for(*this,l) {
 34798             res.draw_image(0,pos,CImg<T>((*this)[l],true).unroll('y'));
 34799             pos+=(*this)[l].size();
 34801         } break;
 34802         case 'z' : {
 34803           cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('z'));
 34804         } break;
 34805         case 'v' : {
 34806           cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 34807         } break;
 34808         case 'p' : {
 34809           cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
 34810         } break;
 34811         case 'n' : {
 34812           cimglist_for(*this,l) {
 34813             res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
 34814             pos+=(*this)[l].height;
 34816         } break;
 34817         default : {
 34818           cimglist_for(*this,l) {
 34819             res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
 34820           pos+=(*this)[l].height;
 34822         } break;
 34824       } break;
 34826       case 'z' : {
 34827         switch (cimg::uncase(align)) {
 34828         case 'x' : { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 34829         case 'y' : { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 34830         case 'z' : { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
 34831         case 'v' : { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 34832         default :
 34833           cimglist_for(*this,l) {
 34834             const CImg<T>& img = (*this)[l];
 34835             dx = cimg::max(dx,img.width);
 34836             dy = cimg::max(dy,img.height);
 34837             dz += img.depth;
 34838             dv = cimg::max(dv,img.dim);
 34841         res.assign(dx,dy,dz,dv,0);
 34842         switch (cimg::uncase(align)) {
 34843         case 'x' : {
 34844           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
 34845         } break;
 34846         case 'y' : {
 34847           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
 34848         } break;
 34849         case 'z' : {
 34850           cimglist_for(*this,l) {
 34851             res.draw_image(0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
 34852             pos+=(*this)[l].size();
 34854         } break;
 34855         case 'v' : {
 34856           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 34857         } break;
 34858         case 'p' : {
 34859           cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
 34860         } break;
 34861         case 'n' : {
 34862           cimglist_for(*this,l) {
 34863             res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
 34864             pos+=(*this)[l].depth;
 34866         } break;
 34867         case 'c' : {
 34868           cimglist_for(*this,l) {
 34869             res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
 34870             pos+=(*this)[l].depth;
 34872         } break;
 34874       } break;
 34876       case 'v' : {
 34877         switch (cimg::uncase(align)) {
 34878         case 'x' : { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 34879         case 'y' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 34880         case 'z' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 34881         case 'v' : { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
 34882         default :
 34883           cimglist_for(*this,l) {
 34884             const CImg<T>& img = (*this)[l];
 34885             dx = cimg::max(dx,img.width);
 34886             dy = cimg::max(dy,img.height);
 34887             dz = cimg::max(dz,img.depth);
 34888             dv += img.dim;
 34891         res.assign(dx,dy,dz,dv,0);
 34892         switch (cimg::uncase(align)) {
 34893         case 'x' : {
 34894           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
 34895         } break;
 34896         case 'y' : {
 34897           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
 34898         } break;
 34899         case 'z' : {
 34900           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 34901         } break;
 34902         case 'v' : {
 34903           cimglist_for(*this,l) {
 34904             res.draw_image(0,0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
 34905             pos+=(*this)[l].size();
 34907         } break;
 34908         case 'p' : {
 34909           cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
 34910         } break;
 34911         case 'n' : {
 34912           cimglist_for(*this,l) {
 34913             res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
 34914             pos+=(*this)[l].dim;
 34916         } break;
 34917         case 'c' : {
 34918           cimglist_for(*this,l) {
 34919             res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
 34920             pos+=(*this)[l].dim;
 34922         } break;
 34924       } break;
 34925       default :
 34926         throw CImgArgumentException("CImgList<%s>::get_append() : unknow axis '%c', must be 'x','y','z' or 'v'",
 34927                                     pixel_type(),axis);
 34929       return res;
 34932     //! Create an auto-cropped font (along the X axis) from a input font \p font.
 34933     CImgList<T>& crop_font() {
 34934       return get_crop_font().transfer_to(*this);
 34937     CImgList<T> get_crop_font() const {
 34938       CImgList<T> res;
 34939       cimglist_for(*this,l) {
 34940         const CImg<T>& letter = (*this)[l];
 34941         int xmin = letter.width, xmax = 0;
 34942         cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
 34943         if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
 34944         else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
 34946       res[' '].resize(res['f'].width);
 34947       res[' '+256].resize(res['f'].width);
 34948       return res;
 34951     //! Invert primitives orientation of a 3D object.
 34952     CImgList<T>& invert_object3d() {
 34953       cimglist_for(*this,l) {
 34954         CImg<T>& p = data[l];
 34955         const unsigned int siz = p.size();
 34956         if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
 34957         else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
 34959       return *this;
 34962     CImgList<T> get_invert_object3d() const {
 34963       return (+*this).invert_object3d();
 34966     //! Return a CImg pre-defined font with desired size.
 34967     /**
 34968        \param font_height = height of the desired font (can be 11,13,24,38 or 57)
 34969        \param fixed_size = tell if the font has a fixed or variable width.
 34970     **/
 34971     static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
 34972       if (font_width<=11) {
 34973         static CImgList<T> font7x11, nfont7x11;
 34974         if (!variable_size && !font7x11)  font7x11 = _font(cimg::font7x11,7,11,1,0,false);
 34975         if (variable_size  && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
 34976         return variable_size?nfont7x11:font7x11;
 34978       if (font_width<=13) {
 34979         static CImgList<T> font10x13, nfont10x13;
 34980         if (!variable_size && !font10x13)  font10x13 = _font(cimg::font10x13,10,13,1,0,false);
 34981         if (variable_size  && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
 34982         return variable_size?nfont10x13:font10x13;
 34984       if (font_width<=17) {
 34985         static CImgList<T> font8x17, nfont8x17;
 34986         if (!variable_size && !font8x17)  font8x17 = _font(cimg::font8x17,8,17,1,0,false);
 34987         if (variable_size  && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
 34988         return variable_size?nfont8x17:font8x17;
 34990       if (font_width<=19) {
 34991         static CImgList<T> font10x19, nfont10x19;
 34992         if (!variable_size && !font10x19)  font10x19 = _font(cimg::font10x19,10,19,2,0,false);
 34993         if (variable_size  && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
 34994         return variable_size?nfont10x19:font10x19;
 34996       if (font_width<=24) {
 34997         static CImgList<T> font12x24, nfont12x24;
 34998         if (!variable_size && !font12x24)  font12x24 = _font(cimg::font12x24,12,24,2,0,false);
 34999         if (variable_size  && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
 35000         return variable_size?nfont12x24:font12x24;
 35002       if (font_width<=32) {
 35003         static CImgList<T> font16x32, nfont16x32;
 35004         if (!variable_size && !font16x32)  font16x32 = _font(cimg::font16x32,16,32,2,0,false);
 35005         if (variable_size  && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
 35006         return variable_size?nfont16x32:font16x32;
 35008       if (font_width<=38) {
 35009         static CImgList<T> font19x38, nfont19x38;
 35010         if (!variable_size && !font19x38)  font19x38 = _font(cimg::font19x38,19,38,3,0,false);
 35011         if (variable_size  && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
 35012         return variable_size?nfont19x38:font19x38;
 35014       static CImgList<T> font29x57, nfont29x57;
 35015       if (!variable_size && !font29x57)  font29x57 = _font(cimg::font29x57,29,57,5,0,false);
 35016       if (variable_size  && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
 35017       return variable_size?nfont29x57:font29x57;
 35020     static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
 35021                              const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
 35022       CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
 35023       const unsigned int *ptr = font;
 35024       unsigned int m = 0, val = 0;
 35025       for (unsigned int y=0; y<h; ++y)
 35026         for (unsigned int x=0; x<256*w; ++x) {
 35027           m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
 35028           CImg<T>& img = res[x/w], &mask = res[x/w+256];
 35029           unsigned int xm = x%w;
 35030           img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
 35032       if (variable_size) res.crop_font();
 35033       if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
 35034       return res;
 35037     //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
 35038     /**
 35039        This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
 35040        Images of the list are concatenated in a single temporarly image for visualization purposes.
 35041        The function returns immediately.
 35042        \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
 35043        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 35044        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 35045        \return A reference to the current CImgList instance is returned.
 35046     **/
 35047     const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
 35048       get_append(axis,align).display(disp);
 35049       return *this;
 35052     //! Display the current CImgList instance in a new display window.
 35053     /**
 35054        This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
 35055        Images of the list are concatenated in a single temporarly image for visualization purposes.
 35056        The function returns when a key is pressed or the display window is closed by the user.
 35057        \param title : specify the title of the opening display window.
 35058        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 35059        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 35060        \return A reference to the current CImgList instance is returned.
 35061     **/
 35062     const CImgList<T>& display(CImgDisplay &disp,
 35063                                const bool display_info, const char axis='x', const char align='p') const {
 35064       if (is_empty())
 35065         throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
 35066                                     pixel_type(),size,data);
 35067       const CImg<T> visu = get_append(axis,align);
 35068       if (display_info) print(disp.title);
 35069       visu.display(disp,false);
 35070       return *this;
 35073     //! Display the current CImgList instance in a new display window.
 35074     const CImgList<T>& display(const char *const title=0,
 35075                                const bool display_info=true, const char axis='x', const char align='p') const {
 35076       const CImg<T> visu = get_append(axis,align);
 35077       char ntitle[64] = { 0 };
 35078       if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 35079       if (display_info) print(title?title:ntitle);
 35080       visu.display(title?title:ntitle,false);
 35081       return *this;
 35084     //@}
 35085     //----------------------------------
 35086     //
 35087     //! \name Input-Output
 35088     //@{
 35089     //----------------------------------
 35091     //! Return a C-string containing the values of all images in the instance list.
 35092     CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
 35093       if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
 35094       CImgList<charT> items;
 35095       for (unsigned int l = 0; l<size-1; ++l) {
 35096         CImg<charT> item = data[l].value_string(separator,0);
 35097         item[item.size()-1] = separator;
 35098         items.insert(item);
 35100       items.insert(data[size-1].value_string(separator,0));
 35101       CImg<charT> res = items.get_append('x');
 35102       if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
 35103       return res;
 35106     //! Print informations about the list on the standard output.
 35107     const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
 35108       unsigned long msiz = 0;
 35109       cimglist_for(*this,l) msiz += data[l].size();
 35110       msiz*=sizeof(T);
 35111       const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
 35112       char ntitle[64] = { 0 };
 35113       if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 35114       cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
 35115                    title?title:ntitle,(void*)this,size,
 35116                    mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 35117                    mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 35118                    pixel_type(),(void*)data);
 35119       char tmp[16] = { 0 };
 35120       cimglist_for(*this,ll) {
 35121         cimg_std::sprintf(tmp,"[%d]",ll);
 35122         cimg_std::fprintf(cimg_stdout,"  ");
 35123         data[ll].print(tmp,display_stats);
 35124         if (ll==3 && size>8) { ll = size-5; cimg_std::fprintf(cimg_stdout,"  ...\n"); }
 35126       return *this;
 35129     //! Load an image list from a file.
 35130     CImgList<T>& load(const char *const filename) {
 35131       const char *ext = cimg::split_filename(filename);
 35132       const unsigned int odebug = cimg::exception_mode();
 35133       cimg::exception_mode() = 0;
 35134       assign();
 35135       try {
 35136 #ifdef cimglist_load_plugin
 35137         cimglist_load_plugin(filename);
 35138 #endif
 35139 #ifdef cimglist_load_plugin1
 35140         cimglist_load_plugin1(filename);
 35141 #endif
 35142 #ifdef cimglist_load_plugin2
 35143         cimglist_load_plugin2(filename);
 35144 #endif
 35145 #ifdef cimglist_load_plugin3
 35146         cimglist_load_plugin3(filename);
 35147 #endif
 35148 #ifdef cimglist_load_plugin4
 35149         cimglist_load_plugin4(filename);
 35150 #endif
 35151 #ifdef cimglist_load_plugin5
 35152         cimglist_load_plugin5(filename);
 35153 #endif
 35154 #ifdef cimglist_load_plugin6
 35155         cimglist_load_plugin6(filename);
 35156 #endif
 35157 #ifdef cimglist_load_plugin7
 35158         cimglist_load_plugin7(filename);
 35159 #endif
 35160 #ifdef cimglist_load_plugin8
 35161         cimglist_load_plugin8(filename);
 35162 #endif
 35163         if (!cimg::strcasecmp(ext,"tif") ||
 35164             !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
 35165         if (!cimg::strcasecmp(ext,"cimg") ||
 35166             !cimg::strcasecmp(ext,"cimgz") ||
 35167             !ext[0]) load_cimg(filename);
 35168         if (!cimg::strcasecmp(ext,"rec") ||
 35169             !cimg::strcasecmp(ext,"par")) load_parrec(filename);
 35170         if (!cimg::strcasecmp(ext,"avi") ||
 35171             !cimg::strcasecmp(ext,"mov") ||
 35172             !cimg::strcasecmp(ext,"asf") ||
 35173             !cimg::strcasecmp(ext,"divx") ||
 35174             !cimg::strcasecmp(ext,"flv") ||
 35175             !cimg::strcasecmp(ext,"mpg") ||
 35176             !cimg::strcasecmp(ext,"m1v") ||
 35177             !cimg::strcasecmp(ext,"m2v") ||
 35178             !cimg::strcasecmp(ext,"m4v") ||
 35179             !cimg::strcasecmp(ext,"mjp") ||
 35180             !cimg::strcasecmp(ext,"mkv") ||
 35181             !cimg::strcasecmp(ext,"mpe") ||
 35182             !cimg::strcasecmp(ext,"movie") ||
 35183             !cimg::strcasecmp(ext,"ogm") ||
 35184             !cimg::strcasecmp(ext,"qt") ||
 35185             !cimg::strcasecmp(ext,"rm") ||
 35186             !cimg::strcasecmp(ext,"vob") ||
 35187             !cimg::strcasecmp(ext,"wmv") ||
 35188             !cimg::strcasecmp(ext,"xvid") ||
 35189             !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
 35190         if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
 35191         if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
 35192       } catch (CImgIOException& e) {
 35193         if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
 35194           cimg::exception_mode() = odebug;
 35195           throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
 35196         } else try {
 35197           assign(1);
 35198           data->load(filename);
 35199         } catch (CImgException&) {
 35200           assign();
 35203       cimg::exception_mode() = odebug;
 35204       if (is_empty())
 35205         throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
 35206       return *this;
 35209     static CImgList<T> get_load(const char *const filename) {
 35210       return CImgList<T>().load(filename);
 35213     //! Load an image list from a .cimg file.
 35214     CImgList<T>& load_cimg(const char *const filename) {
 35215       return _load_cimg(0,filename);
 35218     static CImgList<T> get_load_cimg(const char *const filename) {
 35219       return CImgList<T>().load_cimg(filename);
 35222     //! Load an image list from a .cimg file.
 35223     CImgList<T>& load_cimg(cimg_std::FILE *const file) {
 35224       return _load_cimg(file,0);
 35227     static CImgList<T> get_load_cimg(cimg_std::FILE *const file) {
 35228       return CImgList<T>().load_cimg(file);
 35231     CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename) {
 35232 #ifdef cimg_use_zlib
 35233 #define _cimgz_load_cimg_case(Tss) { \
 35234    Bytef *const cbuf = new Bytef[csiz]; \
 35235    cimg::fread(cbuf,csiz,nfile); \
 35236    raw.assign(W,H,D,V); \
 35237    unsigned long destlen = raw.size()*sizeof(T); \
 35238    uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
 35239    delete[] cbuf; \
 35240    const Tss *ptrs = raw.data; \
 35241    for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
 35243 #else
 35244 #define _cimgz_load_cimg_case(Tss) \
 35245    throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
 35246                          pixel_type(),filename?filename:"(FILE*)");
 35247 #endif
 35249 #define _cimg_load_cimg_case(Ts,Tss) \
 35250       if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 35251         for (unsigned int l = 0; l<N; ++l) { \
 35252           j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
 35253           W = H = D = V = 0; csiz = 0; \
 35254           if ((err = cimg_std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
 35255             throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 35256                                   pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
 35257           if (W*H*D*V>0) { \
 35258             CImg<Tss> raw; \
 35259             CImg<T> &img = data[l]; \
 35260             img.assign(W,H,D,V); \
 35261             T *ptrd = img.data; \
 35262             if (err==5) _cimgz_load_cimg_case(Tss) \
 35263             else for (int toread = (int)img.size(); toread>0; ) { \
 35264               raw.assign(cimg::min(toread,cimg_iobuffer)); \
 35265               cimg::fread(raw.data,raw.width,nfile); \
 35266               if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
 35267               toread-=raw.width; \
 35268               const Tss *ptrs = raw.data; \
 35269               for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
 35270             } \
 35271           } \
 35272         } \
 35273         loaded = true; \
 35276       if (!filename && !file)
 35277         throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 35278                                     pixel_type());
 35279       typedef unsigned char uchar;
 35280       typedef unsigned short ushort;
 35281       typedef unsigned int uint;
 35282       typedef unsigned long ulong;
 35283       const int cimg_iobuffer = 12*1024*1024;
 35284       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 35285       bool loaded = false, endian = cimg::endianness();
 35286       char tmp[256], str_pixeltype[256], str_endian[256];
 35287       unsigned int j, err, N = 0, W, H, D, V, csiz;
 35288       int i;
 35289       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 35290       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 35291       if (err<2) {
 35292         if (!file) cimg::fclose(nfile);
 35293         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
 35294                               pixel_type(),filename?filename:"(FILE*)");
 35296       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 35297       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 35298       assign(N);
 35299       _cimg_load_cimg_case("bool",bool);
 35300       _cimg_load_cimg_case("unsigned_char",uchar);
 35301       _cimg_load_cimg_case("uchar",uchar);
 35302       _cimg_load_cimg_case("char",char);
 35303       _cimg_load_cimg_case("unsigned_short",ushort);
 35304       _cimg_load_cimg_case("ushort",ushort);
 35305       _cimg_load_cimg_case("short",short);
 35306       _cimg_load_cimg_case("unsigned_int",uint);
 35307       _cimg_load_cimg_case("uint",uint);
 35308       _cimg_load_cimg_case("int",int);
 35309       _cimg_load_cimg_case("unsigned_long",ulong);
 35310       _cimg_load_cimg_case("ulong",ulong);
 35311       _cimg_load_cimg_case("long",long);
 35312       _cimg_load_cimg_case("float",float);
 35313       _cimg_load_cimg_case("double",double);
 35314       if (!loaded) {
 35315         if (!file) cimg::fclose(nfile);
 35316         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
 35317                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 35319       if (!file) cimg::fclose(nfile);
 35320       return *this;
 35323     //! Load a sub-image list from a non compressed .cimg file.
 35324     CImgList<T>& load_cimg(const char *const filename,
 35325                            const unsigned int n0, const unsigned int n1,
 35326                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 35327                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 35328       return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 35331     static CImgList<T> get_load_cimg(const char *const filename,
 35332                                      const unsigned int n0, const unsigned int n1,
 35333                                      const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 35334                                      const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 35335       return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 35338     //! Load a sub-image list from a non compressed .cimg file.
 35339     CImgList<T>& load_cimg(cimg_std::FILE *const file,
 35340                            const unsigned int n0, const unsigned int n1,
 35341                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 35342                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 35343       return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 35346     static CImgList<T> get_load_cimg(cimg_std::FILE *const file,
 35347                                      const unsigned int n0, const unsigned int n1,
 35348                                      const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 35349                                      const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 35350       return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 35353     CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename,
 35354                             const unsigned int n0, const unsigned int n1,
 35355                             const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 35356                             const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 35357 #define _cimg_load_cimg_case2(Ts,Tss) \
 35358       if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 35359         for (unsigned int l = 0; l<=nn1; ++l) { \
 35360           j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
 35361           W = H = D = V = 0; \
 35362           if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
 35363             throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 35364                                   pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
 35365           if (W*H*D*V>0) { \
 35366             if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
 35367             else { \
 35368               const unsigned int \
 35369                 nx1 = x1>=W?W-1:x1, \
 35370                 ny1 = y1>=H?H-1:y1, \
 35371                 nz1 = z1>=D?D-1:z1, \
 35372                 nv1 = v1>=V?V-1:v1; \
 35373               CImg<Tss> raw(1+nx1-x0); \
 35374               CImg<T> &img = data[l-n0]; \
 35375               img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
 35376               T *ptrd = img.data; \
 35377               const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
 35378               if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
 35379               for (unsigned int v=1+nv1-v0; v; --v) { \
 35380                 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
 35381                 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
 35382                 for (unsigned int z=1+nz1-z0; z; --z) { \
 35383                   const unsigned int skipyb = y0*W*sizeof(Tss); \
 35384                   if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
 35385                   for (unsigned int y=1+ny1-y0; y; --y) { \
 35386                     const unsigned int skipxb = x0*sizeof(Tss); \
 35387                     if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
 35388                     cimg::fread(raw.data,raw.width,nfile); \
 35389                     if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
 35390                     const Tss *ptrs = raw.data; \
 35391                     for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
 35392                     const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
 35393                     if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
 35394                   } \
 35395                   const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
 35396                   if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
 35397                 } \
 35398                 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
 35399                 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
 35400               } \
 35401               const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
 35402               if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
 35403             } \
 35404           } \
 35405         } \
 35406         loaded = true; \
 35409       if (!filename && !file)
 35410         throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 35411                                     pixel_type());
 35412       typedef unsigned char uchar;
 35413       typedef unsigned short ushort;
 35414       typedef unsigned int uint;
 35415       typedef unsigned long ulong;
 35416       if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
 35417         throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
 35418                                     "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
 35419                                     pixel_type(),filename?filename:"(FILE*)",
 35420                                     n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 35421       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 35422       bool loaded = false, endian = cimg::endianness();
 35423       char tmp[256], str_pixeltype[256], str_endian[256];
 35424       unsigned int j, err, N, W, H, D, V;
 35425       int i;
 35426       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 35427       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 35428       if (err<2) {
 35429         if (!file) cimg::fclose(nfile);
 35430         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
 35431                               pixel_type(),filename?filename:"(FILE*)");
 35433       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 35434       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 35435       const unsigned int nn1 = n1>=N?N-1:n1;
 35436       assign(1+nn1-n0);
 35437       _cimg_load_cimg_case2("bool",bool);
 35438       _cimg_load_cimg_case2("unsigned_char",uchar);
 35439       _cimg_load_cimg_case2("uchar",uchar);
 35440       _cimg_load_cimg_case2("char",char);
 35441       _cimg_load_cimg_case2("unsigned_short",ushort);
 35442       _cimg_load_cimg_case2("ushort",ushort);
 35443       _cimg_load_cimg_case2("short",short);
 35444       _cimg_load_cimg_case2("unsigned_int",uint);
 35445       _cimg_load_cimg_case2("uint",uint);
 35446       _cimg_load_cimg_case2("int",int);
 35447       _cimg_load_cimg_case2("unsigned_long",ulong);
 35448       _cimg_load_cimg_case2("ulong",ulong);
 35449       _cimg_load_cimg_case2("long",long);
 35450       _cimg_load_cimg_case2("float",float);
 35451       _cimg_load_cimg_case2("double",double);
 35452       if (!loaded) {
 35453         if (!file) cimg::fclose(nfile);
 35454         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
 35455                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 35457       if (!file) cimg::fclose(nfile);
 35458       return *this;
 35461     //! Load an image list from a PAR/REC (Philips) file.
 35462     CImgList<T>& load_parrec(const char *const filename) {
 35463       if (!filename)
 35464         throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
 35465                                     pixel_type());
 35466       char body[1024], filenamepar[1024], filenamerec[1024];
 35467       const char *ext = cimg::split_filename(filename,body);
 35468       if (!cimg::strcmp(ext,"par")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.rec",body); }
 35469       if (!cimg::strcmp(ext,"PAR")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.REC",body); }
 35470       if (!cimg::strcmp(ext,"rec")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.par",body); }
 35471       if (!cimg::strcmp(ext,"REC")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.PAR",body); }
 35472       cimg_std::FILE *file = cimg::fopen(filenamepar,"r");
 35474       // Parse header file
 35475       CImgList<floatT> st_slices;
 35476       CImgList<uintT> st_global;
 35477       int err;
 35478       char line[256] = { 0 };
 35479       do { err=cimg_std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
 35480       do {
 35481         unsigned int sn,sizex,sizey,pixsize;
 35482         float rs,ri,ss;
 35483         err = cimg_std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss);
 35484         if (err==7) {
 35485           st_slices.insert(CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
 35486                                                ri,rs,ss,0));
 35487           unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
 35488           if (i==st_global.size) st_global.insert(CImg<uintT>::vector(sizex,sizey,sn));
 35489           else {
 35490             CImg<uintT> &vec = st_global[i];
 35491             if (sizex>vec[0]) vec[0] = sizex;
 35492             if (sizey>vec[1]) vec[1] = sizey;
 35493             vec[2] = sn;
 35495           st_slices[st_slices.size-1][7] = (float)i;
 35497       } while (err==7);
 35499       // Read data
 35500       cimg_std::FILE *file2 = cimg::fopen(filenamerec,"rb");
 35501       { cimglist_for(st_global,l) {
 35502         const CImg<uintT>& vec = st_global[l];
 35503         insert(CImg<T>(vec[0],vec[1],vec[2]));
 35504       }}
 35506       cimglist_for(st_slices,l) {
 35507         const CImg<floatT>& vec = st_slices[l];
 35508         const unsigned int
 35509           sn = (unsigned int)vec[0]-1,
 35510           pixsize = (unsigned int)vec[1],
 35511           sizex = (unsigned int)vec[2],
 35512           sizey = (unsigned int)vec[3],
 35513           imn = (unsigned int)vec[7];
 35514         const float ri = vec[4], rs = vec[5], ss = vec[6];
 35515         switch (pixsize) {
 35516         case 8 : {
 35517           CImg<ucharT> buf(sizex,sizey);
 35518           cimg::fread(buf.data,sizex*sizey,file2);
 35519           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 35520           CImg<T>& img = (*this)[imn];
 35521           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 35522         } break;
 35523         case 16 : {
 35524           CImg<ushortT> buf(sizex,sizey);
 35525           cimg::fread(buf.data,sizex*sizey,file2);
 35526           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 35527           CImg<T>& img = (*this)[imn];
 35528           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 35529         } break;
 35530         case 32 : {
 35531           CImg<uintT> buf(sizex,sizey);
 35532           cimg::fread(buf.data,sizex*sizey,file2);
 35533           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 35534           CImg<T>& img = (*this)[imn];
 35535           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 35536         } break;
 35537         default :
 35538           cimg::fclose(file);
 35539           cimg::fclose(file2);
 35540           throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
 35541                                 pixel_type(),filename,pixsize);
 35544       cimg::fclose(file);
 35545       cimg::fclose(file2);
 35546       if (!size)
 35547         throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
 35548                               pixel_type(),filename);
 35549       return *this;
 35552     static CImgList<T> get_load_parrec(const char *const filename) {
 35553       return CImgList<T>().load_parrec(filename);
 35556     //! Load an image sequence from a YUV file.
 35557     CImgList<T>& load_yuv(const char *const filename,
 35558                           const unsigned int sizex, const unsigned int sizey,
 35559                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35560                           const unsigned int step_frame=1, const bool yuv2rgb=true) {
 35561       return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 35564     static CImgList<T> get_load_yuv(const char *const filename,
 35565                                     const unsigned int sizex, const unsigned int sizey=1,
 35566                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35567                                     const unsigned int step_frame=1, const bool yuv2rgb=true) {
 35568       return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 35571     //! Load an image sequence from a YUV file.
 35572     CImgList<T>& load_yuv(cimg_std::FILE *const file,
 35573                           const unsigned int sizex, const unsigned int sizey,
 35574                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35575                           const unsigned int step_frame=1, const bool yuv2rgb=true) {
 35576       return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 35579     static CImgList<T> get_load_yuv(cimg_std::FILE *const file,
 35580                                     const unsigned int sizex, const unsigned int sizey=1,
 35581                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35582                                     const unsigned int step_frame=1, const bool yuv2rgb=true) {
 35583       return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 35586     CImgList<T>& _load_yuv(cimg_std::FILE *const file, const char *const filename,
 35587                            const unsigned int sizex, const unsigned int sizey,
 35588                            const unsigned int first_frame, const unsigned int last_frame,
 35589                            const unsigned int step_frame, const bool yuv2rgb) {
 35590       if (!filename && !file)
 35591         throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
 35592                                     pixel_type());
 35593       if (sizex%2 || sizey%2)
 35594         throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
 35595                                     "even numbers (given are %ux%u)\n",
 35596                                     pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 35597       if (!sizex || !sizey)
 35598         throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
 35599                                     pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 35601       const unsigned int
 35602         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 35603         nlast_frame = first_frame<last_frame?last_frame:first_frame,
 35604         nstep_frame = step_frame?step_frame:1;
 35606       CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
 35607       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 35608       bool stopflag = false;
 35609       int err;
 35610       if (nfirst_frame) {
 35611         err = cimg_std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
 35612         if (err) {
 35613           if (!file) cimg::fclose(nfile);
 35614           throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
 35615                                 "(out of range error).",
 35616                                 pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
 35619       unsigned int frame;
 35620       for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
 35621         tmp.fill(0);
 35622         // *TRY* to read the luminance part, do not replace by cimg::fread !
 35623         err = (int)cimg_std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
 35624         if (err!=(int)(tmp.width*tmp.height)) {
 35625           stopflag = true;
 35626           if (err>0)
 35627             cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
 35628                        " or given image dimensions (%u,%u) are incorrect.",
 35629                        pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 35630         } else {
 35631           UV.fill(0);
 35632           // *TRY* to read the luminance part, do not replace by cimg::fread !
 35633           err = (int)cimg_std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
 35634           if (err!=(int)(UV.size())) {
 35635             stopflag = true;
 35636             if (err>0)
 35637               cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
 35638                          " or given image dimensions (%u,%u) are incorrect.",
 35639                          pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 35640           } else {
 35641             cimg_forXY(UV,x,y) {
 35642               const int x2 = x*2, y2 = y*2;
 35643               tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
 35644               tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
 35646             if (yuv2rgb) tmp.YCbCrtoRGB();
 35647             insert(tmp);
 35648             if (nstep_frame>1) cimg_std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
 35652       if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
 35653         cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
 35654                    pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
 35655       if (!file) cimg::fclose(nfile);
 35656       return *this;
 35659     //! Load an image from a video file, using ffmpeg libraries.
 35660     // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
 35661     // I modified it afterwards for direct inclusion in the library core.
 35662     CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35663                              const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
 35664       if (!filename)
 35665         throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
 35666                                     pixel_type());
 35667       const unsigned int
 35668         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 35669         nlast_frame = first_frame<last_frame?last_frame:first_frame,
 35670         nstep_frame = step_frame?step_frame:1;
 35671       assign();
 35673 #ifndef cimg_use_ffmpeg
 35674       if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
 35675         throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
 35676                                     "('cimg_use_ffmpeg' must be defined).",
 35677                                     pixel_type(),filename);
 35678       return load_ffmpeg_external(filename);
 35679 #else
 35680       const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
 35681       avcodec_register_all();
 35682       av_register_all();
 35683       static AVFormatContext *format_ctx = 0;
 35684       static AVCodecContext *codec_ctx = 0;
 35685       static AVCodec *codec = 0;
 35686       static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
 35687       static int vstream = 0;
 35689       if (resume) {
 35690         if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
 35691           throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
 35692                                       pixel_type(),filename);
 35693       } else {
 35694         // Open video file, find main video stream and codec.
 35695         if (format_ctx) av_close_input_file(format_ctx);
 35696         if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
 35697           throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
 35698                                 pixel_type(),filename);
 35699         if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
 35700           av_close_input_file(format_ctx); format_ctx = 0;
 35701           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
 35702                      "Trying with external ffmpeg executable.",
 35703                      pixel_type(),filename);
 35704           return load_ffmpeg_external(filename);
 35706 #if cimg_debug>=3
 35707         dump_format(format_ctx,0,0,0);
 35708 #endif
 35710         // Special command : Return informations on main video stream.
 35711         // as a vector 1x4 containing : (nb_frames,width,height,fps).
 35712         if (!first_frame && !last_frame && !step_frame) {
 35713           for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
 35714             if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
 35715           if (vstream==(int)format_ctx->nb_streams) assign();
 35716           else {
 35717             CImgList<doubleT> timestamps;
 35718             int nb_frames;
 35719             AVPacket packet;
 35720             // Count frames and store timestamps.
 35721             for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
 35722               if (packet.stream_index==vstream) {
 35723                 timestamps.insert(CImg<doubleT>::vector((double)packet.pts));
 35724                 ++nb_frames;
 35726             // Get frame with, height and fps.
 35727             const int
 35728               framew = format_ctx->streams[vstream]->codec->width,
 35729               frameh = format_ctx->streams[vstream]->codec->height;
 35730             const float
 35731               num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
 35732               den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
 35733               fps = num/den;
 35734             // Return infos as a list.
 35735             assign(2);
 35736             (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
 35737             (*this)[1] = timestamps.get_append('y');
 35739           av_close_input_file(format_ctx); format_ctx = 0;
 35740           return *this;
 35743         for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
 35744                format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
 35745         if (vstream==(int)format_ctx->nb_streams) {
 35746           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
 35747                      "Trying with external ffmpeg executable.",
 35748                      pixel_type(),filename);
 35749           av_close_input_file(format_ctx); format_ctx = 0;
 35750           return load_ffmpeg_external(filename);
 35752         codec_ctx = format_ctx->streams[vstream]->codec;
 35753         codec = avcodec_find_decoder(codec_ctx->codec_id);
 35754         if (!codec) {
 35755           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
 35756                      "Trying with external ffmpeg executable.",
 35757                      pixel_type(),filename);
 35758           return load_ffmpeg_external(filename);
 35760         if (avcodec_open(codec_ctx,codec)<0) { // Open codec
 35761           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
 35762                      "Trying with external ffmpeg executable.",
 35763                      pixel_type(),filename);
 35764           return load_ffmpeg_external(filename);
 35768       // Read video frames
 35769       const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 35770       uint8_t *const buffer = new uint8_t[numBytes];
 35771       avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 35772       const T foo = (T)0;
 35773       AVPacket packet;
 35774       for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
 35775         if (packet.stream_index==(int)vstream) {
 35776           int decoded = 0;
 35777           avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
 35778           if (decoded) {
 35779             if (frame==next_frame) {
 35780               SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
 35781                                              codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
 35782               sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
 35783               if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
 35784                 CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
 35785                 insert(next_image._get_permute_axes("yzvx",foo));
 35786               } else {
 35787                 CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
 35788                 insert(next_image._get_permute_axes("yzvx",foo));
 35790               next_frame+=nstep_frame;
 35792             ++frame;
 35794           av_free_packet(&packet);
 35795           if (next_frame>nlast_frame) break;
 35798       delete[] buffer;
 35799 #endif
 35800       return *this;
 35803     static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35804                                        const unsigned int step_frame=1, const bool pixel_format=true) {
 35805       return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
 35808     //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
 35809     CImgList<T>& load_ffmpeg_external(const char *const filename) {
 35810       if (!filename)
 35811         throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
 35812                                     pixel_type());
 35813       char command[1024], filetmp[512], filetmp2[512];
 35814       cimg_std::FILE *file = 0;
 35815       do {
 35816         cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 35817         cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 35818         if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
 35819       } while (file);
 35820       cimg_std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
 35821 #if cimg_OS!=2
 35822       cimg_std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
 35823 #else
 35824       cimg_std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
 35825 #endif
 35826       cimg::system(command,0);
 35827       const unsigned int odebug = cimg::exception_mode();
 35828       cimg::exception_mode() = 0;
 35829       assign();
 35830       unsigned int i = 1;
 35831       for (bool stopflag = false; !stopflag; ++i) {
 35832         cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
 35833         CImg<T> img;
 35834         try { img.load_pnm(filetmp2); }
 35835         catch (CImgException&) { stopflag = true; }
 35836         if (img) { insert(img); cimg_std::remove(filetmp2); }
 35838       cimg::exception_mode() = odebug;
 35839       if (is_empty())
 35840         throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
 35841                               "Check the filename and if the 'ffmpeg' tool is installed on your system.",
 35842                               pixel_type(),filename);
 35843       return *this;
 35846     static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
 35847       return CImgList<T>().load_ffmpeg_external(filename);
 35850     //! Load a gzipped list, using external tool 'gunzip'.
 35851     CImgList<T>& load_gzip_external(const char *const filename) {
 35852       if (!filename)
 35853         throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
 35854                               pixel_type());
 35855       char command[1024], filetmp[512], body[512];
 35856       const char
 35857         *ext = cimg::split_filename(filename,body),
 35858         *ext2 = cimg::split_filename(body,0);
 35859       cimg_std::FILE *file = 0;
 35860       do {
 35861         if (!cimg::strcasecmp(ext,"gz")) {
 35862           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 35863                                   cimg::filenamerand(),ext2);
 35864           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 35865                                   cimg::filenamerand());
 35866         } else {
 35867            if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 35868                                   cimg::filenamerand(),ext);
 35869            else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 35870                              cimg::filenamerand());
 35872         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 35873       } while (file);
 35874       cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 35875       cimg::system(command);
 35876       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 35877         cimg::fclose(cimg::fopen(filename,"r"));
 35878         throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
 35879                               pixel_type(),filename);
 35880       } else cimg::fclose(file);
 35881       load(filetmp);
 35882       cimg_std::remove(filetmp);
 35883       return *this;
 35886     static CImgList<T> get_load_gzip_external(const char *const filename) {
 35887       return CImgList<T>().load_gzip_external(filename);
 35890     //! Load a 3D object from a .OFF file.
 35891     template<typename tf, typename tc>
 35892     CImgList<T>& load_off(const char *const filename,
 35893                           CImgList<tf>& primitives, CImgList<tc>& colors,
 35894                           const bool invert_faces=false) {
 35895       return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
 35898     template<typename tf, typename tc>
 35899       static CImgList<T> get_load_off(const char *const filename,
 35900                                       CImgList<tf>& primitives, CImgList<tc>& colors,
 35901                                       const bool invert_faces=false) {
 35902       return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
 35905     //! Load a TIFF file.
 35906     CImgList<T>& load_tiff(const char *const filename,
 35907                            const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35908                            const unsigned int step_frame=1) {
 35909       const unsigned int
 35910         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 35911         nstep_frame = step_frame?step_frame:1;
 35912       unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 35913 #ifndef cimg_use_tiff
 35914       if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
 35915         throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 35916                                     "('cimg_use_tiff' must be defined).",
 35917                                     pixel_type(),filename);
 35918       return assign(CImg<T>::get_load_tiff(filename));
 35919 #else
 35920       TIFF *tif = TIFFOpen(filename,"r");
 35921       if (tif) {
 35922         unsigned int nb_images = 0;
 35923         do ++nb_images; while (TIFFReadDirectory(tif));
 35924         if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 35925           cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 35926                      pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 35927         if (nfirst_frame>=nb_images) return assign();
 35928         if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 35929         assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
 35930         TIFFSetDirectory(tif,0);
 35931 #if cimg_debug>=3
 35932         TIFFSetWarningHandler(0);
 35933         TIFFSetErrorHandler(0);
 35934 #endif
 35935         cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
 35936         TIFFClose(tif);
 35937       } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
 35938                                  pixel_type(),filename);
 35939       return *this;
 35940 #endif
 35943     static CImgList<T> get_load_tiff(const char *const filename,
 35944                                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 35945                                      const unsigned int step_frame=1) {
 35946       return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 35949     //! Save an image list into a file.
 35950     /**
 35951        Depending on the extension of the given filename, a file format is chosen for the output file.
 35952     **/
 35953     const CImgList<T>& save(const char *const filename, const int number=-1) const {
 35954       if (is_empty())
 35955         throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
 35956                                     pixel_type(),filename?filename:"(null)",size,data);
 35957       if (!filename)
 35958         throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
 35959                                     pixel_type(),size,data);
 35960       const char *ext = cimg::split_filename(filename);
 35961       char nfilename[1024];
 35962       const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
 35963 #ifdef cimglist_save_plugin
 35964       cimglist_save_plugin(fn);
 35965 #endif
 35966 #ifdef cimglist_save_plugin1
 35967       cimglist_save_plugin1(fn);
 35968 #endif
 35969 #ifdef cimglist_save_plugin2
 35970       cimglist_save_plugin2(fn);
 35971 #endif
 35972 #ifdef cimglist_save_plugin3
 35973       cimglist_save_plugin3(fn);
 35974 #endif
 35975 #ifdef cimglist_save_plugin4
 35976       cimglist_save_plugin4(fn);
 35977 #endif
 35978 #ifdef cimglist_save_plugin5
 35979       cimglist_save_plugin5(fn);
 35980 #endif
 35981 #ifdef cimglist_save_plugin6
 35982       cimglist_save_plugin6(fn);
 35983 #endif
 35984 #ifdef cimglist_save_plugin7
 35985       cimglist_save_plugin7(fn);
 35986 #endif
 35987 #ifdef cimglist_save_plugin8
 35988       cimglist_save_plugin8(fn);
 35989 #endif
 35990 #ifdef cimg_use_tiff
 35991       if (!cimg::strcasecmp(ext,"tif") ||
 35992           !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
 35993 #endif
 35994       if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 35995       if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
 35996       if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 35997       if (!cimg::strcasecmp(ext,"avi") ||
 35998           !cimg::strcasecmp(ext,"mov") ||
 35999           !cimg::strcasecmp(ext,"asf") ||
 36000           !cimg::strcasecmp(ext,"divx") ||
 36001           !cimg::strcasecmp(ext,"flv") ||
 36002           !cimg::strcasecmp(ext,"mpg") ||
 36003           !cimg::strcasecmp(ext,"m1v") ||
 36004           !cimg::strcasecmp(ext,"m2v") ||
 36005           !cimg::strcasecmp(ext,"m4v") ||
 36006           !cimg::strcasecmp(ext,"mjp") ||
 36007           !cimg::strcasecmp(ext,"mkv") ||
 36008           !cimg::strcasecmp(ext,"mpe") ||
 36009           !cimg::strcasecmp(ext,"movie") ||
 36010           !cimg::strcasecmp(ext,"ogm") ||
 36011           !cimg::strcasecmp(ext,"qt") ||
 36012           !cimg::strcasecmp(ext,"rm") ||
 36013           !cimg::strcasecmp(ext,"vob") ||
 36014           !cimg::strcasecmp(ext,"wmv") ||
 36015           !cimg::strcasecmp(ext,"xvid") ||
 36016           !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
 36017       if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 36018       if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
 36019       return *this;
 36022     //! Save an image sequence, using FFMPEG library.
 36023     // This piece of code has been originally written by David. G. Starkweather.
 36024     const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 36025                                    const unsigned int fps=25) const {
 36026       if (is_empty())
 36027         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
 36028                                     pixel_type(),filename?filename:"(null)",size,data);
 36029       if (!filename)
 36030         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
 36031                                     pixel_type(),size,data);
 36032       if (!fps)
 36033         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
 36034                                     pixel_type(),filename);
 36035       const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
 36036       if (first_frame>=size || nlast_frame>=size)
 36037         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
 36038                                     pixel_type(),filename,first_frame,last_frame,size);
 36039       for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
 36040         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
 36041                                     pixel_type(),filename);
 36043 #ifndef cimg_use_ffmpeg
 36044       return save_ffmpeg_external(filename,first_frame,last_frame);
 36045 #else
 36046       avcodec_register_all();
 36047       av_register_all();
 36048       const int
 36049         frame_dimx = data[first_frame].dimx(),
 36050         frame_dimy = data[first_frame].dimy(),
 36051         frame_dimv = data[first_frame].dimv();
 36052       if (frame_dimv!=1 && frame_dimv!=3)
 36053         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
 36054                                     pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
 36056       PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
 36057       PixelFormat src_pxl_fmt  = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
 36059       int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
 36060       AVOutputFormat *fmt = 0;
 36061       fmt = guess_format(0,filename,0);
 36062       if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
 36063       if (!fmt)
 36064         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
 36065                                     pixel_type(),filename);
 36067       AVFormatContext *oc = 0;
 36068       oc = av_alloc_format_context();
 36069       if (!oc) // Failed to allocate format context.
 36070         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
 36071                               pixel_type(),filename);
 36073       AVCodec *codec = 0;
 36074       AVFrame *picture = 0;
 36075       AVFrame *tmp_pict = 0;
 36076       oc->oformat = fmt;
 36077       cimg_std::sprintf(oc->filename,"%s",filename);
 36079       // Add video stream.
 36080       int stream_index = 0;
 36081       AVStream *video_str = 0;
 36082       if (fmt->video_codec!=CODEC_ID_NONE) {
 36083         video_str = av_new_stream(oc,stream_index);
 36084         if (!video_str) { // Failed to allocate stream.
 36085           av_free(oc);
 36086           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
 36087                                 pixel_type(),filename);
 36089       } else { // No codec identified.
 36090         av_free(oc);
 36091         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
 36092                               pixel_type(),filename);
 36095       AVCodecContext *c = video_str->codec;
 36096       c->codec_id = fmt->video_codec;
 36097       c->codec_type = CODEC_TYPE_VIDEO;
 36098       c->bit_rate = 400000;
 36099       c->width = frame_dimx;
 36100       c->height = frame_dimy;
 36101       c->time_base.num = 1;
 36102       c->time_base.den = fps;
 36103       c->gop_size = 12;
 36104       c->pix_fmt = dest_pxl_fmt;
 36105       if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
 36106       if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
 36108       if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
 36109         av_free(oc);
 36110         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
 36111                               pixel_type(),filename);
 36114       // Open codecs and alloc buffers.
 36115       codec = avcodec_find_encoder(c->codec_id);
 36116       if (!codec) { // Failed to find codec.
 36117         av_free(oc);
 36118         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
 36119                               pixel_type(),filename);
 36121       if (avcodec_open(c,codec)<0) // Failed to open codec.
 36122         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
 36123                               pixel_type(),filename);
 36124       tmp_pict = avcodec_alloc_frame();
 36125       if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
 36126         avcodec_close(video_str->codec);
 36127         av_free(oc);
 36128         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
 36129                               pixel_type(),filename);
 36131       tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
 36132       tmp_pict->type = FF_BUFFER_TYPE_USER;
 36133       int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
 36134       uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
 36135       if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
 36136         av_free(tmp_pict);
 36137         avcodec_close(video_str->codec);
 36138         av_free(oc);
 36139         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
 36140                               pixel_type(),filename);
 36143       // Associate buffer with tmp_pict.
 36144       avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
 36145       picture = avcodec_alloc_frame();
 36146       if (!picture) { // Failed to allocate picture frame.
 36147         av_free(tmp_pict->data[0]);
 36148         av_free(tmp_pict);
 36149         avcodec_close(video_str->codec);
 36150         av_free(oc);
 36151         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
 36152                               pixel_type(),filename);
 36155       int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
 36156       uint8_t *buffer = (uint8_t*)av_malloc(size);
 36157       if (!buffer) { // Failed to allocate picture frame buffer.
 36158         av_free(picture);
 36159         av_free(tmp_pict->data[0]);
 36160         av_free(tmp_pict);
 36161         avcodec_close(video_str->codec);
 36162         av_free(oc);
 36163         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
 36164                               pixel_type(),filename);
 36167       // Associate the buffer with picture.
 36168       avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
 36170       // Open file.
 36171       if (!(fmt->flags&AVFMT_NOFILE)) {
 36172         if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
 36173           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
 36174                                 pixel_type(),filename);
 36177       if (av_write_header(oc)<0)
 36178         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
 36179                               pixel_type(),filename);
 36180       double video_pts;
 36181       SwsContext *img_convert_context = 0;
 36182       img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
 36183                                            c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
 36184       if (!img_convert_context) { // Failed to get swscale context.
 36185         // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
 36186         av_free(picture->data);
 36187         av_free(picture);
 36188         av_free(tmp_pict->data[0]);
 36189         av_free(tmp_pict);
 36190         avcodec_close(video_str->codec);
 36191         av_free(oc);
 36192         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
 36193                               pixel_type(),filename);
 36195       int ret = 0, out_size;
 36196       uint8_t *video_outbuf = 0;
 36197       int video_outbuf_size = 1000000;
 36198       video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
 36199       if (!video_outbuf) {
 36200         // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
 36201         av_free(picture->data);
 36202         av_free(picture);
 36203         av_free(tmp_pict->data[0]);
 36204         av_free(tmp_pict);
 36205         avcodec_close(video_str->codec);
 36206         av_free(oc);
 36207         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
 36208                               pixel_type(),filename);
 36211       // Loop through each desired image in list.
 36212       for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
 36213         CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
 36214         if (src_pxl_fmt == PIX_FMT_RGB24) {
 36215           red = currentIm.get_shared_channel(0);
 36216           green = currentIm.get_shared_channel(1);
 36217           blue = currentIm.get_shared_channel(2);
 36218           cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
 36219             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X]     = red(X,Y);
 36220             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
 36221             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
 36223         } else {
 36224           gray = currentIm.get_shared_channel(0);
 36225           cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
 36228         if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
 36229         else video_pts = 0.0;
 36230         if (!video_str) break;
 36231         if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
 36232         out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
 36233         if (out_size>0) {
 36234           AVPacket pkt;
 36235           av_init_packet(&pkt);
 36236           pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
 36237           if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
 36238           pkt.stream_index = video_str->index;
 36239           pkt.data = video_outbuf;
 36240           pkt.size = out_size;
 36241           ret = av_write_frame(oc,&pkt);
 36242         } else if (out_size<0) break;
 36243         if (ret) break; // Error occured in writing frame.
 36246       // Close codec.
 36247       if (video_str) {
 36248         avcodec_close(video_str->codec);
 36249         av_free(picture->data[0]);
 36250         av_free(picture);
 36251         av_free(tmp_pict->data[0]);
 36252         av_free(tmp_pict);
 36254       if (av_write_trailer(oc)<0)
 36255         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
 36256                               pixel_type(),filename);
 36257       av_freep(&oc->streams[stream_index]->codec);
 36258       av_freep(&oc->streams[stream_index]);
 36259       if (!(fmt->flags&AVFMT_NOFILE)) {
 36260         /*if (url_fclose(oc->pb)<0)
 36261           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
 36262           pixel_type(),filename);
 36263         */
 36265       av_free(oc);
 36266       av_free(video_outbuf);
 36267 #endif
 36268       return *this;
 36271     // Save an image sequence into a YUV file (internal).
 36272     const CImgList<T>& _save_yuv(cimg_std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
 36273       if (is_empty())
 36274         throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
 36275                                     pixel_type(),filename?filename:"(FILE*)",size,data);
 36276       if (!file && !filename)
 36277         throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
 36278                                     pixel_type(),size,data);
 36279       if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
 36280         throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
 36281                                     pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
 36283       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 36284       cimglist_for(*this,l) {
 36285         CImg<ucharT> YCbCr((*this)[l]);
 36286         if (rgb2yuv) YCbCr.RGBtoYCbCr();
 36287         cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
 36288         cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
 36289                      YCbCr.width*YCbCr.height/2,nfile);
 36291       if (!file) cimg::fclose(nfile);
 36292       return *this;
 36295     //! Save an image sequence into a YUV file.
 36296     const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
 36297       return _save_yuv(0,filename,rgb2yuv);
 36300     //! Save an image sequence into a YUV file.
 36301     const CImgList<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
 36302       return _save_yuv(file,0,rgb2yuv);
 36305     //! Save an image list into a .cimg file.
 36306     /**
 36307        A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images.
 36308        \param filename : name of the output file.
 36309        \return A reference to the current CImgList instance is returned.
 36310     **/
 36311     const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename, const bool compression) const {
 36312       if (is_empty())
 36313         throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
 36314                                     pixel_type(),filename?filename:"(FILE*)",size,data);
 36315       if (!file && !filename)
 36316         throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
 36317                                     pixel_type(),size,data);
 36318       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 36319       const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
 36320       if (cimg_std::strstr(ptype,"unsigned")==ptype) cimg_std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
 36321       else cimg_std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
 36322       cimglist_for(*this,l) {
 36323         const CImg<T>& img = data[l];
 36324         cimg_std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
 36325         if (img.data) {
 36326           CImg<T> tmp;
 36327           if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
 36328           const CImg<T>& ref = cimg::endianness()?tmp:img;
 36329           bool compressed = false;
 36330           if (compression) {
 36331 #ifdef cimg_use_zlib
 36332             const unsigned long siz = sizeof(T)*ref.size();
 36333             unsigned long csiz = siz + siz/10 + 16;
 36334             Bytef *const cbuf = new Bytef[csiz];
 36335             if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
 36336               cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
 36337                        pixel_type(),filename?filename:"(FILE*)");
 36338               compressed = false;
 36339             } else {
 36340               cimg_std::fprintf(nfile," #%lu\n",csiz);
 36341               cimg::fwrite(cbuf,csiz,nfile);
 36342               delete[] cbuf;
 36343               compressed = true;
 36345 #else
 36346             cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
 36347                        "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
 36348                        pixel_type(),filename?filename:"(FILE*)");
 36349             compressed = false;
 36350 #endif
 36352           if (!compressed) {
 36353             cimg_std::fputc('\n',nfile);
 36354             cimg::fwrite(ref.data,ref.size(),nfile);
 36356         } else cimg_std::fputc('\n',nfile);
 36358       if (!file) cimg::fclose(nfile);
 36359       return *this;
 36362     //! Save an image list into a CImg file (RAW binary file + simple header)
 36363     const CImgList<T>& save_cimg(cimg_std::FILE *file, const bool compress=false) const {
 36364       return _save_cimg(file,0,compress);
 36367     //! Save an image list into a CImg file (RAW binary file + simple header)
 36368     const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
 36369       return _save_cimg(0,filename,compress);
 36372     // Insert the instance image into into an existing .cimg file, at specified coordinates.
 36373     const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename,
 36374                                  const unsigned int n0,
 36375                                  const unsigned int x0, const unsigned int y0,
 36376                                  const unsigned int z0, const unsigned int v0) const {
 36377 #define _cimg_save_cimg_case(Ts,Tss) \
 36378       if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 36379         for (unsigned int l=0; l<lmax; ++l) { \
 36380           j = 0; while((i=cimg_std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
 36381           W = H = D = V = 0; \
 36382           if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
 36383             throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 36384                                   pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
 36385           if (W*H*D*V>0) { \
 36386             if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
 36387             else { \
 36388               const CImg<T>& img = (*this)[l-n0]; \
 36389               const T *ptrs = img.data; \
 36390               const unsigned int \
 36391                 x1 = x0 + img.width - 1, \
 36392                 y1 = y0 + img.height - 1, \
 36393                 z1 = z0 + img.depth - 1, \
 36394                 v1 = v0 + img.dim - 1, \
 36395                 nx1 = x1>=W?W-1:x1, \
 36396                 ny1 = y1>=H?H-1:y1, \
 36397                 nz1 = z1>=D?D-1:z1, \
 36398                 nv1 = v1>=V?V-1:v1; \
 36399               CImg<Tss> raw(1+nx1-x0); \
 36400               const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
 36401               if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
 36402               for (unsigned int v=1+nv1-v0; v; --v) { \
 36403                 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
 36404                 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
 36405                 for (unsigned int z=1+nz1-z0; z; --z) { \
 36406                   const unsigned int skipyb = y0*W*sizeof(Tss); \
 36407                   if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
 36408                   for (unsigned int y=1+ny1-y0; y; --y) { \
 36409                     const unsigned int skipxb = x0*sizeof(Tss); \
 36410                     if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
 36411                     raw.assign(ptrs, raw.width); \
 36412                     ptrs+=img.width; \
 36413                     if (endian) cimg::invert_endianness(raw.data,raw.width); \
 36414                     cimg::fwrite(raw.data,raw.width,nfile); \
 36415                     const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
 36416                     if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
 36417                   } \
 36418                   const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
 36419                   if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
 36420                 } \
 36421                 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
 36422                 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
 36423               } \
 36424               const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
 36425               if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
 36426             } \
 36427           } \
 36428         } \
 36429         saved = true; \
 36431       if (is_empty())
 36432         throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
 36433                                     pixel_type(),filename?filename:"(FILE*)",size,data);
 36434       if (!file && !filename)
 36435         throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
 36436                                     pixel_type(),size,data);
 36437       typedef unsigned char uchar;
 36438       typedef unsigned short ushort;
 36439       typedef unsigned int uint;
 36440       typedef unsigned long ulong;
 36441       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
 36442       bool saved = false, endian = cimg::endianness();
 36443       char tmp[256], str_pixeltype[256], str_endian[256];
 36444       unsigned int j, err, N, W, H, D, V;
 36445       int i;
 36446       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 36447       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 36448       if (err<2) {
 36449         if (!file) cimg::fclose(nfile);
 36450         throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
 36451                               pixel_type(),filename?filename:"(FILE*)");
 36453       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 36454       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 36455       const unsigned int lmax = cimg::min(N,n0+size);
 36456       _cimg_save_cimg_case("bool",bool);
 36457       _cimg_save_cimg_case("unsigned_char",uchar);
 36458       _cimg_save_cimg_case("uchar",uchar);
 36459       _cimg_save_cimg_case("char",char);
 36460       _cimg_save_cimg_case("unsigned_short",ushort);
 36461       _cimg_save_cimg_case("ushort",ushort);
 36462       _cimg_save_cimg_case("short",short);
 36463       _cimg_save_cimg_case("unsigned_int",uint);
 36464       _cimg_save_cimg_case("uint",uint);
 36465       _cimg_save_cimg_case("int",int);
 36466       _cimg_save_cimg_case("unsigned_long",ulong);
 36467       _cimg_save_cimg_case("ulong",ulong);
 36468       _cimg_save_cimg_case("long",long);
 36469       _cimg_save_cimg_case("float",float);
 36470       _cimg_save_cimg_case("double",double);
 36471       if (!saved) {
 36472         if (!file) cimg::fclose(nfile);
 36473         throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
 36474                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 36476       if (!file) cimg::fclose(nfile);
 36477       return *this;
 36480     //! Insert the instance image into into an existing .cimg file, at specified coordinates.
 36481     const CImgList<T>& save_cimg(const char *const filename,
 36482                                  const unsigned int n0,
 36483                                  const unsigned int x0, const unsigned int y0,
 36484                                  const unsigned int z0, const unsigned int v0) const {
 36485       return _save_cimg(0,filename,n0,x0,y0,z0,v0);
 36488     //! Insert the instance image into into an existing .cimg file, at specified coordinates.
 36489     const CImgList<T>& save_cimg(cimg_std::FILE *const file,
 36490                                  const unsigned int n0,
 36491                                  const unsigned int x0, const unsigned int y0,
 36492                                  const unsigned int z0, const unsigned int v0) const {
 36493       return _save_cimg(file,0,n0,x0,y0,z0,v0);
 36496     // Create an empty .cimg file with specified dimensions (internal)
 36497     static void _save_empty_cimg(cimg_std::FILE *const file, const char *const filename,
 36498                                 const unsigned int nb,
 36499                                 const unsigned int dx, const unsigned int dy,
 36500                                 const unsigned int dz, const unsigned int dv) {
 36501       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 36502       const unsigned int siz = dx*dy*dz*dv*sizeof(T);
 36503       cimg_std::fprintf(nfile,"%u %s\n",nb,pixel_type());
 36504       for (unsigned int i=nb; i; --i) {
 36505         cimg_std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
 36506         for (unsigned int off=siz; off; --off) cimg_std::fputc(0,nfile);
 36508       if (!file) cimg::fclose(nfile);
 36511     //! Create an empty .cimg file with specified dimensions.
 36512     static void save_empty_cimg(const char *const filename,
 36513                                 const unsigned int nb,
 36514                                 const unsigned int dx, const unsigned int dy=1,
 36515                                 const unsigned int dz=1, const unsigned int dv=1) {
 36516       return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
 36519     //! Create an empty .cimg file with specified dimensions.
 36520     static void save_empty_cimg(cimg_std::FILE *const file,
 36521                                 const unsigned int nb,
 36522                                 const unsigned int dx, const unsigned int dy=1,
 36523                                 const unsigned int dz=1, const unsigned int dv=1) {
 36524       return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
 36527     //! Save a file in TIFF format.
 36528 #ifdef cimg_use_tiff
 36529     const CImgList<T>& save_tiff(const char *const filename) const {
 36530       if (is_empty())
 36531         throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
 36532                                     pixel_type(),filename?filename:"(null)",size,data);
 36533       if (!filename)
 36534         throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
 36535                                     pixel_type(),size,data);
 36536       TIFF *tif = TIFFOpen(filename,"w");
 36537       if (tif) {
 36538         for (unsigned int dir=0, l=0; l<size; ++l) {
 36539           const CImg<T>& img = (*this)[l];
 36540           if (img) {
 36541             if (img.depth==1) img._save_tiff(tif,dir++);
 36542             else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
 36545         TIFFClose(tif);
 36546       } else
 36547         throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
 36548                             pixel_type(),filename);
 36549       return *this;
 36551 #endif
 36553     //! Save an image list as a gzipped file, using external tool 'gzip'.
 36554     const CImgList<T>& save_gzip_external(const char *const filename) const {
 36555       if (!filename)
 36556         throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 36557                               pixel_type());
 36558       char command[1024], filetmp[512], body[512];
 36559       const char
 36560         *ext = cimg::split_filename(filename,body),
 36561         *ext2 = cimg::split_filename(body,0);
 36562       cimg_std::FILE *file;
 36563       do {
 36564         if (!cimg::strcasecmp(ext,"gz")) {
 36565           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 36566                                   cimg::filenamerand(),ext2);
 36567           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 36568                             cimg::filenamerand());
 36569         } else {
 36570           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 36571                                  cimg::filenamerand(),ext);
 36572           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 36573                                  cimg::filenamerand());
 36575         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 36576       } while (file);
 36577       save(filetmp);
 36578       cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 36579       cimg::system(command);
 36580       file = cimg_std::fopen(filename,"rb");
 36581       if (!file)
 36582         throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
 36583                               pixel_type(),filename);
 36584       else cimg::fclose(file);
 36585       cimg_std::remove(filetmp);
 36586       return *this;
 36589     //! Save an image list into a OFF file.
 36590     template<typename tf, typename tc>
 36591     const CImgList<T>& save_off(const char *const filename,
 36592                                 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 36593       get_append('x','y').save_off(filename,primitives,colors,invert_faces);
 36594       return *this;
 36597     //! Save an image list into a OFF file.
 36598     template<typename tf, typename tc>
 36599     const CImgList<T>& save_off(cimg_std::FILE *const file,
 36600                                 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 36601       get_append('x','y').save_off(file,primitives,colors,invert_faces);
 36602       return *this;
 36605     //! Save an image sequence using the external tool 'ffmpeg'.
 36606     const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 36607                                             const char *const codec="mpeg2video") const {
 36608       if (is_empty())
 36609         throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
 36610                                     pixel_type(),filename?filename:"(null)",size,data);
 36611       if (!filename)
 36612         throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
 36613                                     pixel_type(),size,data);
 36614       char command[1024], filetmp[512], filetmp2[512];
 36615       cimg_std::FILE *file = 0;
 36616       const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
 36617       if (first_frame>=size || nlast_frame>=size)
 36618         throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
 36619                                     pixel_type(),filename,first_frame,last_frame,size);
 36620       for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
 36621         throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
 36622                                     pixel_type(),filename);
 36623       do {
 36624         cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 36625         cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 36626         if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
 36627       } while (file);
 36628       for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
 36629         cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
 36630         if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
 36631         else data[l].save_pnm(filetmp2);
 36633 #if cimg_OS!=2
 36634       cimg_std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
 36635 #else
 36636       cimg_std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
 36637 #endif
 36638       cimg::system(command);
 36639       file = cimg_std::fopen(filename,"rb");
 36640       if (!file)
 36641         throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
 36642                               pixel_type(),filename);
 36643       else cimg::fclose(file);
 36644       cimglist_for(*this,lll) { cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); cimg_std::remove(filetmp2); }
 36645       return *this;
 36648    };
 36650   /*
 36651    #---------------------------------------------
 36653    # Completion of previously declared functions
 36655    #----------------------------------------------
 36656   */
 36658 namespace cimg {
 36660   //! Display a dialog box, where a user can click standard buttons.
 36661   /**
 36662      Up to 6 buttons can be defined in the dialog window.
 36663      This function returns when a user clicked one of the button or closed the dialog window.
 36664      \param title = Title of the dialog window.
 36665      \param msg = Main message displayed inside the dialog window.
 36666      \param button1_txt = Label of the 1st button.
 36667      \param button2_txt = Label of the 2nd button.
 36668      \param button3_txt = Label of the 3rd button.
 36669      \param button4_txt = Label of the 4th button.
 36670      \param button5_txt = Label of the 5th button.
 36671      \param button6_txt = Label of the 6th button.
 36672      \param logo = Logo image displayed at the left of the main message. This parameter is optional.
 36673      \param centering = Tell to center the dialog window on the screen.
 36674      \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user.
 36675      \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in
 36676      the dialog box. At least one button is necessary.
 36677   **/
 36679   template<typename t>
 36680   inline int dialog(const char *title, const char *msg,
 36681                     const char *button1_txt, const char *button2_txt,
 36682                     const char *button3_txt, const char *button4_txt,
 36683                     const char *button5_txt, const char *button6_txt,
 36684                     const CImg<t>& logo, const bool centering = false) {
 36685 #if cimg_display!=0
 36686     const unsigned char
 36687       black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
 36689       // Create buttons and canvas graphics
 36690       CImgList<unsigned char> buttons, cbuttons, sbuttons;
 36691       if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13));
 36692       if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13));
 36693       if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13));
 36694       if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13));
 36695       if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13));
 36696       if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13));
 36697       }}}}}}
 36698       if (!buttons.size)
 36699         throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
 36701       unsigned int bw = 0, bh = 0;
 36702       cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
 36703       bw+=8; bh+=8;
 36704       if (bw<64) bw=64;
 36705       if (bw>128) bw=128;
 36706       if (bh<24) bh=24;
 36707       if (bh>48) bh=48;
 36709       CImg<unsigned char> button(bw,bh,1,3);
 36710       button.draw_rectangle(0,0,bw-1,bh-1,gray);
 36711       button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
 36712       button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
 36713       button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
 36714       CImg<unsigned char> sbutton(bw,bh,1,3);
 36715       sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
 36716       sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
 36717       sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
 36718       sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
 36719       sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
 36720       sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
 36721       sbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
 36722       sbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
 36723       CImg<unsigned char> cbutton(bw,bh,1,3);
 36724       cbutton.draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray);
 36725       cbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
 36726       cbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
 36728       cimglist_for(buttons,ll) {
 36729         cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]));
 36730         sbuttons.insert(CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]));
 36731         buttons[ll] = CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]);
 36734       CImg<unsigned char> canvas;
 36735       if (msg) canvas = CImg<unsigned char>().draw_text(0,0,msg,black,gray,1,13);
 36736       const unsigned int
 36737         bwall = (buttons.size-1)*(12+bw) + bw,
 36738         w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
 36739         h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
 36740         lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
 36741         ly = (h-12-bh-logo.height)/2,
 36742         tx = lx+logo.width+12,
 36743         ty = (h-12-bh-canvas.height)/2,
 36744         bx = (w-bwall)/2,
 36745         by = h-12-bh;
 36747       if (canvas.data)
 36748         canvas = CImg<unsigned char>(w,h,1,3).
 36749           draw_rectangle(0,0,w-1,h-1,gray).
 36750           draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
 36751           draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
 36752           draw_image(tx,ty,canvas);
 36753       else
 36754         canvas = CImg<unsigned char>(w,h,1,3).
 36755           draw_rectangle(0,0,w-1,h-1,gray).
 36756           draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
 36757           draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
 36758       if (logo.data) canvas.draw_image(lx,ly,logo);
 36760       unsigned int xbuttons[6];
 36761       cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
 36763       // Open window and enter events loop
 36764       CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
 36765       if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
 36766                                (CImgDisplay::screen_dimy()-disp.dimy())/2);
 36767       bool stopflag = false, refresh = false;
 36768       int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
 36769       while (!disp.is_closed && !stopflag) {
 36770         if (refresh) {
 36771           if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
 36772           else {
 36773             if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
 36774             else canvas.display(disp);
 36776           refresh = false;
 36778         disp.wait(15);
 36779         if (disp.is_resized) disp.resize(disp);
 36781         if (disp.button&1)  {
 36782           oclicked = clicked;
 36783           clicked = -1;
 36784           cimglist_for(buttons,l)
 36785             if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
 36786                 disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
 36787               clicked = selected = l;
 36788               refresh = true;
 36790           if (clicked!=oclicked) refresh = true;
 36791         } else if (clicked>=0) stopflag = true;
 36793         if (disp.key) {
 36794           oselected = selected;
 36795           switch (disp.key) {
 36796           case cimg::keyESC : selected=-1; stopflag=true; break;
 36797           case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
 36798           case cimg::keyTAB :
 36799           case cimg::keyARROWRIGHT :
 36800           case cimg::keyARROWDOWN : selected = (selected+1)%buttons.size; break;
 36801           case cimg::keyARROWLEFT :
 36802           case cimg::keyARROWUP : selected = (selected+buttons.size-1)%buttons.size; break;
 36804           disp.key = 0;
 36805           if (selected!=oselected) refresh = true;
 36808       if (!disp) selected = -1;
 36809       return selected;
 36810 #else
 36811       cimg_std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
 36812       return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
 36813 #endif
 36816   inline int dialog(const char *title, const char *msg,
 36817                     const char *button1_txt, const char *button2_txt, const char *button3_txt,
 36818                     const char *button4_txt, const char *button5_txt, const char *button6_txt,
 36819                     const bool centering) {
 36820     return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
 36821                   CImg<unsigned char>::logo40x38(),centering);
 36824   // End of cimg:: namespace
 36827   // End of cimg_library:: namespace
 36830 #ifdef _cimg_redefine_min
 36831 #define min(a,b) (((a)<(b))?(a):(b))
 36832 #endif
 36833 #ifdef _cimg_redefine_max
 36834 #define max(a,b) (((a)>(b))?(a):(b))
 36835 #endif
 36837 #endif
 36838 // Local Variables:
 36839 // mode: c++
 36840 // End: