PTdecode/CImg-1.3.0/CImg.h

changeset 5
1204ebf9340d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/PTdecode/CImg-1.3.0/CImg.h	Mon Aug 03 14:09:20 2009 +0100
     1.3 @@ -0,0 +1,36840 @@
     1.4 +/*
     1.5 + #
     1.6 + #  File            : CImg.h
     1.7 + #                    ( C++ header file )
     1.8 + #
     1.9 + #  Description     : The C++ Template Image Processing Library.
    1.10 + #                    This file is the main part of the CImg Library project.
    1.11 + #                    ( http://cimg.sourceforge.net )
    1.12 + #
    1.13 + #  Project manager : David Tschumperle.
    1.14 + #                    ( http://www.greyc.ensicaen.fr/~dtschump/ )
    1.15 + #
    1.16 + #                    The complete contributor list can be seen in the 'README.txt' file.
    1.17 + #
    1.18 + #  Licenses        : This file is "dual-licensed", you have to choose one
    1.19 + #                    of the two licenses below to apply on this file.
    1.20 + #
    1.21 + #                    CeCILL-C
    1.22 + #                    The CeCILL-C license is close to the GNU LGPL.
    1.23 + #                    ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
    1.24 + #
    1.25 + #                or  CeCILL v2.0
    1.26 + #                    The CeCILL license is compatible with the GNU GPL.
    1.27 + #                    ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    1.28 + #
    1.29 + #  This software is governed either by the CeCILL or the CeCILL-C license
    1.30 + #  under French law and abiding by the rules of distribution of free software.
    1.31 + #  You can  use, modify and or redistribute the software under the terms of
    1.32 + #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
    1.33 + #  at the following URL : "http://www.cecill.info".
    1.34 + #
    1.35 + #  As a counterpart to the access to the source code and  rights to copy,
    1.36 + #  modify and redistribute granted by the license, users are provided only
    1.37 + #  with a limited warranty  and the software's author,  the holder of the
    1.38 + #  economic rights,  and the successive licensors  have only  limited
    1.39 + #  liability.
    1.40 + #
    1.41 + #  In this respect, the user's attention is drawn to the risks associated
    1.42 + #  with loading,  using,  modifying and/or developing or reproducing the
    1.43 + #  software by the user in light of its specific status of free software,
    1.44 + #  that may mean  that it is complicated to manipulate,  and  that  also
    1.45 + #  therefore means  that it is reserved for developers  and  experienced
    1.46 + #  professionals having in-depth computer knowledge. Users are therefore
    1.47 + #  encouraged to load and test the software's suitability as regards their
    1.48 + #  requirements in conditions enabling the security of their systems and/or
    1.49 + #  data to be ensured and,  more generally, to use and operate it in the
    1.50 + #  same conditions as regards security.
    1.51 + #
    1.52 + #  The fact that you are presently reading this means that you have had
    1.53 + #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
    1.54 + #
    1.55 +*/
    1.56 +
    1.57 +// Define version number of the current file.
    1.58 +//
    1.59 +#ifndef cimg_version
    1.60 +#define cimg_version 130
    1.61 +
    1.62 +/*-----------------------------------------------------------
    1.63 + #
    1.64 + # Test/auto-set CImg configuration variables
    1.65 + # and include required headers.
    1.66 + #
    1.67 + # If you find that default configuration variables are
    1.68 + # not adapted, you can override their values before including
    1.69 + # the header file "CImg.h" (using the #define directive).
    1.70 + #
    1.71 + ------------------------------------------------------------*/
    1.72 +
    1.73 +// Include required standard C++ headers.
    1.74 +//
    1.75 +#include <cstdio>
    1.76 +#include <cstdlib>
    1.77 +#include <cstdarg>
    1.78 +#include <cstring>
    1.79 +#include <cmath>
    1.80 +#include <ctime>
    1.81 +
    1.82 +// Operating system configuration.
    1.83 +//
    1.84 +// Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
    1.85 +//                       1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
    1.86 +//                       2 for Microsoft Windows.
    1.87 +//
    1.88 +#ifndef cimg_OS
    1.89 +#if defined(unix)        || defined(__unix)      || defined(__unix__) \
    1.90 + || defined(linux)       || defined(__linux)     || defined(__linux__) \
    1.91 + || defined(sun)         || defined(__sun) \
    1.92 + || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
    1.93 + || defined(__FreeBSD__) || defined __DragonFly__ \
    1.94 + || defined(sgi)         || defined(__sgi) \
    1.95 + || defined(__MACOSX__)  || defined(__APPLE__) \
    1.96 + || defined(__CYGWIN__)
    1.97 +#define cimg_OS 1
    1.98 +#elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
    1.99 +   || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
   1.100 +#define cimg_OS 2
   1.101 +#else
   1.102 +#define cimg_OS 0
   1.103 +#endif
   1.104 +#elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
   1.105 +#error CImg Library : Configuration variable 'cimg_OS' is badly defined.
   1.106 +#error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
   1.107 +#endif
   1.108 +
   1.109 +// Compiler configuration.
   1.110 +//
   1.111 +// Try to detect Microsoft VC++ compilers.
   1.112 +// (lot of workarounds are needed afterwards to
   1.113 +// make CImg working, particularly with VC++ 6.0).
   1.114 +//
   1.115 +#ifdef _MSC_VER
   1.116 +#pragma warning(push)
   1.117 +#pragma warning(disable:4311)
   1.118 +#pragma warning(disable:4312)
   1.119 +#pragma warning(disable:4800)
   1.120 +#pragma warning(disable:4804)
   1.121 +#pragma warning(disable:4996)
   1.122 +#define _CRT_SECURE_NO_DEPRECATE 1
   1.123 +#define _CRT_NONSTDC_NO_DEPRECATE 1
   1.124 +#if _MSC_VER<1300
   1.125 +#define cimg_use_visualcpp6
   1.126 +#define cimg_std
   1.127 +#define _WIN32_WINNT 0x0500
   1.128 +#endif
   1.129 +#endif
   1.130 +
   1.131 +// Include OS-specific headers.
   1.132 +//
   1.133 +#if cimg_OS==1
   1.134 +#include <sys/time.h>
   1.135 +#include <unistd.h>
   1.136 +#elif cimg_OS==2
   1.137 +#include <windows.h>
   1.138 +#ifndef _WIN32_IE
   1.139 +#define _WIN32_IE 0x0400
   1.140 +#endif
   1.141 +#include <shlobj.h>
   1.142 +#endif
   1.143 +
   1.144 +// Define defaut pipe for output messages
   1.145 +//
   1.146 +// Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
   1.147 +//                           stderr to print CImg messages on the standart error output (default behavior).
   1.148 +//
   1.149 +#ifndef cimg_std
   1.150 +#define cimg_std std
   1.151 +#endif
   1.152 +#ifndef cimg_stdout
   1.153 +#define cimg_stdout stderr
   1.154 +#endif
   1.155 +
   1.156 +// Output messages configuration.
   1.157 +//
   1.158 +// Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
   1.159 +//                          1 to display debug messages on the console.
   1.160 +//                          2 to display debug messages with dialog windows (default behavior).
   1.161 +//                          3 to do as 1 + add extra warnings (may slow down the code !).
   1.162 +//                          4 to do as 2 + add extra warnings (may slow down the code !).
   1.163 +//
   1.164 +// Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
   1.165 +//
   1.166 +// Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
   1.167 +//
   1.168 +#ifndef cimg_debug
   1.169 +#define cimg_debug 2
   1.170 +#elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
   1.171 +#error CImg Library : Configuration variable 'cimg_debug' is badly defined.
   1.172 +#error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
   1.173 +#endif
   1.174 +
   1.175 +// Display framework configuration.
   1.176 +//
   1.177 +// Define 'cimg_display' to : 0 to disable display capabilities.
   1.178 +//                            1 to use X-Window framework (X11).
   1.179 +//                            2 to use Microsoft GDI32 framework.
   1.180 +//                            3 to use Apple Carbon framework.
   1.181 +//
   1.182 +#ifndef cimg_display
   1.183 +#if cimg_OS==0
   1.184 +#define cimg_display 0
   1.185 +#elif cimg_OS==1
   1.186 +#if defined(__MACOSX__) || defined(__APPLE__)
   1.187 +#define cimg_display 1
   1.188 +#else
   1.189 +#define cimg_display 1
   1.190 +#endif
   1.191 +#elif cimg_OS==2
   1.192 +#define cimg_display 2
   1.193 +#endif
   1.194 +#elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
   1.195 +#error CImg Library : Configuration variable 'cimg_display' is badly defined.
   1.196 +#error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
   1.197 +#endif
   1.198 +
   1.199 +// Include display-specific headers.
   1.200 +//
   1.201 +#if cimg_display==1
   1.202 +#include <X11/Xlib.h>
   1.203 +#include <X11/Xutil.h>
   1.204 +#include <X11/keysym.h>
   1.205 +#include <pthread.h>
   1.206 +#ifdef cimg_use_xshm
   1.207 +#include <sys/ipc.h>
   1.208 +#include <sys/shm.h>
   1.209 +#include <X11/extensions/XShm.h>
   1.210 +#endif
   1.211 +#ifdef cimg_use_xrandr
   1.212 +#include <X11/extensions/Xrandr.h>
   1.213 +#endif
   1.214 +#elif cimg_display==3
   1.215 +#include <Carbon/Carbon.h>
   1.216 +#include <pthread.h>
   1.217 +#endif
   1.218 +
   1.219 +// OpenMP configuration.
   1.220 +// (http://www.openmp.org)
   1.221 +//
   1.222 +// Define 'cimg_use_openmp' to enable OpenMP support.
   1.223 +//
   1.224 +// OpenMP directives can be used in few CImg functions to get
   1.225 +// advantages of multi-core CPUs. Using OpenMP is not mandatory.
   1.226 +//
   1.227 +#ifdef cimg_use_openmp
   1.228 +#include "omp.h"
   1.229 +#endif
   1.230 +
   1.231 +// LibPNG configuration.
   1.232 +// (http://www.libpng.org)
   1.233 +//
   1.234 +// Define 'cimg_use_png' to enable LibPNG support.
   1.235 +//
   1.236 +// LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
   1.237 +// to get a builtin support of PNG files. Using LibPNG is not mandatory.
   1.238 +//
   1.239 +#ifdef cimg_use_png
   1.240 +extern "C" {
   1.241 +#include "png.h"
   1.242 +}
   1.243 +#endif
   1.244 +
   1.245 +// LibJPEG configuration.
   1.246 +// (http://en.wikipedia.org/wiki/Libjpeg)
   1.247 +//
   1.248 +// Define 'cimg_use_jpeg' to enable LibJPEG support.
   1.249 +//
   1.250 +// LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
   1.251 +// to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
   1.252 +//
   1.253 +#ifdef cimg_use_jpeg
   1.254 +extern "C" {
   1.255 +#include "jpeglib.h"
   1.256 +}
   1.257 +#endif
   1.258 +
   1.259 +// LibTIFF configuration.
   1.260 +// (http://www.libtiff.org)
   1.261 +//
   1.262 +// Define 'cimg_use_tiff' to enable LibTIFF support.
   1.263 +//
   1.264 +// LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
   1.265 +// to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
   1.266 +//
   1.267 +#ifdef cimg_use_tiff
   1.268 +extern "C" {
   1.269 +#include "tiffio.h"
   1.270 +}
   1.271 +#endif
   1.272 +
   1.273 +// FFMPEG Avcodec and Avformat libraries configuration.
   1.274 +// (http://www.ffmpeg.org)
   1.275 +//
   1.276 +// Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
   1.277 +//
   1.278 +// Avcodec and Avformat libraries can be used in functions
   1.279 +// 'CImg[List]<T>::load_ffmpeg()' to get a builtin
   1.280 +// support of various image sequences files.
   1.281 +// Using FFMPEG libraries is not mandatory.
   1.282 +//
   1.283 +#ifdef cimg_use_ffmpeg
   1.284 +extern "C" {
   1.285 +#include "avformat.h"
   1.286 +#include "avcodec.h"
   1.287 +#include "swscale.h"
   1.288 +}
   1.289 +#endif
   1.290 +
   1.291 +// Zlib configuration
   1.292 +// (http://www.zlib.net)
   1.293 +//
   1.294 +// Define 'cimg_use_zlib' to enable Zlib support.
   1.295 +//
   1.296 +// Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
   1.297 +// to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
   1.298 +//
   1.299 +#ifdef cimg_use_zlib
   1.300 +extern "C" {
   1.301 +#include "zlib.h"
   1.302 +}
   1.303 +#endif
   1.304 +
   1.305 +// Magick++ configuration.
   1.306 +// (http://www.imagemagick.org/Magick++)
   1.307 +//
   1.308 +// Define 'cimg_use_magick' to enable Magick++ support.
   1.309 +//
   1.310 +// Magick++ library can be used in functions 'CImg<T>::{load,save}()'
   1.311 +// to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
   1.312 +// Using Magick++ is not mandatory.
   1.313 +//
   1.314 +#ifdef cimg_use_magick
   1.315 +#include "Magick++.h"
   1.316 +#endif
   1.317 +
   1.318 +// FFTW3 configuration.
   1.319 +// (http://www.fftw.org)
   1.320 +//
   1.321 +// Define 'cimg_use_fftw3' to enable libFFTW3 support.
   1.322 +//
   1.323 +// FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
   1.324 +// efficiently compile the Fast Fourier Transform of image data.
   1.325 +//
   1.326 +#ifdef cimg_use_fftw3
   1.327 +extern "C" {
   1.328 +#include "fftw3.h"
   1.329 +}
   1.330 +#endif
   1.331 +
   1.332 +// Board configuration.
   1.333 +// (http://libboard.sourceforge.net/)
   1.334 +//
   1.335 +// Define 'cimg_use_board' to enable Board support.
   1.336 +//
   1.337 +// Board library can be used in functions 'CImg<T>::draw_object3d()'
   1.338 +// to draw objects 3D in vector-graphics canvas that can be saved
   1.339 +// as .PS or .SVG files afterwards.
   1.340 +//
   1.341 +#ifdef cimg_use_board
   1.342 +#include "Board.h"
   1.343 +#endif
   1.344 +
   1.345 +// Lapack configuration.
   1.346 +// (http://www.netlib.org/lapack)
   1.347 +//
   1.348 +// Define 'cimg_use_lapack' to enable LAPACK support.
   1.349 +//
   1.350 +// Lapack can be used in various CImg functions dealing with
   1.351 +// matrix computation and algorithms (eigenvalues, inverse, ...).
   1.352 +// Using Lapack is not mandatory.
   1.353 +//
   1.354 +#ifdef cimg_use_lapack
   1.355 +extern "C" {
   1.356 +  extern void sgetrf_(int*, int*, float*, int*, int*, int*);
   1.357 +  extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
   1.358 +  extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
   1.359 +  extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
   1.360 +  extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
   1.361 +  extern void dgetrf_(int*, int*, double*, int*, int*, int*);
   1.362 +  extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
   1.363 +  extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
   1.364 +  extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
   1.365 +  extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
   1.366 +}
   1.367 +#endif
   1.368 +
   1.369 +// Check if min/max macros are defined.
   1.370 +//
   1.371 +// CImg does not compile if macros 'min' or 'max' are defined,
   1.372 +// because min() and max() functions are also defined in the cimg:: namespace.
   1.373 +// so it '#undef' these macros if necessary, and restore them to reasonable
   1.374 +// values at the end of the file.
   1.375 +//
   1.376 +#ifdef min
   1.377 +#undef min
   1.378 +#define _cimg_redefine_min
   1.379 +#endif
   1.380 +#ifdef max
   1.381 +#undef max
   1.382 +#define _cimg_redefine_max
   1.383 +#endif
   1.384 +
   1.385 +// Set the current working directory for native MacOSX bundled applications.
   1.386 +//
   1.387 +// By default, MacOS bundled applications set the cwd at the root directory '/',
   1.388 +// the code below allows to set it to the current exec directory instead when
   1.389 +// a CImg-based program is executed.
   1.390 +//
   1.391 +#if cimg_OS==1 && cimg_display==3
   1.392 +static struct _cimg_macosx_setcwd {
   1.393 +  _cimg_macosx_setcwd() {
   1.394 +    FSRef location;
   1.395 +    ProcessSerialNumber psn;
   1.396 +    char filePath[512];
   1.397 +    if (GetCurrentProcess(&psn)!=noErr) return;
   1.398 +    if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
   1.399 +    FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
   1.400 +    int p = cimg_std::strlen(filePath);
   1.401 +    while (filePath[p] != '/') --p;
   1.402 +    filePath[p] = 0;
   1.403 +    chdir(filePath);
   1.404 +  }
   1.405 +} cimg_macosx_setcwd;
   1.406 +#endif
   1.407 +
   1.408 +/*------------------------------------------------------------------------------
   1.409 +  #
   1.410 +  # Define user-friendly macros.
   1.411 +  #
   1.412 +  # User macros are prefixed by 'cimg_' and can be used in your own code.
   1.413 +  # They are particularly useful for option parsing, and image loops creation.
   1.414 +  #
   1.415 +  ------------------------------------------------------------------------------*/
   1.416 +
   1.417 +// Define the program usage, and retrieve command line arguments.
   1.418 +//
   1.419 +#define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
   1.420 +#define cimg_help(str)    cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
   1.421 +#define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
   1.422 +#define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
   1.423 +#define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
   1.424 +#define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
   1.425 +#define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
   1.426 +#define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
   1.427 +#define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
   1.428 +#define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
   1.429 +#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)
   1.430 +#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)
   1.431 +#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)
   1.432 +
   1.433 +// Define and manipulate local neighborhoods.
   1.434 +//
   1.435 +#define CImg_2x2(I,T) T I[4]; \
   1.436 +                      T& I##cc = I[0]; T& I##nc = I[1]; \
   1.437 +                      T& I##cn = I[2]; T& I##nn = I[3]; \
   1.438 +                      I##cc = I##nc = \
   1.439 +                      I##cn = I##nn = 0
   1.440 +
   1.441 +#define CImg_3x3(I,T) T I[9]; \
   1.442 +                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
   1.443 +                      T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
   1.444 +                      T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
   1.445 +                      I##pp = I##cp = I##np = \
   1.446 +                      I##pc = I##cc = I##nc = \
   1.447 +                      I##pn = I##cn = I##nn = 0
   1.448 +
   1.449 +#define CImg_4x4(I,T) T I[16]; \
   1.450 +                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
   1.451 +                      T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
   1.452 +                      T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
   1.453 +                      T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
   1.454 +                      I##pp = I##cp = I##np = I##ap = \
   1.455 +                      I##pc = I##cc = I##nc = I##ac = \
   1.456 +                      I##pn = I##cn = I##nn = I##an = \
   1.457 +                      I##pa = I##ca = I##na = I##aa = 0
   1.458 +
   1.459 +#define CImg_5x5(I,T) T I[25]; \
   1.460 +                      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]; \
   1.461 +                      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]; \
   1.462 +                      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]; \
   1.463 +                      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]; \
   1.464 +                      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]; \
   1.465 +                      I##bb = I##pb = I##cb = I##nb = I##ab = \
   1.466 +                      I##bp = I##pp = I##cp = I##np = I##ap = \
   1.467 +                      I##bc = I##pc = I##cc = I##nc = I##ac = \
   1.468 +                      I##bn = I##pn = I##cn = I##nn = I##an = \
   1.469 +                      I##ba = I##pa = I##ca = I##na = I##aa = 0
   1.470 +
   1.471 +#define CImg_2x2x2(I,T) T I[8]; \
   1.472 +                      T& I##ccc = I[0]; T& I##ncc = I[1]; \
   1.473 +                      T& I##cnc = I[2]; T& I##nnc = I[3]; \
   1.474 +                      T& I##ccn = I[4]; T& I##ncn = I[5]; \
   1.475 +                      T& I##cnn = I[6]; T& I##nnn = I[7]; \
   1.476 +                      I##ccc = I##ncc = \
   1.477 +                      I##cnc = I##nnc = \
   1.478 +                      I##ccn = I##ncn = \
   1.479 +                      I##cnn = I##nnn = 0
   1.480 +
   1.481 +#define CImg_3x3x3(I,T) T I[27]; \
   1.482 +                      T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
   1.483 +                      T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
   1.484 +                      T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
   1.485 +                      T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
   1.486 +                      T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
   1.487 +                      T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
   1.488 +                      T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
   1.489 +                      T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
   1.490 +                      T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
   1.491 +                      I##ppp = I##cpp = I##npp = \
   1.492 +                      I##pcp = I##ccp = I##ncp = \
   1.493 +                      I##pnp = I##cnp = I##nnp = \
   1.494 +                      I##ppc = I##cpc = I##npc = \
   1.495 +                      I##pcc = I##ccc = I##ncc = \
   1.496 +                      I##pnc = I##cnc = I##nnc = \
   1.497 +                      I##ppn = I##cpn = I##npn = \
   1.498 +                      I##pcn = I##ccn = I##ncn = \
   1.499 +                      I##pnn = I##cnn = I##nnn = 0
   1.500 +
   1.501 +#define cimg_get2x2(img,x,y,z,v,I) \
   1.502 +  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)
   1.503 +
   1.504 +#define cimg_get3x3(img,x,y,z,v,I) \
   1.505 +  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), \
   1.506 +  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), \
   1.507 +  I[8] = (img)(_n1##x,_n1##y,z,v)
   1.508 +
   1.509 +#define cimg_get4x4(img,x,y,z,v,I) \
   1.510 +  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), \
   1.511 +  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), \
   1.512 +  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), \
   1.513 +  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)
   1.514 +
   1.515 +#define cimg_get5x5(img,x,y,z,v,I) \
   1.516 +  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), \
   1.517 +  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), \
   1.518 +  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), \
   1.519 +  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), \
   1.520 +  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), \
   1.521 +  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), \
   1.522 +  I[24] = (img)(_n2##x,_n2##y,z,v)
   1.523 +
   1.524 +#define cimg_get6x6(img,x,y,z,v,I) \
   1.525 + 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), \
   1.526 + 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), \
   1.527 + 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), \
   1.528 + 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), \
   1.529 + 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), \
   1.530 + 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), \
   1.531 + 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), \
   1.532 + 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), \
   1.533 + 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)
   1.534 +
   1.535 +#define cimg_get7x7(img,x,y,z,v,I) \
   1.536 + 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), \
   1.537 + 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), \
   1.538 + 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), \
   1.539 + 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), \
   1.540 + 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), \
   1.541 + 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), \
   1.542 + 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), \
   1.543 + 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), \
   1.544 + 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), \
   1.545 + 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), \
   1.546 + 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), \
   1.547 + 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), \
   1.548 + I[48] = (img)(_n3##x,_n3##y,z,v)
   1.549 +
   1.550 +#define cimg_get8x8(img,x,y,z,v,I) \
   1.551 + 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), \
   1.552 + 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), \
   1.553 + 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), \
   1.554 + 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), \
   1.555 + 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), \
   1.556 + 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), \
   1.557 + 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), \
   1.558 + 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), \
   1.559 + 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), \
   1.560 + 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), \
   1.561 + 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), \
   1.562 + 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), \
   1.563 + 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), \
   1.564 + 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), \
   1.565 + 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), \
   1.566 + 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);
   1.567 +
   1.568 +#define cimg_get9x9(img,x,y,z,v,I) \
   1.569 + 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), \
   1.570 + 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), \
   1.571 + 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), \
   1.572 + 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), \
   1.573 + 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), \
   1.574 + 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), \
   1.575 + 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), \
   1.576 + 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), \
   1.577 + 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), \
   1.578 + 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), \
   1.579 + 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), \
   1.580 + 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), \
   1.581 + 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), \
   1.582 + 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), \
   1.583 + 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), \
   1.584 + 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), \
   1.585 + 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), \
   1.586 + 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), \
   1.587 + 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), \
   1.588 + 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), \
   1.589 + I[80] = (img)(_n4##x,_n4##y,z,v)
   1.590 +
   1.591 +#define cimg_get2x2x2(img,x,y,z,v,I) \
   1.592 +  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), \
   1.593 +  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)
   1.594 +
   1.595 +#define cimg_get3x3x3(img,x,y,z,v,I) \
   1.596 +  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), \
   1.597 +  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), \
   1.598 +  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), \
   1.599 +  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), \
   1.600 +  I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
   1.601 +  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), \
   1.602 +  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), \
   1.603 +  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), \
   1.604 +  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)
   1.605 +
   1.606 +// Define various image loops.
   1.607 +//
   1.608 +// These macros generally avoid the use of iterators, but you are not forced to used them !
   1.609 +//
   1.610 +#define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
   1.611 +#define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
   1.612 +#define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
   1.613 +#define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
   1.614 +
   1.615 +#define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
   1.616 +#define cimg_forX(img,x) cimg_for1((img).width,x)
   1.617 +#define cimg_forY(img,y) cimg_for1((img).height,y)
   1.618 +#define cimg_forZ(img,z) cimg_for1((img).depth,z)
   1.619 +#define cimg_forV(img,v) cimg_for1((img).dim,v)
   1.620 +#define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
   1.621 +#define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
   1.622 +#define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
   1.623 +#define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
   1.624 +#define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
   1.625 +#define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
   1.626 +#define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
   1.627 +#define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
   1.628 +#define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
   1.629 +#define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
   1.630 +#define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
   1.631 +
   1.632 +#define cimg_for_in1(bound,i0,i1,i) \
   1.633 + for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
   1.634 +#define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
   1.635 +#define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
   1.636 +#define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
   1.637 +#define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
   1.638 +#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)
   1.639 +#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)
   1.640 +#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)
   1.641 +#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)
   1.642 +#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)
   1.643 +#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)
   1.644 +#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)
   1.645 +#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)
   1.646 +#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)
   1.647 +#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)
   1.648 +#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)
   1.649 +#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
   1.650 +#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
   1.651 +#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
   1.652 +#define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
   1.653 +#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
   1.654 +#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)
   1.655 +#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)
   1.656 +
   1.657 +#define cimg_for_out1(boundi,i0,i1,i) \
   1.658 + for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
   1.659 +#define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
   1.660 + for (int j = 0; j<(int)(boundj); ++j) \
   1.661 + for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
   1.662 +  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
   1.663 +#define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
   1.664 + for (int k = 0; k<(int)(boundk); ++k) \
   1.665 + for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
   1.666 + for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
   1.667 +  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
   1.668 +#define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
   1.669 + for (int l = 0; l<(int)(boundl); ++l) \
   1.670 + for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
   1.671 + for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
   1.672 + 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); \
   1.673 +  ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
   1.674 +#define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
   1.675 +#define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
   1.676 +#define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
   1.677 +#define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
   1.678 +#define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
   1.679 +#define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
   1.680 +#define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
   1.681 +#define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
   1.682 +#define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
   1.683 +#define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
   1.684 +#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)
   1.685 +#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)
   1.686 +#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)
   1.687 +#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)
   1.688 +#define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
   1.689 + cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
   1.690 +#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
   1.691 +#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
   1.692 +#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
   1.693 +#define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
   1.694 +#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
   1.695 +#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)
   1.696 +#define cimg_for_borderXYZV(img,x,y,z,v,n) \
   1.697 + 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)
   1.698 +
   1.699 +#define cimg_for_spiralXY(img,x,y) \
   1.700 + for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
   1.701 +      --_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)
   1.702 +
   1.703 +#define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
   1.704 + for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
   1.705 +      _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
   1.706 +      _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
   1.707 +      _counter = _dx, \
   1.708 +      _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
   1.709 +      _counter>=0; \
   1.710 +      --_counter, x+=_steep? \
   1.711 +      (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
   1.712 +      (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
   1.713 +
   1.714 +#define cimg_for2(bound,i) \
   1.715 + for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
   1.716 +      _n1##i<(int)(bound) || i==--_n1##i; \
   1.717 +      ++i, ++_n1##i)
   1.718 +#define cimg_for2X(img,x) cimg_for2((img).width,x)
   1.719 +#define cimg_for2Y(img,y) cimg_for2((img).height,y)
   1.720 +#define cimg_for2Z(img,z) cimg_for2((img).depth,z)
   1.721 +#define cimg_for2V(img,v) cimg_for2((img).dim,v)
   1.722 +#define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
   1.723 +#define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
   1.724 +#define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
   1.725 +#define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
   1.726 +#define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
   1.727 +#define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
   1.728 +#define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
   1.729 +#define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
   1.730 +#define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
   1.731 +#define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
   1.732 +
   1.733 +#define cimg_for_in2(bound,i0,i1,i) \
   1.734 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.735 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
   1.736 +      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
   1.737 +      ++i, ++_n1##i)
   1.738 +#define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
   1.739 +#define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
   1.740 +#define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
   1.741 +#define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
   1.742 +#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)
   1.743 +#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)
   1.744 +#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)
   1.745 +#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)
   1.746 +#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)
   1.747 +#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)
   1.748 +#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)
   1.749 +#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)
   1.750 +#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)
   1.751 +#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)
   1.752 +
   1.753 +#define cimg_for3(bound,i) \
   1.754 + for (int i = 0, _p1##i = 0, \
   1.755 +      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
   1.756 +      _n1##i<(int)(bound) || i==--_n1##i; \
   1.757 +      _p1##i = i++, ++_n1##i)
   1.758 +#define cimg_for3X(img,x) cimg_for3((img).width,x)
   1.759 +#define cimg_for3Y(img,y) cimg_for3((img).height,y)
   1.760 +#define cimg_for3Z(img,z) cimg_for3((img).depth,z)
   1.761 +#define cimg_for3V(img,v) cimg_for3((img).dim,v)
   1.762 +#define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
   1.763 +#define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
   1.764 +#define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
   1.765 +#define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
   1.766 +#define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
   1.767 +#define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
   1.768 +#define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
   1.769 +#define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
   1.770 +#define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
   1.771 +#define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
   1.772 +
   1.773 +#define cimg_for_in3(bound,i0,i1,i) \
   1.774 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.775 +      _p1##i = i-1<0?0:i-1, \
   1.776 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
   1.777 +      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
   1.778 +      _p1##i = i++, ++_n1##i)
   1.779 +#define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
   1.780 +#define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
   1.781 +#define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
   1.782 +#define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
   1.783 +#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)
   1.784 +#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)
   1.785 +#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)
   1.786 +#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)
   1.787 +#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)
   1.788 +#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)
   1.789 +#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)
   1.790 +#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)
   1.791 +#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)
   1.792 +#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)
   1.793 +
   1.794 +#define cimg_for4(bound,i) \
   1.795 + for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   1.796 +      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
   1.797 +      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
   1.798 +      _p1##i = i++, ++_n1##i, ++_n2##i)
   1.799 +#define cimg_for4X(img,x) cimg_for4((img).width,x)
   1.800 +#define cimg_for4Y(img,y) cimg_for4((img).height,y)
   1.801 +#define cimg_for4Z(img,z) cimg_for4((img).depth,z)
   1.802 +#define cimg_for4V(img,v) cimg_for4((img).dim,v)
   1.803 +#define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
   1.804 +#define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
   1.805 +#define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
   1.806 +#define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
   1.807 +#define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
   1.808 +#define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
   1.809 +#define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
   1.810 +#define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
   1.811 +#define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
   1.812 +#define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
   1.813 +
   1.814 +#define cimg_for_in4(bound,i0,i1,i) \
   1.815 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.816 +      _p1##i = i-1<0?0:i-1, \
   1.817 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   1.818 +      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
   1.819 +      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
   1.820 +      _p1##i = i++, ++_n1##i, ++_n2##i)
   1.821 +#define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
   1.822 +#define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
   1.823 +#define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
   1.824 +#define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
   1.825 +#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)
   1.826 +#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)
   1.827 +#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)
   1.828 +#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)
   1.829 +#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)
   1.830 +#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)
   1.831 +#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)
   1.832 +#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)
   1.833 +#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)
   1.834 +#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)
   1.835 +
   1.836 +#define cimg_for5(bound,i) \
   1.837 + for (int i = 0, _p2##i = 0, _p1##i = 0, \
   1.838 +      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   1.839 +      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
   1.840 +      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
   1.841 +      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
   1.842 +#define cimg_for5X(img,x) cimg_for5((img).width,x)
   1.843 +#define cimg_for5Y(img,y) cimg_for5((img).height,y)
   1.844 +#define cimg_for5Z(img,z) cimg_for5((img).depth,z)
   1.845 +#define cimg_for5V(img,v) cimg_for5((img).dim,v)
   1.846 +#define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
   1.847 +#define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
   1.848 +#define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
   1.849 +#define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
   1.850 +#define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
   1.851 +#define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
   1.852 +#define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
   1.853 +#define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
   1.854 +#define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
   1.855 +#define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
   1.856 +
   1.857 +#define cimg_for_in5(bound,i0,i1,i) \
   1.858 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.859 +      _p2##i = i-2<0?0:i-2, \
   1.860 +      _p1##i = i-1<0?0:i-1, \
   1.861 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   1.862 +      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
   1.863 +      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
   1.864 +      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
   1.865 +#define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
   1.866 +#define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
   1.867 +#define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
   1.868 +#define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
   1.869 +#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)
   1.870 +#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)
   1.871 +#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)
   1.872 +#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)
   1.873 +#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)
   1.874 +#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)
   1.875 +#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)
   1.876 +#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)
   1.877 +#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)
   1.878 +#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)
   1.879 +
   1.880 +#define cimg_for6(bound,i) \
   1.881 + for (int i = 0, _p2##i = 0, _p1##i = 0, \
   1.882 +      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   1.883 +      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   1.884 +      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
   1.885 +      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
   1.886 +      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   1.887 +#define cimg_for6X(img,x) cimg_for6((img).width,x)
   1.888 +#define cimg_for6Y(img,y) cimg_for6((img).height,y)
   1.889 +#define cimg_for6Z(img,z) cimg_for6((img).depth,z)
   1.890 +#define cimg_for6V(img,v) cimg_for6((img).dim,v)
   1.891 +#define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
   1.892 +#define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
   1.893 +#define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
   1.894 +#define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
   1.895 +#define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
   1.896 +#define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
   1.897 +#define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
   1.898 +#define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
   1.899 +#define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
   1.900 +#define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
   1.901 +
   1.902 +#define cimg_for_in6(bound,i0,i1,i) \
   1.903 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.904 +      _p2##i = i-2<0?0:i-2, \
   1.905 +      _p1##i = i-1<0?0:i-1, \
   1.906 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   1.907 +      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
   1.908 +      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
   1.909 +      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
   1.910 +      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   1.911 +#define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
   1.912 +#define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
   1.913 +#define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
   1.914 +#define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
   1.915 +#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)
   1.916 +#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)
   1.917 +#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)
   1.918 +#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)
   1.919 +#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)
   1.920 +#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)
   1.921 +#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)
   1.922 +#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)
   1.923 +#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)
   1.924 +#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)
   1.925 +
   1.926 +#define cimg_for7(bound,i) \
   1.927 + for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
   1.928 +      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   1.929 +      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   1.930 +      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
   1.931 +      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
   1.932 +      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   1.933 +#define cimg_for7X(img,x) cimg_for7((img).width,x)
   1.934 +#define cimg_for7Y(img,y) cimg_for7((img).height,y)
   1.935 +#define cimg_for7Z(img,z) cimg_for7((img).depth,z)
   1.936 +#define cimg_for7V(img,v) cimg_for7((img).dim,v)
   1.937 +#define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
   1.938 +#define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
   1.939 +#define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
   1.940 +#define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
   1.941 +#define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
   1.942 +#define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
   1.943 +#define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
   1.944 +#define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
   1.945 +#define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
   1.946 +#define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
   1.947 +
   1.948 +#define cimg_for_in7(bound,i0,i1,i) \
   1.949 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.950 +      _p3##i = i-3<0?0:i-3, \
   1.951 +      _p2##i = i-2<0?0:i-2, \
   1.952 +      _p1##i = i-1<0?0:i-1, \
   1.953 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
   1.954 +      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
   1.955 +      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
   1.956 +      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
   1.957 +      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
   1.958 +#define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
   1.959 +#define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
   1.960 +#define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
   1.961 +#define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
   1.962 +#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)
   1.963 +#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)
   1.964 +#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)
   1.965 +#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)
   1.966 +#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)
   1.967 +#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)
   1.968 +#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)
   1.969 +#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)
   1.970 +#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)
   1.971 +#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)
   1.972 +
   1.973 +#define cimg_for8(bound,i) \
   1.974 + for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
   1.975 +      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
   1.976 +      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
   1.977 +      _n3##i = 3>=(bound)?(int)(bound)-1:3, \
   1.978 +      _n4##i = 4>=(bound)?(int)(bound)-1:4; \
   1.979 +      _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
   1.980 +      i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
   1.981 +      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
   1.982 +#define cimg_for8X(img,x) cimg_for8((img).width,x)
   1.983 +#define cimg_for8Y(img,y) cimg_for8((img).height,y)
   1.984 +#define cimg_for8Z(img,z) cimg_for8((img).depth,z)
   1.985 +#define cimg_for8V(img,v) cimg_for8((img).dim,v)
   1.986 +#define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
   1.987 +#define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
   1.988 +#define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
   1.989 +#define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
   1.990 +#define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
   1.991 +#define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
   1.992 +#define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
   1.993 +#define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
   1.994 +#define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
   1.995 +#define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
   1.996 +
   1.997 +#define cimg_for_in8(bound,i0,i1,i) \
   1.998 + for (int i = (int)(i0)<0?0:(int)(i0), \
   1.999 +      _p3##i = i-3<0?0:i-3, \
  1.1000 +      _p2##i = i-2<0?0:i-2, \
  1.1001 +      _p1##i = i-1<0?0:i-1, \
  1.1002 +      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
  1.1003 +      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
  1.1004 +      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
  1.1005 +      _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
  1.1006 +      i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1.1007 +      i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
  1.1008 +      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1.1009 +#define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
  1.1010 +#define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
  1.1011 +#define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
  1.1012 +#define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
  1.1013 +#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)
  1.1014 +#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)
  1.1015 +#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)
  1.1016 +#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)
  1.1017 +#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)
  1.1018 +#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)
  1.1019 +#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)
  1.1020 +#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)
  1.1021 +#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)
  1.1022 +#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)
  1.1023 +
  1.1024 +#define cimg_for9(bound,i) \
  1.1025 +  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
  1.1026 +       _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
  1.1027 +       _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
  1.1028 +       _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
  1.1029 +       _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
  1.1030 +       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1.1031 +       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
  1.1032 +       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1.1033 +#define cimg_for9X(img,x) cimg_for9((img).width,x)
  1.1034 +#define cimg_for9Y(img,y) cimg_for9((img).height,y)
  1.1035 +#define cimg_for9Z(img,z) cimg_for9((img).depth,z)
  1.1036 +#define cimg_for9V(img,v) cimg_for9((img).dim,v)
  1.1037 +#define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
  1.1038 +#define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
  1.1039 +#define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
  1.1040 +#define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
  1.1041 +#define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
  1.1042 +#define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
  1.1043 +#define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
  1.1044 +#define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
  1.1045 +#define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
  1.1046 +#define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
  1.1047 +
  1.1048 +#define cimg_for_in9(bound,i0,i1,i) \
  1.1049 +  for (int i = (int)(i0)<0?0:(int)(i0), \
  1.1050 +       _p4##i = i-4<0?0:i-4, \
  1.1051 +       _p3##i = i-3<0?0:i-3, \
  1.1052 +       _p2##i = i-2<0?0:i-2, \
  1.1053 +       _p1##i = i-1<0?0:i-1, \
  1.1054 +       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
  1.1055 +       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
  1.1056 +       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
  1.1057 +       _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
  1.1058 +       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
  1.1059 +       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
  1.1060 +       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
  1.1061 +#define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
  1.1062 +#define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
  1.1063 +#define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
  1.1064 +#define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
  1.1065 +#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)
  1.1066 +#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)
  1.1067 +#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)
  1.1068 +#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)
  1.1069 +#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)
  1.1070 +#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)
  1.1071 +#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)
  1.1072 +#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)
  1.1073 +#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)
  1.1074 +#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)
  1.1075 +
  1.1076 +#define cimg_for2x2(img,x,y,z,v,I) \
  1.1077 +  cimg_for2((img).height,y) for (int x = 0, \
  1.1078 +   _n1##x = (int)( \
  1.1079 +   (I[0] = (img)(0,y,z,v)), \
  1.1080 +   (I[2] = (img)(0,_n1##y,z,v)), \
  1.1081 +   1>=(img).width?(int)((img).width)-1:1);  \
  1.1082 +   (_n1##x<(int)((img).width) && ( \
  1.1083 +   (I[1] = (img)(_n1##x,y,z,v)), \
  1.1084 +   (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1.1085 +   x==--_n1##x; \
  1.1086 +   I[0] = I[1], \
  1.1087 +   I[2] = I[3], \
  1.1088 +   ++x, ++_n1##x)
  1.1089 +
  1.1090 +#define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1091 +  cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1092 +   _n1##x = (int)( \
  1.1093 +   (I[0] = (img)(x,y,z,v)), \
  1.1094 +   (I[2] = (img)(x,_n1##y,z,v)), \
  1.1095 +   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1.1096 +   x<=(int)(x1) && ((_n1##x<(int)((img).width) && (  \
  1.1097 +   (I[1] = (img)(_n1##x,y,z,v)), \
  1.1098 +   (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1.1099 +   x==--_n1##x); \
  1.1100 +   I[0] = I[1], \
  1.1101 +   I[2] = I[3], \
  1.1102 +   ++x, ++_n1##x)
  1.1103 +
  1.1104 +#define cimg_for3x3(img,x,y,z,v,I) \
  1.1105 +  cimg_for3((img).height,y) for (int x = 0, \
  1.1106 +   _p1##x = 0, \
  1.1107 +   _n1##x = (int)( \
  1.1108 +   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
  1.1109 +   (I[3] = I[4] = (img)(0,y,z,v)), \
  1.1110 +   (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
  1.1111 +   1>=(img).width?(int)((img).width)-1:1); \
  1.1112 +   (_n1##x<(int)((img).width) && ( \
  1.1113 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1.1114 +   (I[5] = (img)(_n1##x,y,z,v)), \
  1.1115 +   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1.1116 +   x==--_n1##x; \
  1.1117 +   I[0] = I[1], I[1] = I[2], \
  1.1118 +   I[3] = I[4], I[4] = I[5], \
  1.1119 +   I[6] = I[7], I[7] = I[8], \
  1.1120 +   _p1##x = x++, ++_n1##x)
  1.1121 +
  1.1122 +#define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1123 +  cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1124 +   _p1##x = x-1<0?0:x-1, \
  1.1125 +   _n1##x = (int)( \
  1.1126 +   (I[0] = (img)(_p1##x,_p1##y,z,v)), \
  1.1127 +   (I[3] = (img)(_p1##x,y,z,v)), \
  1.1128 +   (I[6] = (img)(_p1##x,_n1##y,z,v)), \
  1.1129 +   (I[1] = (img)(x,_p1##y,z,v)), \
  1.1130 +   (I[4] = (img)(x,y,z,v)), \
  1.1131 +   (I[7] = (img)(x,_n1##y,z,v)), \
  1.1132 +   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1.1133 +   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1.1134 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1.1135 +   (I[5] = (img)(_n1##x,y,z,v)), \
  1.1136 +   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
  1.1137 +   x==--_n1##x);            \
  1.1138 +   I[0] = I[1], I[1] = I[2], \
  1.1139 +   I[3] = I[4], I[4] = I[5], \
  1.1140 +   I[6] = I[7], I[7] = I[8], \
  1.1141 +   _p1##x = x++, ++_n1##x)
  1.1142 +
  1.1143 +#define cimg_for4x4(img,x,y,z,v,I) \
  1.1144 +  cimg_for4((img).height,y) for (int x = 0, \
  1.1145 +   _p1##x = 0, \
  1.1146 +   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1.1147 +   _n2##x = (int)( \
  1.1148 +   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
  1.1149 +   (I[4] = I[5] = (img)(0,y,z,v)), \
  1.1150 +   (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
  1.1151 +   (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
  1.1152 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1.1153 +   (I[6] = (img)(_n1##x,y,z,v)), \
  1.1154 +   (I[10] = (img)(_n1##x,_n1##y,z,v)), \
  1.1155 +   (I[14] = (img)(_n1##x,_n2##y,z,v)), \
  1.1156 +   2>=(img).width?(int)((img).width)-1:2); \
  1.1157 +   (_n2##x<(int)((img).width) && ( \
  1.1158 +   (I[3] = (img)(_n2##x,_p1##y,z,v)), \
  1.1159 +   (I[7] = (img)(_n2##x,y,z,v)), \
  1.1160 +   (I[11] = (img)(_n2##x,_n1##y,z,v)), \
  1.1161 +   (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1.1162 +   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
  1.1163 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
  1.1164 +   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1.1165 +   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1.1166 +   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1.1167 +   _p1##x = x++, ++_n1##x, ++_n2##x)
  1.1168 +
  1.1169 +#define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1170 +  cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1171 +   _p1##x = x-1<0?0:x-1, \
  1.1172 +   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1.1173 +   _n2##x = (int)( \
  1.1174 +   (I[0] = (img)(_p1##x,_p1##y,z,v)), \
  1.1175 +   (I[4] = (img)(_p1##x,y,z,v)), \
  1.1176 +   (I[8] = (img)(_p1##x,_n1##y,z,v)), \
  1.1177 +   (I[12] = (img)(_p1##x,_n2##y,z,v)), \
  1.1178 +   (I[1] = (img)(x,_p1##y,z,v)), \
  1.1179 +   (I[5] = (img)(x,y,z,v)), \
  1.1180 +   (I[9] = (img)(x,_n1##y,z,v)), \
  1.1181 +   (I[13] = (img)(x,_n2##y,z,v)), \
  1.1182 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
  1.1183 +   (I[6] = (img)(_n1##x,y,z,v)), \
  1.1184 +   (I[10] = (img)(_n1##x,_n1##y,z,v)), \
  1.1185 +   (I[14] = (img)(_n1##x,_n2##y,z,v)), \
  1.1186 +   x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
  1.1187 +   x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
  1.1188 +   (I[3] = (img)(_n2##x,_p1##y,z,v)), \
  1.1189 +   (I[7] = (img)(_n2##x,y,z,v)), \
  1.1190 +   (I[11] = (img)(_n2##x,_n1##y,z,v)), \
  1.1191 +   (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1.1192 +   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
  1.1193 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
  1.1194 +   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
  1.1195 +   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1.1196 +   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
  1.1197 +   _p1##x = x++, ++_n1##x, ++_n2##x)
  1.1198 +
  1.1199 +#define cimg_for5x5(img,x,y,z,v,I) \
  1.1200 + cimg_for5((img).height,y) for (int x = 0, \
  1.1201 +   _p2##x = 0, _p1##x = 0, \
  1.1202 +   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1.1203 +   _n2##x = (int)( \
  1.1204 +   (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
  1.1205 +   (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
  1.1206 +   (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
  1.1207 +   (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
  1.1208 +   (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
  1.1209 +   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1.1210 +   (I[8] = (img)(_n1##x,_p1##y,z,v)), \
  1.1211 +   (I[13] = (img)(_n1##x,y,z,v)), \
  1.1212 +   (I[18] = (img)(_n1##x,_n1##y,z,v)), \
  1.1213 +   (I[23] = (img)(_n1##x,_n2##y,z,v)),     \
  1.1214 +   2>=(img).width?(int)((img).width)-1:2); \
  1.1215 +   (_n2##x<(int)((img).width) && ( \
  1.1216 +   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1.1217 +   (I[9] = (img)(_n2##x,_p1##y,z,v)), \
  1.1218 +   (I[14] = (img)(_n2##x,y,z,v)), \
  1.1219 +   (I[19] = (img)(_n2##x,_n1##y,z,v)), \
  1.1220 +   (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1.1221 +   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
  1.1222 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
  1.1223 +   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
  1.1224 +   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
  1.1225 +   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
  1.1226 +   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
  1.1227 +   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
  1.1228 +
  1.1229 +#define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1230 + cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1231 +   _p2##x = x-2<0?0:x-2, \
  1.1232 +   _p1##x = x-1<0?0:x-1, \
  1.1233 +   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1.1234 +   _n2##x = (int)( \
  1.1235 +   (I[0] = (img)(_p2##x,_p2##y,z,v)), \
  1.1236 +   (I[5] = (img)(_p2##x,_p1##y,z,v)), \
  1.1237 +   (I[10] = (img)(_p2##x,y,z,v)), \
  1.1238 +   (I[15] = (img)(_p2##x,_n1##y,z,v)), \
  1.1239 +   (I[20] = (img)(_p2##x,_n2##y,z,v)), \
  1.1240 +   (I[1] = (img)(_p1##x,_p2##y,z,v)), \
  1.1241 +   (I[6] = (img)(_p1##x,_p1##y,z,v)), \
  1.1242 +   (I[11] = (img)(_p1##x,y,z,v)), \
  1.1243 +   (I[16] = (img)(_p1##x,_n1##y,z,v)), \
  1.1244 +   (I[21] = (img)(_p1##x,_n2##y,z,v)), \
  1.1245 +   (I[2] = (img)(x,_p2##y,z,v)), \
  1.1246 +   (I[7] = (img)(x,_p1##y,z,v)), \
  1.1247 +   (I[12] = (img)(x,y,z,v)), \
  1.1248 +   (I[17] = (img)(x,_n1##y,z,v)), \
  1.1249 +   (I[22] = (img)(x,_n2##y,z,v)), \
  1.1250 +   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1.1251 +   (I[8] = (img)(_n1##x,_p1##y,z,v)), \
  1.1252 +   (I[13] = (img)(_n1##x,y,z,v)), \
  1.1253 +   (I[18] = (img)(_n1##x,_n1##y,z,v)), \
  1.1254 +   (I[23] = (img)(_n1##x,_n2##y,z,v)), \
  1.1255 +   x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
  1.1256 +   x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
  1.1257 +   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1.1258 +   (I[9] = (img)(_n2##x,_p1##y,z,v)), \
  1.1259 +   (I[14] = (img)(_n2##x,y,z,v)), \
  1.1260 +   (I[19] = (img)(_n2##x,_n1##y,z,v)), \
  1.1261 +   (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
  1.1262 +   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
  1.1263 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
  1.1264 +   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
  1.1265 +   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
  1.1266 +   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
  1.1267 +   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
  1.1268 +   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
  1.1269 +
  1.1270 +#define cimg_for6x6(img,x,y,z,v,I) \
  1.1271 + cimg_for6((img).height,y) for (int x = 0, \
  1.1272 +   _p2##x = 0, _p1##x = 0, \
  1.1273 +   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1.1274 +   _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
  1.1275 +   _n3##x = (int)( \
  1.1276 +   (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
  1.1277 +   (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
  1.1278 +   (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
  1.1279 +   (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
  1.1280 +   (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
  1.1281 +   (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
  1.1282 +   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1.1283 +   (I[9] = (img)(_n1##x,_p1##y,z,v)), \
  1.1284 +   (I[15] = (img)(_n1##x,y,z,v)), \
  1.1285 +   (I[21] = (img)(_n1##x,_n1##y,z,v)), \
  1.1286 +   (I[27] = (img)(_n1##x,_n2##y,z,v)), \
  1.1287 +   (I[33] = (img)(_n1##x,_n3##y,z,v)), \
  1.1288 +   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1.1289 +   (I[10] = (img)(_n2##x,_p1##y,z,v)), \
  1.1290 +   (I[16] = (img)(_n2##x,y,z,v)), \
  1.1291 +   (I[22] = (img)(_n2##x,_n1##y,z,v)), \
  1.1292 +   (I[28] = (img)(_n2##x,_n2##y,z,v)), \
  1.1293 +   (I[34] = (img)(_n2##x,_n3##y,z,v)), \
  1.1294 +   3>=(img).width?(int)((img).width)-1:3); \
  1.1295 +   (_n3##x<(int)((img).width) && ( \
  1.1296 +   (I[5] = (img)(_n3##x,_p2##y,z,v)), \
  1.1297 +   (I[11] = (img)(_n3##x,_p1##y,z,v)), \
  1.1298 +   (I[17] = (img)(_n3##x,y,z,v)), \
  1.1299 +   (I[23] = (img)(_n3##x,_n1##y,z,v)), \
  1.1300 +   (I[29] = (img)(_n3##x,_n2##y,z,v)), \
  1.1301 +   (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1.1302 +   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
  1.1303 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
  1.1304 +   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1.1305 +   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1.1306 +   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1.1307 +   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
  1.1308 +   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1.1309 +   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1.1310 +
  1.1311 +#define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1312 +  cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
  1.1313 +   _p2##x = x-2<0?0:x-2, \
  1.1314 +   _p1##x = x-1<0?0:x-1, \
  1.1315 +   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1.1316 +   _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
  1.1317 +   _n3##x = (int)( \
  1.1318 +   (I[0] = (img)(_p2##x,_p2##y,z,v)), \
  1.1319 +   (I[6] = (img)(_p2##x,_p1##y,z,v)), \
  1.1320 +   (I[12] = (img)(_p2##x,y,z,v)), \
  1.1321 +   (I[18] = (img)(_p2##x,_n1##y,z,v)), \
  1.1322 +   (I[24] = (img)(_p2##x,_n2##y,z,v)), \
  1.1323 +   (I[30] = (img)(_p2##x,_n3##y,z,v)), \
  1.1324 +   (I[1] = (img)(_p1##x,_p2##y,z,v)), \
  1.1325 +   (I[7] = (img)(_p1##x,_p1##y,z,v)), \
  1.1326 +   (I[13] = (img)(_p1##x,y,z,v)), \
  1.1327 +   (I[19] = (img)(_p1##x,_n1##y,z,v)), \
  1.1328 +   (I[25] = (img)(_p1##x,_n2##y,z,v)), \
  1.1329 +   (I[31] = (img)(_p1##x,_n3##y,z,v)), \
  1.1330 +   (I[2] = (img)(x,_p2##y,z,v)), \
  1.1331 +   (I[8] = (img)(x,_p1##y,z,v)), \
  1.1332 +   (I[14] = (img)(x,y,z,v)), \
  1.1333 +   (I[20] = (img)(x,_n1##y,z,v)), \
  1.1334 +   (I[26] = (img)(x,_n2##y,z,v)), \
  1.1335 +   (I[32] = (img)(x,_n3##y,z,v)), \
  1.1336 +   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
  1.1337 +   (I[9] = (img)(_n1##x,_p1##y,z,v)), \
  1.1338 +   (I[15] = (img)(_n1##x,y,z,v)), \
  1.1339 +   (I[21] = (img)(_n1##x,_n1##y,z,v)), \
  1.1340 +   (I[27] = (img)(_n1##x,_n2##y,z,v)), \
  1.1341 +   (I[33] = (img)(_n1##x,_n3##y,z,v)), \
  1.1342 +   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
  1.1343 +   (I[10] = (img)(_n2##x,_p1##y,z,v)), \
  1.1344 +   (I[16] = (img)(_n2##x,y,z,v)), \
  1.1345 +   (I[22] = (img)(_n2##x,_n1##y,z,v)), \
  1.1346 +   (I[28] = (img)(_n2##x,_n2##y,z,v)), \
  1.1347 +   (I[34] = (img)(_n2##x,_n3##y,z,v)), \
  1.1348 +   x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
  1.1349 +   x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
  1.1350 +   (I[5] = (img)(_n3##x,_p2##y,z,v)), \
  1.1351 +   (I[11] = (img)(_n3##x,_p1##y,z,v)), \
  1.1352 +   (I[17] = (img)(_n3##x,y,z,v)), \
  1.1353 +   (I[23] = (img)(_n3##x,_n1##y,z,v)), \
  1.1354 +   (I[29] = (img)(_n3##x,_n2##y,z,v)), \
  1.1355 +   (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1.1356 +   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
  1.1357 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
  1.1358 +   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
  1.1359 +   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
  1.1360 +   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
  1.1361 +   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
  1.1362 +   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
  1.1363 +   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1.1364 +
  1.1365 +#define cimg_for7x7(img,x,y,z,v,I) \
  1.1366 +  cimg_for7((img).height,y) for (int x = 0, \
  1.1367 +   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1.1368 +   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
  1.1369 +   _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
  1.1370 +   _n3##x = (int)( \
  1.1371 +   (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
  1.1372 +   (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
  1.1373 +   (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
  1.1374 +   (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
  1.1375 +   (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
  1.1376 +   (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
  1.1377 +   (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
  1.1378 +   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1.1379 +   (I[11] = (img)(_n1##x,_p2##y,z,v)), \
  1.1380 +   (I[18] = (img)(_n1##x,_p1##y,z,v)), \
  1.1381 +   (I[25] = (img)(_n1##x,y,z,v)), \
  1.1382 +   (I[32] = (img)(_n1##x,_n1##y,z,v)), \
  1.1383 +   (I[39] = (img)(_n1##x,_n2##y,z,v)), \
  1.1384 +   (I[46] = (img)(_n1##x,_n3##y,z,v)), \
  1.1385 +   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1.1386 +   (I[12] = (img)(_n2##x,_p2##y,z,v)), \
  1.1387 +   (I[19] = (img)(_n2##x,_p1##y,z,v)), \
  1.1388 +   (I[26] = (img)(_n2##x,y,z,v)), \
  1.1389 +   (I[33] = (img)(_n2##x,_n1##y,z,v)), \
  1.1390 +   (I[40] = (img)(_n2##x,_n2##y,z,v)), \
  1.1391 +   (I[47] = (img)(_n2##x,_n3##y,z,v)), \
  1.1392 +   3>=(img).width?(int)((img).width)-1:3); \
  1.1393 +   (_n3##x<(int)((img).width) && ( \
  1.1394 +   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1.1395 +   (I[13] = (img)(_n3##x,_p2##y,z,v)), \
  1.1396 +   (I[20] = (img)(_n3##x,_p1##y,z,v)), \
  1.1397 +   (I[27] = (img)(_n3##x,y,z,v)), \
  1.1398 +   (I[34] = (img)(_n3##x,_n1##y,z,v)), \
  1.1399 +   (I[41] = (img)(_n3##x,_n2##y,z,v)), \
  1.1400 +   (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1.1401 +   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
  1.1402 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
  1.1403 +   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
  1.1404 +   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
  1.1405 +   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
  1.1406 +   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
  1.1407 +   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
  1.1408 +   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
  1.1409 +   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1.1410 +
  1.1411 +#define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1412 +  cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1413 +   _p3##x = x-3<0?0:x-3, \
  1.1414 +   _p2##x = x-2<0?0:x-2, \
  1.1415 +   _p1##x = x-1<0?0:x-1, \
  1.1416 +   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
  1.1417 +   _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
  1.1418 +   _n3##x = (int)( \
  1.1419 +   (I[0] = (img)(_p3##x,_p3##y,z,v)), \
  1.1420 +   (I[7] = (img)(_p3##x,_p2##y,z,v)), \
  1.1421 +   (I[14] = (img)(_p3##x,_p1##y,z,v)), \
  1.1422 +   (I[21] = (img)(_p3##x,y,z,v)), \
  1.1423 +   (I[28] = (img)(_p3##x,_n1##y,z,v)), \
  1.1424 +   (I[35] = (img)(_p3##x,_n2##y,z,v)), \
  1.1425 +   (I[42] = (img)(_p3##x,_n3##y,z,v)), \
  1.1426 +   (I[1] = (img)(_p2##x,_p3##y,z,v)), \
  1.1427 +   (I[8] = (img)(_p2##x,_p2##y,z,v)), \
  1.1428 +   (I[15] = (img)(_p2##x,_p1##y,z,v)), \
  1.1429 +   (I[22] = (img)(_p2##x,y,z,v)), \
  1.1430 +   (I[29] = (img)(_p2##x,_n1##y,z,v)), \
  1.1431 +   (I[36] = (img)(_p2##x,_n2##y,z,v)), \
  1.1432 +   (I[43] = (img)(_p2##x,_n3##y,z,v)), \
  1.1433 +   (I[2] = (img)(_p1##x,_p3##y,z,v)), \
  1.1434 +   (I[9] = (img)(_p1##x,_p2##y,z,v)), \
  1.1435 +   (I[16] = (img)(_p1##x,_p1##y,z,v)), \
  1.1436 +   (I[23] = (img)(_p1##x,y,z,v)), \
  1.1437 +   (I[30] = (img)(_p1##x,_n1##y,z,v)), \
  1.1438 +   (I[37] = (img)(_p1##x,_n2##y,z,v)), \
  1.1439 +   (I[44] = (img)(_p1##x,_n3##y,z,v)), \
  1.1440 +   (I[3] = (img)(x,_p3##y,z,v)), \
  1.1441 +   (I[10] = (img)(x,_p2##y,z,v)), \
  1.1442 +   (I[17] = (img)(x,_p1##y,z,v)), \
  1.1443 +   (I[24] = (img)(x,y,z,v)), \
  1.1444 +   (I[31] = (img)(x,_n1##y,z,v)), \
  1.1445 +   (I[38] = (img)(x,_n2##y,z,v)), \
  1.1446 +   (I[45] = (img)(x,_n3##y,z,v)), \
  1.1447 +   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1.1448 +   (I[11] = (img)(_n1##x,_p2##y,z,v)), \
  1.1449 +   (I[18] = (img)(_n1##x,_p1##y,z,v)), \
  1.1450 +   (I[25] = (img)(_n1##x,y,z,v)), \
  1.1451 +   (I[32] = (img)(_n1##x,_n1##y,z,v)), \
  1.1452 +   (I[39] = (img)(_n1##x,_n2##y,z,v)), \
  1.1453 +   (I[46] = (img)(_n1##x,_n3##y,z,v)), \
  1.1454 +   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1.1455 +   (I[12] = (img)(_n2##x,_p2##y,z,v)), \
  1.1456 +   (I[19] = (img)(_n2##x,_p1##y,z,v)), \
  1.1457 +   (I[26] = (img)(_n2##x,y,z,v)), \
  1.1458 +   (I[33] = (img)(_n2##x,_n1##y,z,v)), \
  1.1459 +   (I[40] = (img)(_n2##x,_n2##y,z,v)), \
  1.1460 +   (I[47] = (img)(_n2##x,_n3##y,z,v)), \
  1.1461 +   x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
  1.1462 +   x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
  1.1463 +   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1.1464 +   (I[13] = (img)(_n3##x,_p2##y,z,v)), \
  1.1465 +   (I[20] = (img)(_n3##x,_p1##y,z,v)), \
  1.1466 +   (I[27] = (img)(_n3##x,y,z,v)), \
  1.1467 +   (I[34] = (img)(_n3##x,_n1##y,z,v)), \
  1.1468 +   (I[41] = (img)(_n3##x,_n2##y,z,v)), \
  1.1469 +   (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
  1.1470 +   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
  1.1471 +   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
  1.1472 +   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
  1.1473 +   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
  1.1474 +   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
  1.1475 +   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
  1.1476 +   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
  1.1477 +   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
  1.1478 +   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
  1.1479 +
  1.1480 +#define cimg_for8x8(img,x,y,z,v,I) \
  1.1481 +  cimg_for8((img).height,y) for (int x = 0, \
  1.1482 +   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1.1483 +   _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
  1.1484 +   _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
  1.1485 +   _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
  1.1486 +   _n4##x = (int)( \
  1.1487 +   (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
  1.1488 +   (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
  1.1489 +   (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
  1.1490 +   (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
  1.1491 +   (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
  1.1492 +   (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
  1.1493 +   (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
  1.1494 +   (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
  1.1495 +   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1.1496 +   (I[12] = (img)(_n1##x,_p2##y,z,v)), \
  1.1497 +   (I[20] = (img)(_n1##x,_p1##y,z,v)), \
  1.1498 +   (I[28] = (img)(_n1##x,y,z,v)), \
  1.1499 +   (I[36] = (img)(_n1##x,_n1##y,z,v)), \
  1.1500 +   (I[44] = (img)(_n1##x,_n2##y,z,v)), \
  1.1501 +   (I[52] = (img)(_n1##x,_n3##y,z,v)), \
  1.1502 +   (I[60] = (img)(_n1##x,_n4##y,z,v)), \
  1.1503 +   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1.1504 +   (I[13] = (img)(_n2##x,_p2##y,z,v)), \
  1.1505 +   (I[21] = (img)(_n2##x,_p1##y,z,v)), \
  1.1506 +   (I[29] = (img)(_n2##x,y,z,v)), \
  1.1507 +   (I[37] = (img)(_n2##x,_n1##y,z,v)), \
  1.1508 +   (I[45] = (img)(_n2##x,_n2##y,z,v)), \
  1.1509 +   (I[53] = (img)(_n2##x,_n3##y,z,v)), \
  1.1510 +   (I[61] = (img)(_n2##x,_n4##y,z,v)), \
  1.1511 +   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1.1512 +   (I[14] = (img)(_n3##x,_p2##y,z,v)), \
  1.1513 +   (I[22] = (img)(_n3##x,_p1##y,z,v)), \
  1.1514 +   (I[30] = (img)(_n3##x,y,z,v)), \
  1.1515 +   (I[38] = (img)(_n3##x,_n1##y,z,v)), \
  1.1516 +   (I[46] = (img)(_n3##x,_n2##y,z,v)), \
  1.1517 +   (I[54] = (img)(_n3##x,_n3##y,z,v)), \
  1.1518 +   (I[62] = (img)(_n3##x,_n4##y,z,v)), \
  1.1519 +   4>=((img).width)?(int)((img).width)-1:4); \
  1.1520 +   (_n4##x<(int)((img).width) && ( \
  1.1521 +   (I[7] = (img)(_n4##x,_p3##y,z,v)), \
  1.1522 +   (I[15] = (img)(_n4##x,_p2##y,z,v)), \
  1.1523 +   (I[23] = (img)(_n4##x,_p1##y,z,v)), \
  1.1524 +   (I[31] = (img)(_n4##x,y,z,v)), \
  1.1525 +   (I[39] = (img)(_n4##x,_n1##y,z,v)), \
  1.1526 +   (I[47] = (img)(_n4##x,_n2##y,z,v)), \
  1.1527 +   (I[55] = (img)(_n4##x,_n3##y,z,v)), \
  1.1528 +   (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1.1529 +   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
  1.1530 +   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], \
  1.1531 +   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], \
  1.1532 +   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], \
  1.1533 +   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], \
  1.1534 +   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], \
  1.1535 +   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], \
  1.1536 +   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], \
  1.1537 +   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], \
  1.1538 +   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1.1539 +
  1.1540 +#define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1541 +  cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1542 +   _p3##x = x-3<0?0:x-3, \
  1.1543 +   _p2##x = x-2<0?0:x-2, \
  1.1544 +   _p1##x = x-1<0?0:x-1, \
  1.1545 +   _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
  1.1546 +   _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
  1.1547 +   _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
  1.1548 +   _n4##x = (int)( \
  1.1549 +   (I[0] = (img)(_p3##x,_p3##y,z,v)), \
  1.1550 +   (I[8] = (img)(_p3##x,_p2##y,z,v)), \
  1.1551 +   (I[16] = (img)(_p3##x,_p1##y,z,v)), \
  1.1552 +   (I[24] = (img)(_p3##x,y,z,v)), \
  1.1553 +   (I[32] = (img)(_p3##x,_n1##y,z,v)), \
  1.1554 +   (I[40] = (img)(_p3##x,_n2##y,z,v)), \
  1.1555 +   (I[48] = (img)(_p3##x,_n3##y,z,v)), \
  1.1556 +   (I[56] = (img)(_p3##x,_n4##y,z,v)), \
  1.1557 +   (I[1] = (img)(_p2##x,_p3##y,z,v)), \
  1.1558 +   (I[9] = (img)(_p2##x,_p2##y,z,v)), \
  1.1559 +   (I[17] = (img)(_p2##x,_p1##y,z,v)), \
  1.1560 +   (I[25] = (img)(_p2##x,y,z,v)), \
  1.1561 +   (I[33] = (img)(_p2##x,_n1##y,z,v)), \
  1.1562 +   (I[41] = (img)(_p2##x,_n2##y,z,v)), \
  1.1563 +   (I[49] = (img)(_p2##x,_n3##y,z,v)), \
  1.1564 +   (I[57] = (img)(_p2##x,_n4##y,z,v)), \
  1.1565 +   (I[2] = (img)(_p1##x,_p3##y,z,v)), \
  1.1566 +   (I[10] = (img)(_p1##x,_p2##y,z,v)), \
  1.1567 +   (I[18] = (img)(_p1##x,_p1##y,z,v)), \
  1.1568 +   (I[26] = (img)(_p1##x,y,z,v)), \
  1.1569 +   (I[34] = (img)(_p1##x,_n1##y,z,v)), \
  1.1570 +   (I[42] = (img)(_p1##x,_n2##y,z,v)), \
  1.1571 +   (I[50] = (img)(_p1##x,_n3##y,z,v)), \
  1.1572 +   (I[58] = (img)(_p1##x,_n4##y,z,v)), \
  1.1573 +   (I[3] = (img)(x,_p3##y,z,v)), \
  1.1574 +   (I[11] = (img)(x,_p2##y,z,v)), \
  1.1575 +   (I[19] = (img)(x,_p1##y,z,v)), \
  1.1576 +   (I[27] = (img)(x,y,z,v)), \
  1.1577 +   (I[35] = (img)(x,_n1##y,z,v)), \
  1.1578 +   (I[43] = (img)(x,_n2##y,z,v)), \
  1.1579 +   (I[51] = (img)(x,_n3##y,z,v)), \
  1.1580 +   (I[59] = (img)(x,_n4##y,z,v)), \
  1.1581 +   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
  1.1582 +   (I[12] = (img)(_n1##x,_p2##y,z,v)), \
  1.1583 +   (I[20] = (img)(_n1##x,_p1##y,z,v)), \
  1.1584 +   (I[28] = (img)(_n1##x,y,z,v)), \
  1.1585 +   (I[36] = (img)(_n1##x,_n1##y,z,v)), \
  1.1586 +   (I[44] = (img)(_n1##x,_n2##y,z,v)), \
  1.1587 +   (I[52] = (img)(_n1##x,_n3##y,z,v)), \
  1.1588 +   (I[60] = (img)(_n1##x,_n4##y,z,v)), \
  1.1589 +   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
  1.1590 +   (I[13] = (img)(_n2##x,_p2##y,z,v)), \
  1.1591 +   (I[21] = (img)(_n2##x,_p1##y,z,v)), \
  1.1592 +   (I[29] = (img)(_n2##x,y,z,v)), \
  1.1593 +   (I[37] = (img)(_n2##x,_n1##y,z,v)), \
  1.1594 +   (I[45] = (img)(_n2##x,_n2##y,z,v)), \
  1.1595 +   (I[53] = (img)(_n2##x,_n3##y,z,v)), \
  1.1596 +   (I[61] = (img)(_n2##x,_n4##y,z,v)), \
  1.1597 +   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
  1.1598 +   (I[14] = (img)(_n3##x,_p2##y,z,v)), \
  1.1599 +   (I[22] = (img)(_n3##x,_p1##y,z,v)), \
  1.1600 +   (I[30] = (img)(_n3##x,y,z,v)), \
  1.1601 +   (I[38] = (img)(_n3##x,_n1##y,z,v)), \
  1.1602 +   (I[46] = (img)(_n3##x,_n2##y,z,v)), \
  1.1603 +   (I[54] = (img)(_n3##x,_n3##y,z,v)), \
  1.1604 +   (I[62] = (img)(_n3##x,_n4##y,z,v)), \
  1.1605 +   x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
  1.1606 +   x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
  1.1607 +   (I[7] = (img)(_n4##x,_p3##y,z,v)), \
  1.1608 +   (I[15] = (img)(_n4##x,_p2##y,z,v)), \
  1.1609 +   (I[23] = (img)(_n4##x,_p1##y,z,v)), \
  1.1610 +   (I[31] = (img)(_n4##x,y,z,v)), \
  1.1611 +   (I[39] = (img)(_n4##x,_n1##y,z,v)), \
  1.1612 +   (I[47] = (img)(_n4##x,_n2##y,z,v)), \
  1.1613 +   (I[55] = (img)(_n4##x,_n3##y,z,v)), \
  1.1614 +   (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1.1615 +   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
  1.1616 +   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], \
  1.1617 +   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], \
  1.1618 +   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], \
  1.1619 +   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], \
  1.1620 +   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], \
  1.1621 +   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], \
  1.1622 +   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], \
  1.1623 +   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], \
  1.1624 +   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1.1625 +
  1.1626 +#define cimg_for9x9(img,x,y,z,v,I) \
  1.1627 +  cimg_for9((img).height,y) for (int x = 0, \
  1.1628 +   _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
  1.1629 +   _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
  1.1630 +   _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
  1.1631 +   _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
  1.1632 +   _n4##x = (int)( \
  1.1633 +   (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
  1.1634 +   (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
  1.1635 +   (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
  1.1636 +   (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
  1.1637 +   (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
  1.1638 +   (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
  1.1639 +   (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
  1.1640 +   (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
  1.1641 +   (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
  1.1642 +   (I[5] = (img)(_n1##x,_p4##y,z,v)), \
  1.1643 +   (I[14] = (img)(_n1##x,_p3##y,z,v)), \
  1.1644 +   (I[23] = (img)(_n1##x,_p2##y,z,v)), \
  1.1645 +   (I[32] = (img)(_n1##x,_p1##y,z,v)), \
  1.1646 +   (I[41] = (img)(_n1##x,y,z,v)), \
  1.1647 +   (I[50] = (img)(_n1##x,_n1##y,z,v)), \
  1.1648 +   (I[59] = (img)(_n1##x,_n2##y,z,v)), \
  1.1649 +   (I[68] = (img)(_n1##x,_n3##y,z,v)), \
  1.1650 +   (I[77] = (img)(_n1##x,_n4##y,z,v)), \
  1.1651 +   (I[6] = (img)(_n2##x,_p4##y,z,v)), \
  1.1652 +   (I[15] = (img)(_n2##x,_p3##y,z,v)), \
  1.1653 +   (I[24] = (img)(_n2##x,_p2##y,z,v)), \
  1.1654 +   (I[33] = (img)(_n2##x,_p1##y,z,v)), \
  1.1655 +   (I[42] = (img)(_n2##x,y,z,v)), \
  1.1656 +   (I[51] = (img)(_n2##x,_n1##y,z,v)), \
  1.1657 +   (I[60] = (img)(_n2##x,_n2##y,z,v)), \
  1.1658 +   (I[69] = (img)(_n2##x,_n3##y,z,v)), \
  1.1659 +   (I[78] = (img)(_n2##x,_n4##y,z,v)), \
  1.1660 +   (I[7] = (img)(_n3##x,_p4##y,z,v)), \
  1.1661 +   (I[16] = (img)(_n3##x,_p3##y,z,v)), \
  1.1662 +   (I[25] = (img)(_n3##x,_p2##y,z,v)), \
  1.1663 +   (I[34] = (img)(_n3##x,_p1##y,z,v)), \
  1.1664 +   (I[43] = (img)(_n3##x,y,z,v)), \
  1.1665 +   (I[52] = (img)(_n3##x,_n1##y,z,v)), \
  1.1666 +   (I[61] = (img)(_n3##x,_n2##y,z,v)), \
  1.1667 +   (I[70] = (img)(_n3##x,_n3##y,z,v)), \
  1.1668 +   (I[79] = (img)(_n3##x,_n4##y,z,v)), \
  1.1669 +   4>=((img).width)?(int)((img).width)-1:4); \
  1.1670 +   (_n4##x<(int)((img).width) && ( \
  1.1671 +   (I[8] = (img)(_n4##x,_p4##y,z,v)), \
  1.1672 +   (I[17] = (img)(_n4##x,_p3##y,z,v)), \
  1.1673 +   (I[26] = (img)(_n4##x,_p2##y,z,v)), \
  1.1674 +   (I[35] = (img)(_n4##x,_p1##y,z,v)), \
  1.1675 +   (I[44] = (img)(_n4##x,y,z,v)), \
  1.1676 +   (I[53] = (img)(_n4##x,_n1##y,z,v)), \
  1.1677 +   (I[62] = (img)(_n4##x,_n2##y,z,v)), \
  1.1678 +   (I[71] = (img)(_n4##x,_n3##y,z,v)), \
  1.1679 +   (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1.1680 +   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
  1.1681 +   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], \
  1.1682 +   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], \
  1.1683 +   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], \
  1.1684 +   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], \
  1.1685 +   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], \
  1.1686 +   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], \
  1.1687 +   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], \
  1.1688 +   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], \
  1.1689 +   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], \
  1.1690 +   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1.1691 +
  1.1692 +#define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
  1.1693 +  cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
  1.1694 +   _p4##x = x-4<0?0:x-4, \
  1.1695 +   _p3##x = x-3<0?0:x-3, \
  1.1696 +   _p2##x = x-2<0?0:x-2, \
  1.1697 +   _p1##x = x-1<0?0:x-1, \
  1.1698 +   _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
  1.1699 +   _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
  1.1700 +   _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
  1.1701 +   _n4##x = (int)( \
  1.1702 +   (I[0] = (img)(_p4##x,_p4##y,z,v)), \
  1.1703 +   (I[9] = (img)(_p4##x,_p3##y,z,v)), \
  1.1704 +   (I[18] = (img)(_p4##x,_p2##y,z,v)), \
  1.1705 +   (I[27] = (img)(_p4##x,_p1##y,z,v)), \
  1.1706 +   (I[36] = (img)(_p4##x,y,z,v)), \
  1.1707 +   (I[45] = (img)(_p4##x,_n1##y,z,v)), \
  1.1708 +   (I[54] = (img)(_p4##x,_n2##y,z,v)), \
  1.1709 +   (I[63] = (img)(_p4##x,_n3##y,z,v)), \
  1.1710 +   (I[72] = (img)(_p4##x,_n4##y,z,v)), \
  1.1711 +   (I[1] = (img)(_p3##x,_p4##y,z,v)), \
  1.1712 +   (I[10] = (img)(_p3##x,_p3##y,z,v)), \
  1.1713 +   (I[19] = (img)(_p3##x,_p2##y,z,v)), \
  1.1714 +   (I[28] = (img)(_p3##x,_p1##y,z,v)), \
  1.1715 +   (I[37] = (img)(_p3##x,y,z,v)), \
  1.1716 +   (I[46] = (img)(_p3##x,_n1##y,z,v)), \
  1.1717 +   (I[55] = (img)(_p3##x,_n2##y,z,v)), \
  1.1718 +   (I[64] = (img)(_p3##x,_n3##y,z,v)), \
  1.1719 +   (I[73] = (img)(_p3##x,_n4##y,z,v)), \
  1.1720 +   (I[2] = (img)(_p2##x,_p4##y,z,v)), \
  1.1721 +   (I[11] = (img)(_p2##x,_p3##y,z,v)), \
  1.1722 +   (I[20] = (img)(_p2##x,_p2##y,z,v)), \
  1.1723 +   (I[29] = (img)(_p2##x,_p1##y,z,v)), \
  1.1724 +   (I[38] = (img)(_p2##x,y,z,v)), \
  1.1725 +   (I[47] = (img)(_p2##x,_n1##y,z,v)), \
  1.1726 +   (I[56] = (img)(_p2##x,_n2##y,z,v)), \
  1.1727 +   (I[65] = (img)(_p2##x,_n3##y,z,v)), \
  1.1728 +   (I[74] = (img)(_p2##x,_n4##y,z,v)), \
  1.1729 +   (I[3] = (img)(_p1##x,_p4##y,z,v)), \
  1.1730 +   (I[12] = (img)(_p1##x,_p3##y,z,v)), \
  1.1731 +   (I[21] = (img)(_p1##x,_p2##y,z,v)), \
  1.1732 +   (I[30] = (img)(_p1##x,_p1##y,z,v)), \
  1.1733 +   (I[39] = (img)(_p1##x,y,z,v)), \
  1.1734 +   (I[48] = (img)(_p1##x,_n1##y,z,v)), \
  1.1735 +   (I[57] = (img)(_p1##x,_n2##y,z,v)), \
  1.1736 +   (I[66] = (img)(_p1##x,_n3##y,z,v)), \
  1.1737 +   (I[75] = (img)(_p1##x,_n4##y,z,v)), \
  1.1738 +   (I[4] = (img)(x,_p4##y,z,v)), \
  1.1739 +   (I[13] = (img)(x,_p3##y,z,v)), \
  1.1740 +   (I[22] = (img)(x,_p2##y,z,v)), \
  1.1741 +   (I[31] = (img)(x,_p1##y,z,v)), \
  1.1742 +   (I[40] = (img)(x,y,z,v)), \
  1.1743 +   (I[49] = (img)(x,_n1##y,z,v)), \
  1.1744 +   (I[58] = (img)(x,_n2##y,z,v)), \
  1.1745 +   (I[67] = (img)(x,_n3##y,z,v)), \
  1.1746 +   (I[76] = (img)(x,_n4##y,z,v)), \
  1.1747 +   (I[5] = (img)(_n1##x,_p4##y,z,v)), \
  1.1748 +   (I[14] = (img)(_n1##x,_p3##y,z,v)), \
  1.1749 +   (I[23] = (img)(_n1##x,_p2##y,z,v)), \
  1.1750 +   (I[32] = (img)(_n1##x,_p1##y,z,v)), \
  1.1751 +   (I[41] = (img)(_n1##x,y,z,v)), \
  1.1752 +   (I[50] = (img)(_n1##x,_n1##y,z,v)), \
  1.1753 +   (I[59] = (img)(_n1##x,_n2##y,z,v)), \
  1.1754 +   (I[68] = (img)(_n1##x,_n3##y,z,v)), \
  1.1755 +   (I[77] = (img)(_n1##x,_n4##y,z,v)), \
  1.1756 +   (I[6] = (img)(_n2##x,_p4##y,z,v)), \
  1.1757 +   (I[15] = (img)(_n2##x,_p3##y,z,v)), \
  1.1758 +   (I[24] = (img)(_n2##x,_p2##y,z,v)), \
  1.1759 +   (I[33] = (img)(_n2##x,_p1##y,z,v)), \
  1.1760 +   (I[42] = (img)(_n2##x,y,z,v)), \
  1.1761 +   (I[51] = (img)(_n2##x,_n1##y,z,v)), \
  1.1762 +   (I[60] = (img)(_n2##x,_n2##y,z,v)), \
  1.1763 +   (I[69] = (img)(_n2##x,_n3##y,z,v)), \
  1.1764 +   (I[78] = (img)(_n2##x,_n4##y,z,v)), \
  1.1765 +   (I[7] = (img)(_n3##x,_p4##y,z,v)), \
  1.1766 +   (I[16] = (img)(_n3##x,_p3##y,z,v)), \
  1.1767 +   (I[25] = (img)(_n3##x,_p2##y,z,v)), \
  1.1768 +   (I[34] = (img)(_n3##x,_p1##y,z,v)), \
  1.1769 +   (I[43] = (img)(_n3##x,y,z,v)), \
  1.1770 +   (I[52] = (img)(_n3##x,_n1##y,z,v)), \
  1.1771 +   (I[61] = (img)(_n3##x,_n2##y,z,v)), \
  1.1772 +   (I[70] = (img)(_n3##x,_n3##y,z,v)), \
  1.1773 +   (I[79] = (img)(_n3##x,_n4##y,z,v)), \
  1.1774 +   x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
  1.1775 +   x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
  1.1776 +   (I[8] = (img)(_n4##x,_p4##y,z,v)), \
  1.1777 +   (I[17] = (img)(_n4##x,_p3##y,z,v)), \
  1.1778 +   (I[26] = (img)(_n4##x,_p2##y,z,v)), \
  1.1779 +   (I[35] = (img)(_n4##x,_p1##y,z,v)), \
  1.1780 +   (I[44] = (img)(_n4##x,y,z,v)), \
  1.1781 +   (I[53] = (img)(_n4##x,_n1##y,z,v)), \
  1.1782 +   (I[62] = (img)(_n4##x,_n2##y,z,v)), \
  1.1783 +   (I[71] = (img)(_n4##x,_n3##y,z,v)), \
  1.1784 +   (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
  1.1785 +   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
  1.1786 +   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], \
  1.1787 +   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], \
  1.1788 +   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], \
  1.1789 +   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], \
  1.1790 +   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], \
  1.1791 +   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], \
  1.1792 +   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], \
  1.1793 +   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], \
  1.1794 +   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], \
  1.1795 +   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
  1.1796 +
  1.1797 +#define cimg_for2x2x2(img,x,y,z,v,I) \
  1.1798 + cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
  1.1799 +   _n1##x = (int)( \
  1.1800 +   (I[0] = (img)(0,y,z,v)), \
  1.1801 +   (I[2] = (img)(0,_n1##y,z,v)), \
  1.1802 +   (I[4] = (img)(0,y,_n1##z,v)), \
  1.1803 +   (I[6] = (img)(0,_n1##y,_n1##z,v)), \
  1.1804 +   1>=(img).width?(int)((img).width)-1:1); \
  1.1805 +   (_n1##x<(int)((img).width) && ( \
  1.1806 +   (I[1] = (img)(_n1##x,y,z,v)), \
  1.1807 +   (I[3] = (img)(_n1##x,_n1##y,z,v)), \
  1.1808 +   (I[5] = (img)(_n1##x,y,_n1##z,v)), \
  1.1809 +   (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1.1810 +   x==--_n1##x; \
  1.1811 +   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
  1.1812 +   ++x, ++_n1##x)
  1.1813 +
  1.1814 +#define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
  1.1815 + 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), \
  1.1816 +   _n1##x = (int)( \
  1.1817 +   (I[0] = (img)(x,y,z,v)), \
  1.1818 +   (I[2] = (img)(x,_n1##y,z,v)), \
  1.1819 +   (I[4] = (img)(x,y,_n1##z,v)), \
  1.1820 +   (I[6] = (img)(x,_n1##y,_n1##z,v)), \
  1.1821 +   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1.1822 +   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1.1823 +   (I[1] = (img)(_n1##x,y,z,v)), \
  1.1824 +   (I[3] = (img)(_n1##x,_n1##y,z,v)), \
  1.1825 +   (I[5] = (img)(_n1##x,y,_n1##z,v)), \
  1.1826 +   (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1.1827 +   x==--_n1##x); \
  1.1828 +   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
  1.1829 +   ++x, ++_n1##x)
  1.1830 +
  1.1831 +#define cimg_for3x3x3(img,x,y,z,v,I) \
  1.1832 + cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
  1.1833 +   _p1##x = 0, \
  1.1834 +   _n1##x = (int)( \
  1.1835 +   (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
  1.1836 +   (I[3] = I[4] = (img)(0,y,_p1##z,v)),  \
  1.1837 +   (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
  1.1838 +   (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
  1.1839 +   (I[12] = I[13] = (img)(0,y,z,v)), \
  1.1840 +   (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
  1.1841 +   (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
  1.1842 +   (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
  1.1843 +   (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
  1.1844 +   1>=(img).width?(int)((img).width)-1:1); \
  1.1845 +   (_n1##x<(int)((img).width) && ( \
  1.1846 +   (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
  1.1847 +   (I[5] = (img)(_n1##x,y,_p1##z,v)), \
  1.1848 +   (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
  1.1849 +   (I[11] = (img)(_n1##x,_p1##y,z,v)), \
  1.1850 +   (I[14] = (img)(_n1##x,y,z,v)), \
  1.1851 +   (I[17] = (img)(_n1##x,_n1##y,z,v)), \
  1.1852 +   (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
  1.1853 +   (I[23] = (img)(_n1##x,y,_n1##z,v)), \
  1.1854 +   (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1.1855 +   x==--_n1##x; \
  1.1856 +   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
  1.1857 +   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
  1.1858 +   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
  1.1859 +   _p1##x = x++, ++_n1##x)
  1.1860 +
  1.1861 +#define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
  1.1862 + 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), \
  1.1863 +   _p1##x = x-1<0?0:x-1, \
  1.1864 +   _n1##x = (int)( \
  1.1865 +   (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
  1.1866 +   (I[3] = (img)(_p1##x,y,_p1##z,v)),  \
  1.1867 +   (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
  1.1868 +   (I[9] = (img)(_p1##x,_p1##y,z,v)), \
  1.1869 +   (I[12] = (img)(_p1##x,y,z,v)), \
  1.1870 +   (I[15] = (img)(_p1##x,_n1##y,z,v)), \
  1.1871 +   (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
  1.1872 +   (I[21] = (img)(_p1##x,y,_n1##z,v)), \
  1.1873 +   (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
  1.1874 +   (I[1] = (img)(x,_p1##y,_p1##z,v)), \
  1.1875 +   (I[4] = (img)(x,y,_p1##z,v)),  \
  1.1876 +   (I[7] = (img)(x,_n1##y,_p1##z,v)), \
  1.1877 +   (I[10] = (img)(x,_p1##y,z,v)), \
  1.1878 +   (I[13] = (img)(x,y,z,v)), \
  1.1879 +   (I[16] = (img)(x,_n1##y,z,v)), \
  1.1880 +   (I[19] = (img)(x,_p1##y,_n1##z,v)), \
  1.1881 +   (I[22] = (img)(x,y,_n1##z,v)), \
  1.1882 +   (I[25] = (img)(x,_n1##y,_n1##z,v)), \
  1.1883 +   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
  1.1884 +   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
  1.1885 +   (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
  1.1886 +   (I[5] = (img)(_n1##x,y,_p1##z,v)), \
  1.1887 +   (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
  1.1888 +   (I[11] = (img)(_n1##x,_p1##y,z,v)), \
  1.1889 +   (I[14] = (img)(_n1##x,y,z,v)), \
  1.1890 +   (I[17] = (img)(_n1##x,_n1##y,z,v)), \
  1.1891 +   (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
  1.1892 +   (I[23] = (img)(_n1##x,y,_n1##z,v)), \
  1.1893 +   (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
  1.1894 +   x==--_n1##x); \
  1.1895 +   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
  1.1896 +   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
  1.1897 +   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
  1.1898 +   _p1##x = x++, ++_n1##x)
  1.1899 +
  1.1900 +/*------------------------------------------------
  1.1901 + #
  1.1902 + #
  1.1903 + #  Definition of the cimg_library:: namespace
  1.1904 + #
  1.1905 + #
  1.1906 + -------------------------------------------------*/
  1.1907 +//! This namespace encompasses all classes and functions of the %CImg library.
  1.1908 +/**
  1.1909 +   This namespace is defined to avoid functions and class names collisions
  1.1910 +   that could happen with the include of other C++ header files.
  1.1911 +   Anyway, it should not happen often and you should reasonnably start most of your
  1.1912 +   %CImg-based programs with
  1.1913 +   \code
  1.1914 +   #include "CImg.h"
  1.1915 +   using namespace cimg_library;
  1.1916 +   \endcode
  1.1917 +   to simplify the declaration of %CImg Library variables afterwards.
  1.1918 +**/
  1.1919 +namespace cimg_library {
  1.1920 +
  1.1921 +  // Declare the only four classes of the CImg Library.
  1.1922 +  //
  1.1923 +  template<typename T=float> struct CImg;
  1.1924 +  template<typename T=float> struct CImgList;
  1.1925 +  struct CImgDisplay;
  1.1926 +  struct CImgException;
  1.1927 +
  1.1928 +  // (Pre)declare the cimg namespace.
  1.1929 +  // This is not the complete namespace declaration. It only contains some
  1.1930 +  // necessary stuffs to ensure a correct declaration order of classes and functions
  1.1931 +  // defined afterwards.
  1.1932 +  //
  1.1933 +  namespace cimg {
  1.1934 +
  1.1935 +#ifdef cimg_use_vt100
  1.1936 +    const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
  1.1937 +    const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
  1.1938 +    const char t_bold[] = { 0x1b,'[','1','m','\0' };
  1.1939 +    const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
  1.1940 +    const char t_green[] = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
  1.1941 +#else
  1.1942 +    const char t_normal[] = { '\0' };
  1.1943 +    const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
  1.1944 +      *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
  1.1945 +#endif
  1.1946 +
  1.1947 +    inline void info();
  1.1948 +
  1.1949 +    //! Get/set the current CImg exception mode.
  1.1950 +    /**
  1.1951 +       The way error messages are handled by CImg can be changed dynamically, using this function.
  1.1952 +       Possible values are :
  1.1953 +       - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
  1.1954 +       - 1 to display debug messages on standard error (console).
  1.1955 +       - 2 to display debug messages in modal windows (default behavior).
  1.1956 +       - 3 to do as 1 + add extra warnings (may slow down the code !).
  1.1957 +       - 4 to do as 2 + add extra warnings (may slow down the code !).
  1.1958 +     **/
  1.1959 +    inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
  1.1960 +
  1.1961 +    inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
  1.1962 +                      const char *button2_txt=0, const char *button3_txt=0,
  1.1963 +                      const char *button4_txt=0, const char *button5_txt=0,
  1.1964 +                      const char *button6_txt=0, const bool centering=false);
  1.1965 +  }
  1.1966 +
  1.1967 +  /*----------------------------------------------
  1.1968 +   #
  1.1969 +   # Definition of the CImgException structures
  1.1970 +   #
  1.1971 +   ----------------------------------------------*/
  1.1972 +  //! Instances of this class are thrown when errors occur during a %CImg library function call.
  1.1973 +  /**
  1.1974 +     \section ex1 Overview
  1.1975 +
  1.1976 +      CImgException is the base class of %CImg exceptions.
  1.1977 +      Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
  1.1978 +      CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
  1.1979 +      are generally used instead. These sub-classes are :
  1.1980 +
  1.1981 +      - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
  1.1982 +      correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
  1.1983 +      below will throw a \a CImgInstanceException.
  1.1984 +      \code
  1.1985 +      CImg<float> img;        // Construct an empty image.
  1.1986 +      img.blur(10);           // Try to blur the image.
  1.1987 +      \endcode
  1.1988 +
  1.1989 +      - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
  1.1990 +      Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
  1.1991 +      The example below will throw a \a CImgArgumentException.
  1.1992 +      \code
  1.1993 +      CImg<float> img(100,100,1,3);   // Define a 100x100 color image with float pixels.
  1.1994 +      img = 0;                     // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
  1.1995 +      \endcode
  1.1996 +
  1.1997 +      - \b CImgIOException : Thrown when an error occured when trying to load or save image files.
  1.1998 +      The example below will throw a \a CImgIOException.
  1.1999 +      \code
  1.2000 +      CImg<float> img("file_doesnt_exist.jpg");    // Try to load a file that doesn't exist.
  1.2001 +      \endcode
  1.2002 +
  1.2003 +      - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window.
  1.2004 +      This exception is thrown when image display request cannot be satisfied.
  1.2005 +
  1.2006 +      The parent class CImgException may be thrown itself when errors that cannot be classified in one of
  1.2007 +      the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
  1.2008 +      reserved to %CImg Library functions.
  1.2009 +      \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple
  1.2010 +      subclasses of CImgException and are thus not detailled more in this reference documentation.
  1.2011 +
  1.2012 +      \section ex2 Exception handling
  1.2013 +
  1.2014 +      When an error occurs, the %CImg Library first displays the error in a modal window.
  1.2015 +      Then, it throws an instance of the corresponding exception class, generally leading the program to stop
  1.2016 +      (this is the default behavior).
  1.2017 +      You can bypass this default behavior by handling the exceptions yourself,
  1.2018 +      using a code block <tt>try { ... } catch() { ... }</tt>.
  1.2019 +      In this case, you can avoid the apparition of the modal window, by
  1.2020 +      defining the environment variable <tt>cimg_debug</tt> to 0 before including the %CImg header file.
  1.2021 +      The example below shows how to cleanly handle %CImg Library exceptions :
  1.2022 +      \code
  1.2023 +      #define cimg_debug 0     // Disable modal window in CImg exceptions.
  1.2024 +      #define "CImg.h"
  1.2025 +      int main() {
  1.2026 +        try {
  1.2027 +          ...; // Here, do what you want.
  1.2028 +        }
  1.2029 +        catch (CImgInstanceException &e) {
  1.2030 +          std::fprintf(stderr,"CImg Library Error : %s",e.message);  // Display your own error message
  1.2031 +          ...                                                        // Do what you want now.
  1.2032 +        }
  1.2033 +      }
  1.2034 +      \endcode
  1.2035 +  **/
  1.2036 +  struct CImgException {
  1.2037 +#define _cimg_exception_err(etype,disp_flag) \
  1.2038 +  cimg_std::va_list ap; va_start(ap,format); cimg_std::vsprintf(message,format,ap); va_end(ap); \
  1.2039 +  switch (cimg::exception_mode()) { \
  1.2040 +  case 0 : break; \
  1.2041 +  case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
  1.2042 +    cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
  1.2043 +  } break; \
  1.2044 +  default : cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
  1.2045 +  } \
  1.2046 +  if (cimg::exception_mode()>=3) cimg_library::cimg::info();
  1.2047 +
  1.2048 +    char message[1024]; //!< Message associated with the error that thrown the exception.
  1.2049 +    CImgException() { message[0]='\0'; }
  1.2050 +    CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
  1.2051 +  };
  1.2052 +
  1.2053 +  // The \ref CImgInstanceException class is used to throw an exception related
  1.2054 +  // to a non suitable instance encountered in a library function call.
  1.2055 +  struct CImgInstanceException: public CImgException {
  1.2056 +    CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
  1.2057 +  };
  1.2058 +
  1.2059 +  // The \ref CImgArgumentException class is used to throw an exception related
  1.2060 +  // to invalid arguments encountered in a library function call.
  1.2061 +  struct CImgArgumentException: public CImgException {
  1.2062 +    CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
  1.2063 +  };
  1.2064 +
  1.2065 +  // The \ref CImgIOException class is used to throw an exception related
  1.2066 +  // to Input/Output file problems encountered in a library function call.
  1.2067 +  struct CImgIOException: public CImgException {
  1.2068 +    CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
  1.2069 +  };
  1.2070 +
  1.2071 +  // The CImgDisplayException class is used to throw an exception related to display problems
  1.2072 +  // encountered in a library function call.
  1.2073 +  struct CImgDisplayException: public CImgException {
  1.2074 +    CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
  1.2075 +  };
  1.2076 +
  1.2077 +  // The CImgWarningException class is used to throw an exception for warnings
  1.2078 +  // encountered in a library function call.
  1.2079 +  struct CImgWarningException: public CImgException {
  1.2080 +    CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
  1.2081 +  };
  1.2082 +
  1.2083 +  /*-------------------------------------
  1.2084 +   #
  1.2085 +   # Definition of the namespace 'cimg'
  1.2086 +   #
  1.2087 +   --------------------------------------*/
  1.2088 +  //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
  1.2089 +  /**
  1.2090 +     Most of the functions and variables within this namespace are used by the library for low-level processing.
  1.2091 +     Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
  1.2092 +
  1.2093 +     \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
  1.2094 +     <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
  1.2095 +  **/
  1.2096 +  namespace cimg {
  1.2097 +
  1.2098 +    // Define the traits that will be used to determine the best data type to work with.
  1.2099 +    //
  1.2100 +    template<typename T> struct type {
  1.2101 +      static const char* string() {
  1.2102 +        static const char* s[] = { "unknown",   "unknown8",   "unknown16",  "unknown24",
  1.2103 +                                   "unknown32", "unknown40",  "unknown48",  "unknown56",
  1.2104 +                                   "unknown64", "unknown72",  "unknown80",  "unknown88",
  1.2105 +                                   "unknown96", "unknown104", "unknown112", "unknown120",
  1.2106 +                                   "unknown128" };
  1.2107 +        return s[(sizeof(T)<17)?sizeof(T):0];
  1.2108 +      }
  1.2109 +      static bool is_float() { return false; }
  1.2110 +      static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
  1.2111 +      static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
  1.2112 +      static const char* format() { return "%s"; }
  1.2113 +      static const char* format(const T val) { static const char *s = "unknown"; return s; }
  1.2114 +    };
  1.2115 +
  1.2116 +    template<> struct type<bool> {
  1.2117 +      static const char* string() { static const char *const s = "bool"; return s; }
  1.2118 +      static bool is_float() { return false; }
  1.2119 +      static bool min() { return false; }
  1.2120 +      static bool max() { return true; }
  1.2121 +      static const char* format() { return "%s"; }
  1.2122 +      static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
  1.2123 +    };
  1.2124 +
  1.2125 +    template<> struct type<unsigned char> {
  1.2126 +      static const char* string() { static const char *const s = "unsigned char"; return s; }
  1.2127 +      static bool is_float() { return false; }
  1.2128 +      static unsigned char min() { return 0; }
  1.2129 +      static unsigned char max() { return (unsigned char)~0U; }
  1.2130 +      static const char* format() { return "%u"; }
  1.2131 +      static unsigned int format(const unsigned char val) { return (unsigned int)val; }
  1.2132 +    };
  1.2133 +
  1.2134 +    template<> struct type<char> {
  1.2135 +      static const char* string() { static const char *const s = "char"; return s; }
  1.2136 +      static bool is_float() { return false; }
  1.2137 +      static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
  1.2138 +      static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
  1.2139 +      static const char* format() { return "%d"; }
  1.2140 +      static int format(const char val) { return (int)val; }
  1.2141 +    };
  1.2142 +
  1.2143 +    template<> struct type<signed char> {
  1.2144 +      static const char* string() { static const char *const s = "signed char"; return s; }
  1.2145 +      static bool is_float() { return false; }
  1.2146 +      static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
  1.2147 +      static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
  1.2148 +      static const char* format() { return "%d"; }
  1.2149 +      static unsigned int format(const signed char val) { return (int)val; }
  1.2150 +    };
  1.2151 +
  1.2152 +    template<> struct type<unsigned short> {
  1.2153 +      static const char* string() { static const char *const s = "unsigned short"; return s; }
  1.2154 +      static bool is_float() { return false; }
  1.2155 +      static unsigned short min() { return 0; }
  1.2156 +      static unsigned short max() { return (unsigned short)~0U; }
  1.2157 +      static const char* format() { return "%u"; }
  1.2158 +      static unsigned int format(const unsigned short val) { return (unsigned int)val; }
  1.2159 +    };
  1.2160 +
  1.2161 +    template<> struct type<short> {
  1.2162 +      static const char* string() { static const char *const s = "short"; return s; }
  1.2163 +      static bool is_float() { return false; }
  1.2164 +      static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
  1.2165 +      static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
  1.2166 +      static const char* format() { return "%d"; }
  1.2167 +      static int format(const short val) { return (int)val; }
  1.2168 +    };
  1.2169 +
  1.2170 +    template<> struct type<unsigned int> {
  1.2171 +      static const char* string() { static const char *const s = "unsigned int"; return s; }
  1.2172 +      static bool is_float() { return false; }
  1.2173 +      static unsigned int min() { return 0; }
  1.2174 +      static unsigned int max() { return (unsigned int)~0U; }
  1.2175 +      static const char* format() { return "%u"; }
  1.2176 +      static unsigned int format(const unsigned int val) { return val; }
  1.2177 +    };
  1.2178 +
  1.2179 +    template<> struct type<int> {
  1.2180 +      static const char* string() { static const char *const s = "int"; return s; }
  1.2181 +      static bool is_float() { return false; }
  1.2182 +      static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
  1.2183 +      static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
  1.2184 +      static const char* format() { return "%d"; }
  1.2185 +      static int format(const int val) { return val; }
  1.2186 +    };
  1.2187 +
  1.2188 +    template<> struct type<unsigned long> {
  1.2189 +      static const char* string() { static const char *const s = "unsigned long"; return s; }
  1.2190 +      static bool is_float() { return false; }
  1.2191 +      static unsigned long min() { return 0; }
  1.2192 +      static unsigned long max() { return (unsigned long)~0UL; }
  1.2193 +      static const char* format() { return "%lu"; }
  1.2194 +      static unsigned long format(const unsigned long val) { return val; }
  1.2195 +    };
  1.2196 +
  1.2197 +    template<> struct type<long> {
  1.2198 +      static const char* string() { static const char *const s = "long"; return s; }
  1.2199 +      static bool is_float() { return false; }
  1.2200 +      static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
  1.2201 +      static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
  1.2202 +      static const char* format() { return "%ld"; }
  1.2203 +      static long format(const long val) { return val; }
  1.2204 +    };
  1.2205 +
  1.2206 +    template<> struct type<float> {
  1.2207 +      static const char* string() { static const char *const s = "float"; return s; }
  1.2208 +      static bool is_float() { return true; }
  1.2209 +      static float min() { return -3.4E38f; }
  1.2210 +      static float max() { return  3.4E38f; }
  1.2211 +      static const char* format() { return "%g"; }
  1.2212 +      static double format(const float val) { return (double)val; }
  1.2213 +    };
  1.2214 +
  1.2215 +    template<> struct type<double> {
  1.2216 +      static const char* string() { static const char *const s = "double"; return s; }
  1.2217 +      static bool is_float() { return true; }
  1.2218 +      static double min() { return -1.7E308; }
  1.2219 +      static double max() { return  1.7E308; }
  1.2220 +      static const char* format() { return "%g"; }
  1.2221 +      static double format(const double val) { return val; }
  1.2222 +    };
  1.2223 +
  1.2224 +    template<typename T, typename t> struct superset { typedef T type; };
  1.2225 +    template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
  1.2226 +    template<> struct superset<bool,char> { typedef char type; };
  1.2227 +    template<> struct superset<bool,signed char> { typedef signed char type; };
  1.2228 +    template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
  1.2229 +    template<> struct superset<bool,short> { typedef short type; };
  1.2230 +    template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
  1.2231 +    template<> struct superset<bool,int> { typedef int type; };
  1.2232 +    template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
  1.2233 +    template<> struct superset<bool,long> { typedef long type; };
  1.2234 +    template<> struct superset<bool,float> { typedef float type; };
  1.2235 +    template<> struct superset<bool,double> { typedef double type; };
  1.2236 +    template<> struct superset<unsigned char,char> { typedef short type; };
  1.2237 +    template<> struct superset<unsigned char,signed char> { typedef short type; };
  1.2238 +    template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
  1.2239 +    template<> struct superset<unsigned char,short> { typedef short type; };
  1.2240 +    template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
  1.2241 +    template<> struct superset<unsigned char,int> { typedef int type; };
  1.2242 +    template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
  1.2243 +    template<> struct superset<unsigned char,long> { typedef long type; };
  1.2244 +    template<> struct superset<unsigned char,float> { typedef float type; };
  1.2245 +    template<> struct superset<unsigned char,double> { typedef double type; };
  1.2246 +    template<> struct superset<signed char,unsigned char> { typedef short type; };
  1.2247 +    template<> struct superset<signed char,char> { typedef short type; };
  1.2248 +    template<> struct superset<signed char,unsigned short> { typedef int type; };
  1.2249 +    template<> struct superset<signed char,short> { typedef short type; };
  1.2250 +    template<> struct superset<signed char,unsigned int> { typedef long type; };
  1.2251 +    template<> struct superset<signed char,int> { typedef int type; };
  1.2252 +    template<> struct superset<signed char,unsigned long> { typedef long type; };
  1.2253 +    template<> struct superset<signed char,long> { typedef long type; };
  1.2254 +    template<> struct superset<signed char,float> { typedef float type; };
  1.2255 +    template<> struct superset<signed char,double> { typedef double type; };
  1.2256 +    template<> struct superset<char,unsigned char> { typedef short type; };
  1.2257 +    template<> struct superset<char,signed char> { typedef short type; };
  1.2258 +    template<> struct superset<char,unsigned short> { typedef int type; };
  1.2259 +    template<> struct superset<char,short> { typedef short type; };
  1.2260 +    template<> struct superset<char,unsigned int> { typedef long type; };
  1.2261 +    template<> struct superset<char,int> { typedef int type; };
  1.2262 +    template<> struct superset<char,unsigned long> { typedef long type; };
  1.2263 +    template<> struct superset<char,long> { typedef long type; };
  1.2264 +    template<> struct superset<char,float> { typedef float type; };
  1.2265 +    template<> struct superset<char,double> { typedef double type; };
  1.2266 +    template<> struct superset<unsigned short,char> { typedef int type; };
  1.2267 +    template<> struct superset<unsigned short,signed char> { typedef int type; };
  1.2268 +    template<> struct superset<unsigned short,short> { typedef int type; };
  1.2269 +    template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
  1.2270 +    template<> struct superset<unsigned short,int> { typedef int type; };
  1.2271 +    template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
  1.2272 +    template<> struct superset<unsigned short,long> { typedef long type; };
  1.2273 +    template<> struct superset<unsigned short,float> { typedef float type; };
  1.2274 +    template<> struct superset<unsigned short,double> { typedef double type; };
  1.2275 +    template<> struct superset<short,unsigned short> { typedef int type; };
  1.2276 +    template<> struct superset<short,unsigned int> { typedef long type; };
  1.2277 +    template<> struct superset<short,int> { typedef int type; };
  1.2278 +    template<> struct superset<short,unsigned long> { typedef long type; };
  1.2279 +    template<> struct superset<short,long> { typedef long type; };
  1.2280 +    template<> struct superset<short,float> { typedef float type; };
  1.2281 +    template<> struct superset<short,double> { typedef double type; };
  1.2282 +    template<> struct superset<unsigned int,char> { typedef long type; };
  1.2283 +    template<> struct superset<unsigned int,signed char> { typedef long type; };
  1.2284 +    template<> struct superset<unsigned int,short> { typedef long type; };
  1.2285 +    template<> struct superset<unsigned int,int> { typedef long type; };
  1.2286 +    template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
  1.2287 +    template<> struct superset<unsigned int,long> { typedef long type; };
  1.2288 +    template<> struct superset<unsigned int,float> { typedef float type; };
  1.2289 +    template<> struct superset<unsigned int,double> { typedef double type; };
  1.2290 +    template<> struct superset<int,unsigned int> { typedef long type; };
  1.2291 +    template<> struct superset<int,unsigned long> { typedef long type; };
  1.2292 +    template<> struct superset<int,long> { typedef long type; };
  1.2293 +    template<> struct superset<int,float> { typedef float type; };
  1.2294 +    template<> struct superset<int,double> { typedef double type; };
  1.2295 +    template<> struct superset<unsigned long,char> { typedef long type; };
  1.2296 +    template<> struct superset<unsigned long,signed char> { typedef long type; };
  1.2297 +    template<> struct superset<unsigned long,short> { typedef long type; };
  1.2298 +    template<> struct superset<unsigned long,int> { typedef long type; };
  1.2299 +    template<> struct superset<unsigned long,long> { typedef long type; };
  1.2300 +    template<> struct superset<unsigned long,float> { typedef float type; };
  1.2301 +    template<> struct superset<unsigned long,double> { typedef double type; };
  1.2302 +    template<> struct superset<long,float> { typedef float type; };
  1.2303 +    template<> struct superset<long,double> { typedef double type; };
  1.2304 +    template<> struct superset<float,double> { typedef double type; };
  1.2305 +
  1.2306 +    template<typename t1, typename t2, typename t3> struct superset2 {
  1.2307 +      typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
  1.2308 +    };
  1.2309 +
  1.2310 +    template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
  1.2311 +      typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
  1.2312 +    };
  1.2313 +
  1.2314 +    template<typename t1, typename t2> struct last { typedef t2 type; };
  1.2315 +
  1.2316 +#define _cimg_Tuchar  typename cimg::superset<T,unsigned char>::type
  1.2317 +#define _cimg_Tint    typename cimg::superset<T,int>::type
  1.2318 +#define _cimg_Tfloat  typename cimg::superset<T,float>::type
  1.2319 +#define _cimg_Tdouble typename cimg::superset<T,double>::type
  1.2320 +#define _cimg_Tt      typename cimg::superset<T,t>::type
  1.2321 +
  1.2322 +    // Define internal library variables.
  1.2323 +    //
  1.2324 +#if cimg_display==1
  1.2325 +    struct X11info {
  1.2326 +      volatile unsigned int nb_wins;
  1.2327 +      pthread_t*       event_thread;
  1.2328 +      CImgDisplay*     wins[1024];
  1.2329 +      Display*         display;
  1.2330 +      unsigned int     nb_bits;
  1.2331 +      GC*              gc;
  1.2332 +      bool             blue_first;
  1.2333 +      bool             byte_order;
  1.2334 +      bool             shm_enabled;
  1.2335 +#ifdef cimg_use_xrandr
  1.2336 +      XRRScreenSize *resolutions;
  1.2337 +      Rotation curr_rotation;
  1.2338 +      unsigned int curr_resolution;
  1.2339 +      unsigned int nb_resolutions;
  1.2340 +#endif
  1.2341 +      X11info():nb_wins(0),event_thread(0),display(0),
  1.2342 +                nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
  1.2343 +#ifdef cimg_use_xrandr
  1.2344 +        resolutions = 0;
  1.2345 +        curr_rotation = 0;
  1.2346 +        curr_resolution = nb_resolutions = 0;
  1.2347 +#endif
  1.2348 +      }
  1.2349 +    };
  1.2350 +#if defined(cimg_module)
  1.2351 +    X11info& X11attr();
  1.2352 +#elif defined(cimg_main)
  1.2353 +    X11info& X11attr() { static X11info val; return val; }
  1.2354 +#else
  1.2355 +    inline X11info& X11attr() { static X11info val; return val; }
  1.2356 +#endif
  1.2357 +
  1.2358 +#elif cimg_display==2
  1.2359 +    struct Win32info {
  1.2360 +      HANDLE wait_event;
  1.2361 +      Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
  1.2362 +    };
  1.2363 +#if defined(cimg_module)
  1.2364 +    Win32info& Win32attr();
  1.2365 +#elif defined(cimg_main)
  1.2366 +    Win32info& Win32attr() { static Win32info val; return val; }
  1.2367 +#else
  1.2368 +    inline Win32info& Win32attr() { static Win32info val; return val; }
  1.2369 +#endif
  1.2370 +
  1.2371 +#elif cimg_display==3
  1.2372 +    struct CarbonInfo {
  1.2373 +      MPCriticalRegionID windowListCR; // Protects access to the list of windows
  1.2374 +      int windowCount;                 // Count of displays used on the screen
  1.2375 +      pthread_t event_thread;          // The background event thread
  1.2376 +      MPSemaphoreID sync_event;        // Event used to perform tasks synchronizations
  1.2377 +      MPSemaphoreID wait_event;        // Event used to notify that new events occured on the display
  1.2378 +      MPQueueID com_queue;             // The message queue
  1.2379 +      CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
  1.2380 +        if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
  1.2381 +          throw CImgDisplayException("MPCreateCriticalRegion failed.");
  1.2382 +        if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
  1.2383 +          throw CImgDisplayException("MPCreateSemaphore failed.");
  1.2384 +        if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
  1.2385 +          throw CImgDisplayException("MPCreateSemaphore failed.");
  1.2386 +        if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
  1.2387 +          throw CImgDisplayException("MPCreateQueue failed.");
  1.2388 +      }
  1.2389 +      ~CarbonInfo() {
  1.2390 +        if (event_thread != 0) { // Terminates the resident thread, if needed
  1.2391 +          pthread_cancel(event_thread);
  1.2392 +          pthread_join(event_thread, NULL);
  1.2393 +          event_thread = 0;
  1.2394 +        }
  1.2395 +        if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
  1.2396 +          throw CImgDisplayException("MPDeleteCriticalRegion failed.");
  1.2397 +        if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
  1.2398 +          throw CImgDisplayException("MPDeleteEvent failed.");
  1.2399 +        if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
  1.2400 +          throw CImgDisplayException("MPDeleteEvent failed.");
  1.2401 +        if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
  1.2402 +          throw CImgDisplayException("MPDeleteQueue failed.");
  1.2403 +      }
  1.2404 +    };
  1.2405 +#if defined(cimg_module)
  1.2406 +    CarbonInfo& CarbonAttr();
  1.2407 +#elif defined(cimg_main)
  1.2408 +    CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
  1.2409 +#else
  1.2410 +    inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
  1.2411 +#endif
  1.2412 +#endif
  1.2413 +
  1.2414 +#if cimg_display==1
  1.2415 +    // Keycodes for X11-based graphical systems.
  1.2416 +    //
  1.2417 +    const unsigned int keyESC        = XK_Escape;
  1.2418 +    const unsigned int keyF1         = XK_F1;
  1.2419 +    const unsigned int keyF2         = XK_F2;
  1.2420 +    const unsigned int keyF3         = XK_F3;
  1.2421 +    const unsigned int keyF4         = XK_F4;
  1.2422 +    const unsigned int keyF5         = XK_F5;
  1.2423 +    const unsigned int keyF6         = XK_F6;
  1.2424 +    const unsigned int keyF7         = XK_F7;
  1.2425 +    const unsigned int keyF8         = XK_F8;
  1.2426 +    const unsigned int keyF9         = XK_F9;
  1.2427 +    const unsigned int keyF10        = XK_F10;
  1.2428 +    const unsigned int keyF11        = XK_F11;
  1.2429 +    const unsigned int keyF12        = XK_F12;
  1.2430 +    const unsigned int keyPAUSE      = XK_Pause;
  1.2431 +    const unsigned int key1          = XK_1;
  1.2432 +    const unsigned int key2          = XK_2;
  1.2433 +    const unsigned int key3          = XK_3;
  1.2434 +    const unsigned int key4          = XK_4;
  1.2435 +    const unsigned int key5          = XK_5;
  1.2436 +    const unsigned int key6          = XK_6;
  1.2437 +    const unsigned int key7          = XK_7;
  1.2438 +    const unsigned int key8          = XK_8;
  1.2439 +    const unsigned int key9          = XK_9;
  1.2440 +    const unsigned int key0          = XK_0;
  1.2441 +    const unsigned int keyBACKSPACE  = XK_BackSpace;
  1.2442 +    const unsigned int keyINSERT     = XK_Insert;
  1.2443 +    const unsigned int keyHOME       = XK_Home;
  1.2444 +    const unsigned int keyPAGEUP     = XK_Page_Up;
  1.2445 +    const unsigned int keyTAB        = XK_Tab;
  1.2446 +    const unsigned int keyQ          = XK_q;
  1.2447 +    const unsigned int keyW          = XK_w;
  1.2448 +    const unsigned int keyE          = XK_e;
  1.2449 +    const unsigned int keyR          = XK_r;
  1.2450 +    const unsigned int keyT          = XK_t;
  1.2451 +    const unsigned int keyY          = XK_y;
  1.2452 +    const unsigned int keyU          = XK_u;
  1.2453 +    const unsigned int keyI          = XK_i;
  1.2454 +    const unsigned int keyO          = XK_o;
  1.2455 +    const unsigned int keyP          = XK_p;
  1.2456 +    const unsigned int keyDELETE     = XK_Delete;
  1.2457 +    const unsigned int keyEND        = XK_End;
  1.2458 +    const unsigned int keyPAGEDOWN   = XK_Page_Down;
  1.2459 +    const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
  1.2460 +    const unsigned int keyA          = XK_a;
  1.2461 +    const unsigned int keyS          = XK_s;
  1.2462 +    const unsigned int keyD          = XK_d;
  1.2463 +    const unsigned int keyF          = XK_f;
  1.2464 +    const unsigned int keyG          = XK_g;
  1.2465 +    const unsigned int keyH          = XK_h;
  1.2466 +    const unsigned int keyJ          = XK_j;
  1.2467 +    const unsigned int keyK          = XK_k;
  1.2468 +    const unsigned int keyL          = XK_l;
  1.2469 +    const unsigned int keyENTER      = XK_Return;
  1.2470 +    const unsigned int keySHIFTLEFT  = XK_Shift_L;
  1.2471 +    const unsigned int keyZ          = XK_z;
  1.2472 +    const unsigned int keyX          = XK_x;
  1.2473 +    const unsigned int keyC          = XK_c;
  1.2474 +    const unsigned int keyV          = XK_v;
  1.2475 +    const unsigned int keyB          = XK_b;
  1.2476 +    const unsigned int keyN          = XK_n;
  1.2477 +    const unsigned int keyM          = XK_m;
  1.2478 +    const unsigned int keySHIFTRIGHT = XK_Shift_R;
  1.2479 +    const unsigned int keyARROWUP    = XK_Up;
  1.2480 +    const unsigned int keyCTRLLEFT   = XK_Control_L;
  1.2481 +    const unsigned int keyAPPLEFT    = XK_Super_L;
  1.2482 +    const unsigned int keyALT        = XK_Alt_L;
  1.2483 +    const unsigned int keySPACE      = XK_space;
  1.2484 +    const unsigned int keyALTGR      = XK_Alt_R;
  1.2485 +    const unsigned int keyAPPRIGHT   = XK_Super_R;
  1.2486 +    const unsigned int keyMENU       = XK_Menu;
  1.2487 +    const unsigned int keyCTRLRIGHT  = XK_Control_R;
  1.2488 +    const unsigned int keyARROWLEFT  = XK_Left;
  1.2489 +    const unsigned int keyARROWDOWN  = XK_Down;
  1.2490 +    const unsigned int keyARROWRIGHT = XK_Right;
  1.2491 +    const unsigned int keyPAD0       = XK_KP_0;
  1.2492 +    const unsigned int keyPAD1       = XK_KP_1;
  1.2493 +    const unsigned int keyPAD2       = XK_KP_2;
  1.2494 +    const unsigned int keyPAD3       = XK_KP_3;
  1.2495 +    const unsigned int keyPAD4       = XK_KP_4;
  1.2496 +    const unsigned int keyPAD5       = XK_KP_5;
  1.2497 +    const unsigned int keyPAD6       = XK_KP_6;
  1.2498 +    const unsigned int keyPAD7       = XK_KP_7;
  1.2499 +    const unsigned int keyPAD8       = XK_KP_8;
  1.2500 +    const unsigned int keyPAD9       = XK_KP_9;
  1.2501 +    const unsigned int keyPADADD     = XK_KP_Add;
  1.2502 +    const unsigned int keyPADSUB     = XK_KP_Subtract;
  1.2503 +    const unsigned int keyPADMUL     = XK_KP_Multiply;
  1.2504 +    const unsigned int keyPADDIV     = XK_KP_Divide;
  1.2505 +
  1.2506 +#elif cimg_display==2
  1.2507 +    // Keycodes for Windows.
  1.2508 +    //
  1.2509 +    const unsigned int keyESC        = VK_ESCAPE;
  1.2510 +    const unsigned int keyF1         = VK_F1;
  1.2511 +    const unsigned int keyF2         = VK_F2;
  1.2512 +    const unsigned int keyF3         = VK_F3;
  1.2513 +    const unsigned int keyF4         = VK_F4;
  1.2514 +    const unsigned int keyF5         = VK_F5;
  1.2515 +    const unsigned int keyF6         = VK_F6;
  1.2516 +    const unsigned int keyF7         = VK_F7;
  1.2517 +    const unsigned int keyF8         = VK_F8;
  1.2518 +    const unsigned int keyF9         = VK_F9;
  1.2519 +    const unsigned int keyF10        = VK_F10;
  1.2520 +    const unsigned int keyF11        = VK_F11;
  1.2521 +    const unsigned int keyF12        = VK_F12;
  1.2522 +    const unsigned int keyPAUSE      = VK_PAUSE;
  1.2523 +    const unsigned int key1          = '1';
  1.2524 +    const unsigned int key2          = '2';
  1.2525 +    const unsigned int key3          = '3';
  1.2526 +    const unsigned int key4          = '4';
  1.2527 +    const unsigned int key5          = '5';
  1.2528 +    const unsigned int key6          = '6';
  1.2529 +    const unsigned int key7          = '7';
  1.2530 +    const unsigned int key8          = '8';
  1.2531 +    const unsigned int key9          = '9';
  1.2532 +    const unsigned int key0          = '0';
  1.2533 +    const unsigned int keyBACKSPACE  = VK_BACK;
  1.2534 +    const unsigned int keyINSERT     = VK_INSERT;
  1.2535 +    const unsigned int keyHOME       = VK_HOME;
  1.2536 +    const unsigned int keyPAGEUP     = VK_PRIOR;
  1.2537 +    const unsigned int keyTAB        = VK_TAB;
  1.2538 +    const unsigned int keyQ          = 'Q';
  1.2539 +    const unsigned int keyW          = 'W';
  1.2540 +    const unsigned int keyE          = 'E';
  1.2541 +    const unsigned int keyR          = 'R';
  1.2542 +    const unsigned int keyT          = 'T';
  1.2543 +    const unsigned int keyY          = 'Y';
  1.2544 +    const unsigned int keyU          = 'U';
  1.2545 +    const unsigned int keyI          = 'I';
  1.2546 +    const unsigned int keyO          = 'O';
  1.2547 +    const unsigned int keyP          = 'P';
  1.2548 +    const unsigned int keyDELETE     = VK_DELETE;
  1.2549 +    const unsigned int keyEND        = VK_END;
  1.2550 +    const unsigned int keyPAGEDOWN   = VK_NEXT;
  1.2551 +    const unsigned int keyCAPSLOCK   = VK_CAPITAL;
  1.2552 +    const unsigned int keyA          = 'A';
  1.2553 +    const unsigned int keyS          = 'S';
  1.2554 +    const unsigned int keyD          = 'D';
  1.2555 +    const unsigned int keyF          = 'F';
  1.2556 +    const unsigned int keyG          = 'G';
  1.2557 +    const unsigned int keyH          = 'H';
  1.2558 +    const unsigned int keyJ          = 'J';
  1.2559 +    const unsigned int keyK          = 'K';
  1.2560 +    const unsigned int keyL          = 'L';
  1.2561 +    const unsigned int keyENTER      = VK_RETURN;
  1.2562 +    const unsigned int keySHIFTLEFT  = VK_SHIFT;
  1.2563 +    const unsigned int keyZ          = 'Z';
  1.2564 +    const unsigned int keyX          = 'X';
  1.2565 +    const unsigned int keyC          = 'C';
  1.2566 +    const unsigned int keyV          = 'V';
  1.2567 +    const unsigned int keyB          = 'B';
  1.2568 +    const unsigned int keyN          = 'N';
  1.2569 +    const unsigned int keyM          = 'M';
  1.2570 +    const unsigned int keySHIFTRIGHT = VK_SHIFT;
  1.2571 +    const unsigned int keyARROWUP    = VK_UP;
  1.2572 +    const unsigned int keyCTRLLEFT   = VK_CONTROL;
  1.2573 +    const unsigned int keyAPPLEFT    = VK_LWIN;
  1.2574 +    const unsigned int keyALT        = VK_LMENU;
  1.2575 +    const unsigned int keySPACE      = VK_SPACE;
  1.2576 +    const unsigned int keyALTGR      = VK_CONTROL;
  1.2577 +    const unsigned int keyAPPRIGHT   = VK_RWIN;
  1.2578 +    const unsigned int keyMENU       = VK_APPS;
  1.2579 +    const unsigned int keyCTRLRIGHT  = VK_CONTROL;
  1.2580 +    const unsigned int keyARROWLEFT  = VK_LEFT;
  1.2581 +    const unsigned int keyARROWDOWN  = VK_DOWN;
  1.2582 +    const unsigned int keyARROWRIGHT = VK_RIGHT;
  1.2583 +    const unsigned int keyPAD0       = 0x60;
  1.2584 +    const unsigned int keyPAD1       = 0x61;
  1.2585 +    const unsigned int keyPAD2       = 0x62;
  1.2586 +    const unsigned int keyPAD3       = 0x63;
  1.2587 +    const unsigned int keyPAD4       = 0x64;
  1.2588 +    const unsigned int keyPAD5       = 0x65;
  1.2589 +    const unsigned int keyPAD6       = 0x66;
  1.2590 +    const unsigned int keyPAD7       = 0x67;
  1.2591 +    const unsigned int keyPAD8       = 0x68;
  1.2592 +    const unsigned int keyPAD9       = 0x69;
  1.2593 +    const unsigned int keyPADADD     = VK_ADD;
  1.2594 +    const unsigned int keyPADSUB     = VK_SUBTRACT;
  1.2595 +    const unsigned int keyPADMUL     = VK_MULTIPLY;
  1.2596 +    const unsigned int keyPADDIV     = VK_DIVIDE;
  1.2597 +
  1.2598 +#elif cimg_display==3
  1.2599 +    // Keycodes for MacOSX, when using the Carbon framework.
  1.2600 +    //
  1.2601 +    const unsigned int keyESC        = kEscapeCharCode;
  1.2602 +    const unsigned int keyF1         = 2U;
  1.2603 +    const unsigned int keyF2         = 3U;
  1.2604 +    const unsigned int keyF3         = 4U;
  1.2605 +    const unsigned int keyF4         = 5U;
  1.2606 +    const unsigned int keyF5         = 6U;
  1.2607 +    const unsigned int keyF6         = 7U;
  1.2608 +    const unsigned int keyF7         = 8U;
  1.2609 +    const unsigned int keyF8         = 9U;
  1.2610 +    const unsigned int keyF9         = 10U;
  1.2611 +    const unsigned int keyF10        = 11U;
  1.2612 +    const unsigned int keyF11        = 12U;
  1.2613 +    const unsigned int keyF12        = 13U;
  1.2614 +    const unsigned int keyPAUSE      = 14U;
  1.2615 +    const unsigned int key1          = '1';
  1.2616 +    const unsigned int key2          = '2';
  1.2617 +    const unsigned int key3          = '3';
  1.2618 +    const unsigned int key4          = '4';
  1.2619 +    const unsigned int key5          = '5';
  1.2620 +    const unsigned int key6          = '6';
  1.2621 +    const unsigned int key7          = '7';
  1.2622 +    const unsigned int key8          = '8';
  1.2623 +    const unsigned int key9          = '9';
  1.2624 +    const unsigned int key0          = '0';
  1.2625 +    const unsigned int keyBACKSPACE  = kBackspaceCharCode;
  1.2626 +    const unsigned int keyINSERT     = 26U;
  1.2627 +    const unsigned int keyHOME       = kHomeCharCode;
  1.2628 +    const unsigned int keyPAGEUP     = kPageUpCharCode;
  1.2629 +    const unsigned int keyTAB        = kTabCharCode;
  1.2630 +    const unsigned int keyQ          = 'q';
  1.2631 +    const unsigned int keyW          = 'w';
  1.2632 +    const unsigned int keyE          = 'e';
  1.2633 +    const unsigned int keyR          = 'r';
  1.2634 +    const unsigned int keyT          = 't';
  1.2635 +    const unsigned int keyY          = 'y';
  1.2636 +    const unsigned int keyU          = 'u';
  1.2637 +    const unsigned int keyI          = 'i';
  1.2638 +    const unsigned int keyO          = 'o';
  1.2639 +    const unsigned int keyP          = 'p';
  1.2640 +    const unsigned int keyDELETE     = kDeleteCharCode;
  1.2641 +    const unsigned int keyEND        = kEndCharCode;
  1.2642 +    const unsigned int keyPAGEDOWN   = kPageDownCharCode;
  1.2643 +    const unsigned int keyCAPSLOCK   = 43U;
  1.2644 +    const unsigned int keyA          = 'a';
  1.2645 +    const unsigned int keyS          = 's';
  1.2646 +    const unsigned int keyD          = 'd';
  1.2647 +    const unsigned int keyF          = 'f';
  1.2648 +    const unsigned int keyG          = 'g';
  1.2649 +    const unsigned int keyH          = 'h';
  1.2650 +    const unsigned int keyJ          = 'j';
  1.2651 +    const unsigned int keyK          = 'k';
  1.2652 +    const unsigned int keyL          = 'l';
  1.2653 +    const unsigned int keyENTER      = kEnterCharCode;
  1.2654 +    const unsigned int keySHIFTLEFT  = 54U; //Macintosh modifier key, emulated
  1.2655 +    const unsigned int keyZ          = 'z';
  1.2656 +    const unsigned int keyX          = 'x';
  1.2657 +    const unsigned int keyC          = 'c';
  1.2658 +    const unsigned int keyV          = 'v';
  1.2659 +    const unsigned int keyB          = 'b';
  1.2660 +    const unsigned int keyN          = 'n';
  1.2661 +    const unsigned int keyM          = 'm';
  1.2662 +    const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
  1.2663 +    const unsigned int keyARROWUP    = kUpArrowCharCode;
  1.2664 +    const unsigned int keyCTRLLEFT   = 64U; //Macintosh modifier key, emulated
  1.2665 +    const unsigned int keyAPPLEFT    = 65U; //Macintosh modifier key, emulated
  1.2666 +    const unsigned int keyALT        = 66U;
  1.2667 +    const unsigned int keySPACE      = kSpaceCharCode;
  1.2668 +    const unsigned int keyALTGR      = 67U; //Macintosh modifier key, emulated
  1.2669 +    const unsigned int keyAPPRIGHT   = 68U; //Aliased on keyAPPLEFT
  1.2670 +    const unsigned int keyMENU       = 69U;
  1.2671 +    const unsigned int keyCTRLRIGHT  = 70U; //Macintosh modifier key, emulated
  1.2672 +    const unsigned int keyARROWLEFT  = kLeftArrowCharCode;
  1.2673 +    const unsigned int keyARROWDOWN  = kDownArrowCharCode;
  1.2674 +    const unsigned int keyARROWRIGHT = kRightArrowCharCode;
  1.2675 +    const unsigned int keyPAD0       = 74U;
  1.2676 +    const unsigned int keyPAD1       = 75U;
  1.2677 +    const unsigned int keyPAD2       = 76U;
  1.2678 +    const unsigned int keyPAD3       = 77U;
  1.2679 +    const unsigned int keyPAD4       = 78U;
  1.2680 +    const unsigned int keyPAD5       = 79U;
  1.2681 +    const unsigned int keyPAD6       = 80U;
  1.2682 +    const unsigned int keyPAD7       = 81U;
  1.2683 +    const unsigned int keyPAD8       = 82U;
  1.2684 +    const unsigned int keyPAD9       = 83U;
  1.2685 +    const unsigned int keyPADADD     = 84U;
  1.2686 +    const unsigned int keyPADSUB     = 85U;
  1.2687 +    const unsigned int keyPADMUL     = 86U;
  1.2688 +    const unsigned int keyPADDIV     = 87U;
  1.2689 +
  1.2690 +#else
  1.2691 +    // Define unknow keycodes when no display are available.
  1.2692 +    // (should rarely be used then !).
  1.2693 +    //
  1.2694 +    const unsigned int keyESC        = 1U;
  1.2695 +    const unsigned int keyF1         = 2U;
  1.2696 +    const unsigned int keyF2         = 3U;
  1.2697 +    const unsigned int keyF3         = 4U;
  1.2698 +    const unsigned int keyF4         = 5U;
  1.2699 +    const unsigned int keyF5         = 6U;
  1.2700 +    const unsigned int keyF6         = 7U;
  1.2701 +    const unsigned int keyF7         = 8U;
  1.2702 +    const unsigned int keyF8         = 9U;
  1.2703 +    const unsigned int keyF9         = 10U;
  1.2704 +    const unsigned int keyF10        = 11U;
  1.2705 +    const unsigned int keyF11        = 12U;
  1.2706 +    const unsigned int keyF12        = 13U;
  1.2707 +    const unsigned int keyPAUSE      = 14U;
  1.2708 +    const unsigned int key1          = 15U;
  1.2709 +    const unsigned int key2          = 16U;
  1.2710 +    const unsigned int key3          = 17U;
  1.2711 +    const unsigned int key4          = 18U;
  1.2712 +    const unsigned int key5          = 19U;
  1.2713 +    const unsigned int key6          = 20U;
  1.2714 +    const unsigned int key7          = 21U;
  1.2715 +    const unsigned int key8          = 22U;
  1.2716 +    const unsigned int key9          = 23U;
  1.2717 +    const unsigned int key0          = 24U;
  1.2718 +    const unsigned int keyBACKSPACE  = 25U;
  1.2719 +    const unsigned int keyINSERT     = 26U;
  1.2720 +    const unsigned int keyHOME       = 27U;
  1.2721 +    const unsigned int keyPAGEUP     = 28U;
  1.2722 +    const unsigned int keyTAB        = 29U;
  1.2723 +    const unsigned int keyQ          = 30U;
  1.2724 +    const unsigned int keyW          = 31U;
  1.2725 +    const unsigned int keyE          = 32U;
  1.2726 +    const unsigned int keyR          = 33U;
  1.2727 +    const unsigned int keyT          = 34U;
  1.2728 +    const unsigned int keyY          = 35U;
  1.2729 +    const unsigned int keyU          = 36U;
  1.2730 +    const unsigned int keyI          = 37U;
  1.2731 +    const unsigned int keyO          = 38U;
  1.2732 +    const unsigned int keyP          = 39U;
  1.2733 +    const unsigned int keyDELETE     = 40U;
  1.2734 +    const unsigned int keyEND        = 41U;
  1.2735 +    const unsigned int keyPAGEDOWN   = 42U;
  1.2736 +    const unsigned int keyCAPSLOCK   = 43U;
  1.2737 +    const unsigned int keyA          = 44U;
  1.2738 +    const unsigned int keyS          = 45U;
  1.2739 +    const unsigned int keyD          = 46U;
  1.2740 +    const unsigned int keyF          = 47U;
  1.2741 +    const unsigned int keyG          = 48U;
  1.2742 +    const unsigned int keyH          = 49U;
  1.2743 +    const unsigned int keyJ          = 50U;
  1.2744 +    const unsigned int keyK          = 51U;
  1.2745 +    const unsigned int keyL          = 52U;
  1.2746 +    const unsigned int keyENTER      = 53U;
  1.2747 +    const unsigned int keySHIFTLEFT  = 54U;
  1.2748 +    const unsigned int keyZ          = 55U;
  1.2749 +    const unsigned int keyX          = 56U;
  1.2750 +    const unsigned int keyC          = 57U;
  1.2751 +    const unsigned int keyV          = 58U;
  1.2752 +    const unsigned int keyB          = 59U;
  1.2753 +    const unsigned int keyN          = 60U;
  1.2754 +    const unsigned int keyM          = 61U;
  1.2755 +    const unsigned int keySHIFTRIGHT = 62U;
  1.2756 +    const unsigned int keyARROWUP    = 63U;
  1.2757 +    const unsigned int keyCTRLLEFT   = 64U;
  1.2758 +    const unsigned int keyAPPLEFT    = 65U;
  1.2759 +    const unsigned int keyALT        = 66U;
  1.2760 +    const unsigned int keySPACE      = 67U;
  1.2761 +    const unsigned int keyALTGR      = 68U;
  1.2762 +    const unsigned int keyAPPRIGHT   = 69U;
  1.2763 +    const unsigned int keyMENU       = 70U;
  1.2764 +    const unsigned int keyCTRLRIGHT  = 71U;
  1.2765 +    const unsigned int keyARROWLEFT  = 72U;
  1.2766 +    const unsigned int keyARROWDOWN  = 73U;
  1.2767 +    const unsigned int keyARROWRIGHT = 74U;
  1.2768 +    const unsigned int keyPAD0       = 75U;
  1.2769 +    const unsigned int keyPAD1       = 76U;
  1.2770 +    const unsigned int keyPAD2       = 77U;
  1.2771 +    const unsigned int keyPAD3       = 78U;
  1.2772 +    const unsigned int keyPAD4       = 79U;
  1.2773 +    const unsigned int keyPAD5       = 80U;
  1.2774 +    const unsigned int keyPAD6       = 81U;
  1.2775 +    const unsigned int keyPAD7       = 82U;
  1.2776 +    const unsigned int keyPAD8       = 83U;
  1.2777 +    const unsigned int keyPAD9       = 84U;
  1.2778 +    const unsigned int keyPADADD     = 85U;
  1.2779 +    const unsigned int keyPADSUB     = 86U;
  1.2780 +    const unsigned int keyPADMUL     = 87U;
  1.2781 +    const unsigned int keyPADDIV     = 88U;
  1.2782 +#endif
  1.2783 +
  1.2784 +    const double valuePI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI
  1.2785 +
  1.2786 +    // Definition of a 7x11 font, used to return a default font for drawing text.
  1.2787 +    const unsigned int font7x11[7*11*256/32] = {
  1.2788 +      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,
  1.2789 +      0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
  1.2790 +      0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
  1.2791 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2792 +      0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
  1.2793 +      0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
  1.2794 +      0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
  1.2795 +      0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
  1.2796 +      0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2797 +      0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
  1.2798 +      0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2799 +      0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
  1.2800 +      0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2801 +      0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
  1.2802 +      0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2803 +      0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
  1.2804 +      0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2805 +      0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
  1.2806 +      0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2807 +      0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
  1.2808 +      0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2809 +      0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
  1.2810 +      0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2811 +      0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
  1.2812 +      0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
  1.2813 +      0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
  1.2814 +      0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
  1.2815 +      0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
  1.2816 +      0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
  1.2817 +      0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
  1.2818 +      0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
  1.2819 +      0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
  1.2820 +      0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
  1.2821 +      0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
  1.2822 +      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,
  1.2823 +      0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2824 +      0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
  1.2825 +    };
  1.2826 +
  1.2827 +    // Definition of a 10x13 font (used in dialog boxes).
  1.2828 +    const unsigned int font10x13[256*10*13/32] = {
  1.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,
  1.2830 +      0x0,0x0,0x0,0x0,0x0,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,
  1.2831 +      0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2832 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2833 +      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,
  1.2834 +      0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2835 +      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,
  1.2836 +      0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2837 +      0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
  1.2838 +      0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
  1.2839 +      0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
  1.2840 +      0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
  1.2841 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
  1.2842 +      0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
  1.2843 +      0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
  1.2844 +      0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
  1.2845 +      0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
  1.2846 +      0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
  1.2847 +      0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
  1.2848 +      0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
  1.2849 +      0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
  1.2850 +      0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
  1.2851 +      0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
  1.2852 +      0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
  1.2853 +      0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
  1.2854 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
  1.2855 +      0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
  1.2856 +      0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2857 +      0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
  1.2858 +      0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
  1.2859 +      0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
  1.2860 +      0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
  1.2861 +      0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
  1.2862 +      0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
  1.2863 +      0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
  1.2864 +      0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
  1.2865 +      0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
  1.2866 +      0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
  1.2867 +      0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2868 +      0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
  1.2869 +      0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
  1.2870 +      0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
  1.2871 +      0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
  1.2872 +      0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
  1.2873 +      0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
  1.2874 +      0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
  1.2875 +      0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
  1.2876 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
  1.2877 +      0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
  1.2878 +      0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
  1.2879 +      0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
  1.2880 +      0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
  1.2881 +      0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
  1.2882 +      0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
  1.2883 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
  1.2884 +      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,
  1.2885 +      0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
  1.2886 +      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,
  1.2887 +      0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
  1.2888 +    };
  1.2889 +
  1.2890 +    // Definition of a 8x17 font.
  1.2891 +    const unsigned int font8x17[8*17*256/32] = {
  1.2892 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2893 +      0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
  1.2894 +      0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
  1.2895 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
  1.2896 +      0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
  1.2897 +      0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
  1.2898 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
  1.2899 +      0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
  1.2900 +      0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
  1.2901 +      0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
  1.2902 +      0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
  1.2903 +      0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
  1.2904 +      0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
  1.2905 +      0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
  1.2906 +      0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
  1.2907 +      0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
  1.2908 +      0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
  1.2909 +      0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
  1.2910 +      0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
  1.2911 +      0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
  1.2912 +      0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
  1.2913 +      0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
  1.2914 +      0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
  1.2915 +      0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
  1.2916 +      0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
  1.2917 +      0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
  1.2918 +      0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
  1.2919 +      0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
  1.2920 +      0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
  1.2921 +      0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
  1.2922 +      0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
  1.2923 +      0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
  1.2924 +      0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
  1.2925 +      0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
  1.2926 +      0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
  1.2927 +      0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
  1.2928 +      0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
  1.2929 +      0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
  1.2930 +      0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
  1.2931 +      0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
  1.2932 +      0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
  1.2933 +      0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
  1.2934 +      0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
  1.2935 +      0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
  1.2936 +      0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
  1.2937 +      0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
  1.2938 +      0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
  1.2939 +      0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
  1.2940 +      0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
  1.2941 +      0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
  1.2942 +      0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
  1.2943 +      0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
  1.2944 +      0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
  1.2945 +      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,
  1.2946 +      0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
  1.2947 +      0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
  1.2948 +      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,
  1.2949 +      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,
  1.2950 +      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,
  1.2951 +      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,
  1.2952 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2953 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2954 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2955 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.2956 +
  1.2957 +    // Definition of a 10x19 font.
  1.2958 +    const unsigned int font10x19[10*19*256/32] = {
  1.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,
  1.2960 +      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,
  1.2961 +      0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
  1.2962 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.2963 +      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,
  1.2964 +      0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
  1.2965 +      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,
  1.2966 +      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,
  1.2967 +      0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
  1.2968 +      0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
  1.2969 +      0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
  1.2970 +      0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
  1.2971 +      0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
  1.2972 +      0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
  1.2973 +      0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
  1.2974 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
  1.2975 +      0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
  1.2976 +      0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
  1.2977 +      0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
  1.2978 +      0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
  1.2979 +      0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
  1.2980 +      0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
  1.2981 +      0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
  1.2982 +      0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
  1.2983 +      0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
  1.2984 +      0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
  1.2985 +      0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
  1.2986 +      0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
  1.2987 +      0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
  1.2988 +      0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
  1.2989 +      0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
  1.2990 +      0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
  1.2991 +      0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
  1.2992 +      0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
  1.2993 +      0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
  1.2994 +      0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
  1.2995 +      0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
  1.2996 +      0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
  1.2997 +      0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
  1.2998 +      0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
  1.2999 +      0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
  1.3000 +      0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
  1.3001 +      0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
  1.3002 +      0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
  1.3003 +      0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
  1.3004 +      0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
  1.3005 +      0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
  1.3006 +      0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
  1.3007 +      0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
  1.3008 +      0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
  1.3009 +      0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
  1.3010 +      0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
  1.3011 +      0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
  1.3012 +      0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
  1.3013 +      0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
  1.3014 +      0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
  1.3015 +      0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
  1.3016 +      0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
  1.3017 +      0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
  1.3018 +      0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
  1.3019 +      0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
  1.3020 +      0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
  1.3021 +      0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
  1.3022 +      0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
  1.3023 +      0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
  1.3024 +      0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
  1.3025 +      0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
  1.3026 +      0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
  1.3027 +      0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
  1.3028 +      0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
  1.3029 +      0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
  1.3030 +      0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
  1.3031 +      0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
  1.3032 +      0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
  1.3033 +      0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
  1.3034 +      0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
  1.3035 +      0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
  1.3036 +      0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
  1.3037 +      0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
  1.3038 +      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,
  1.3039 +      0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
  1.3040 +      0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3041 +      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,
  1.3042 +      0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
  1.3043 +      0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
  1.3044 +      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,
  1.3045 +      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,
  1.3046 +      0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
  1.3047 +      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,
  1.3048 +      0x0,0x0,0x0,0x0,0x0,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,
  1.3049 +      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,
  1.3050 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.3051 +
  1.3052 +    // Definition of a 12x24 font.
  1.3053 +     const unsigned int font12x24[12*24*256/32] = {
  1.3054 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3055 +       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,
  1.3056 +       0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
  1.3057 +       0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3058 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3059 +       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,
  1.3060 +       0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
  1.3061 +       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,
  1.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,
  1.3063 +       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,
  1.3064 +       0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
  1.3065 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3066 +       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,
  1.3067 +       0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
  1.3068 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
  1.3069 +       0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
  1.3070 +       0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
  1.3071 +       0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
  1.3072 +       0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
  1.3073 +       0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
  1.3074 +       0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
  1.3075 +       0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
  1.3076 +       0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
  1.3077 +       0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
  1.3078 +       0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
  1.3079 +       0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
  1.3080 +       0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
  1.3081 +       0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
  1.3082 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
  1.3083 +       0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
  1.3084 +       0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
  1.3085 +       0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
  1.3086 +       0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
  1.3087 +       0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
  1.3088 +       0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
  1.3089 +       0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
  1.3090 +       0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
  1.3091 +       0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
  1.3092 +       0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
  1.3093 +       0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
  1.3094 +       0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
  1.3095 +       0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
  1.3096 +       0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
  1.3097 +       0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
  1.3098 +       0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
  1.3099 +       0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
  1.3100 +       0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
  1.3101 +       0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
  1.3102 +       0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
  1.3103 +       0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
  1.3104 +       0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
  1.3105 +       0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
  1.3106 +       0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
  1.3107 +       0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
  1.3108 +       0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
  1.3109 +       0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
  1.3110 +       0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
  1.3111 +       0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
  1.3112 +       0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
  1.3113 +       0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
  1.3114 +       0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
  1.3115 +       0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
  1.3116 +       0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
  1.3117 +       0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
  1.3118 +       0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
  1.3119 +       0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
  1.3120 +       0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
  1.3121 +       0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
  1.3122 +       0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
  1.3123 +       0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
  1.3124 +       0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
  1.3125 +       0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
  1.3126 +       0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
  1.3127 +       0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
  1.3128 +       0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
  1.3129 +       0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
  1.3130 +       0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
  1.3131 +       0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
  1.3132 +       0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
  1.3133 +       0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
  1.3134 +       0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
  1.3135 +       0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
  1.3136 +       0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
  1.3137 +       0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
  1.3138 +       0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
  1.3139 +       0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
  1.3140 +       0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
  1.3141 +       0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
  1.3142 +       0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
  1.3143 +       0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
  1.3144 +       0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
  1.3145 +       0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
  1.3146 +       0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
  1.3147 +       0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
  1.3148 +       0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
  1.3149 +       0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
  1.3150 +       0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
  1.3151 +       0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
  1.3152 +       0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
  1.3153 +       0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
  1.3154 +       0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
  1.3155 +       0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
  1.3156 +       0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
  1.3157 +       0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
  1.3158 +       0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
  1.3159 +       0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
  1.3160 +       0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
  1.3161 +       0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
  1.3162 +       0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
  1.3163 +       0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
  1.3164 +       0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
  1.3165 +       0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
  1.3166 +       0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
  1.3167 +       0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
  1.3168 +       0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
  1.3169 +       0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
  1.3170 +       0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
  1.3171 +       0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
  1.3172 +       0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
  1.3173 +       0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
  1.3174 +       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,
  1.3175 +       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,
  1.3176 +       0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
  1.3177 +       0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
  1.3178 +       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,
  1.3179 +       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,
  1.3180 +       0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
  1.3181 +       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,
  1.3182 +       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,
  1.3183 +       0x0,0x0,0x0,0x0,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,
  1.3184 +       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,
  1.3185 +       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,
  1.3186 +       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,
  1.3187 +       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,
  1.3188 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3189 +       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.3190 +
  1.3191 +    // Definition of a 16x32 font.
  1.3192 +    const unsigned int font16x32[16*32*256/32] = {
  1.3193 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3194 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3195 +      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,
  1.3196 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
  1.3197 +      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,
  1.3198 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3199 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3200 +      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,
  1.3201 +      0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
  1.3202 +      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,
  1.3203 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3204 +      0x0,0x0,0x0,0x0,0x0,0x0,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,
  1.3205 +      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,
  1.3206 +      0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
  1.3207 +      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,
  1.3208 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3209 +      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,
  1.3210 +      0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
  1.3211 +      0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
  1.3212 +      0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3213 +      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,
  1.3214 +      0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
  1.3215 +      0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
  1.3216 +      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,
  1.3217 +      0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
  1.3218 +      0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
  1.3219 +      0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
  1.3220 +      0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
  1.3221 +      0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
  1.3222 +      0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
  1.3223 +      0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
  1.3224 +      0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
  1.3225 +      0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
  1.3226 +      0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
  1.3227 +      0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
  1.3228 +      0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
  1.3229 +      0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
  1.3230 +      0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
  1.3231 +      0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
  1.3232 +      0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
  1.3233 +      0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
  1.3234 +      0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
  1.3235 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
  1.3236 +      0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
  1.3237 +      0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
  1.3238 +      0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
  1.3239 +      0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
  1.3240 +      0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
  1.3241 +      0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
  1.3242 +      0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
  1.3243 +      0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
  1.3244 +      0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
  1.3245 +      0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
  1.3246 +      0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
  1.3247 +      0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
  1.3248 +      0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
  1.3249 +      0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
  1.3250 +      0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3251 +      0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
  1.3252 +      0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
  1.3253 +      0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
  1.3254 +      0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
  1.3255 +      0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
  1.3256 +      0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
  1.3257 +      0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
  1.3258 +      0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
  1.3259 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
  1.3260 +      0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
  1.3261 +      0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
  1.3262 +      0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
  1.3263 +      0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
  1.3264 +      0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
  1.3265 +      0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
  1.3266 +      0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
  1.3267 +      0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
  1.3268 +      0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
  1.3269 +      0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
  1.3270 +      0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
  1.3271 +      0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
  1.3272 +      0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
  1.3273 +      0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
  1.3274 +      0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
  1.3275 +      0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
  1.3276 +      0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
  1.3277 +      0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3278 +      0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
  1.3279 +      0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
  1.3280 +      0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
  1.3281 +      0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
  1.3282 +      0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
  1.3283 +      0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
  1.3284 +      0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
  1.3285 +      0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
  1.3286 +      0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3287 +      0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
  1.3288 +      0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
  1.3289 +      0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
  1.3290 +      0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
  1.3291 +      0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
  1.3292 +      0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
  1.3293 +      0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
  1.3294 +      0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
  1.3295 +      0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
  1.3296 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
  1.3297 +      0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
  1.3298 +      0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
  1.3299 +      0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
  1.3300 +      0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
  1.3301 +      0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
  1.3302 +      0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
  1.3303 +      0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
  1.3304 +      0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
  1.3305 +      0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
  1.3306 +      0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
  1.3307 +      0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
  1.3308 +      0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
  1.3309 +      0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
  1.3310 +      0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
  1.3311 +      0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
  1.3312 +      0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
  1.3313 +      0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
  1.3314 +      0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
  1.3315 +      0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
  1.3316 +      0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
  1.3317 +      0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
  1.3318 +      0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
  1.3319 +      0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
  1.3320 +      0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
  1.3321 +      0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
  1.3322 +      0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
  1.3323 +      0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
  1.3324 +      0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
  1.3325 +      0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
  1.3326 +      0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
  1.3327 +      0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
  1.3328 +      0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
  1.3329 +      0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  1.3330 +      0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
  1.3331 +      0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
  1.3332 +      0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
  1.3333 +      0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
  1.3334 +      0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
  1.3335 +      0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
  1.3336 +      0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
  1.3337 +      0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
  1.3338 +      0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  1.3339 +      0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
  1.3340 +      0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
  1.3341 +      0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
  1.3342 +      0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
  1.3343 +      0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
  1.3344 +      0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
  1.3345 +      0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
  1.3346 +      0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
  1.3347 +      0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
  1.3348 +      0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
  1.3349 +      0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
  1.3350 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
  1.3351 +      0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
  1.3352 +      0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
  1.3353 +      0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
  1.3354 +      0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
  1.3355 +      0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
  1.3356 +      0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
  1.3357 +      0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
  1.3358 +      0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
  1.3359 +      0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
  1.3360 +      0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
  1.3361 +      0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
  1.3362 +      0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
  1.3363 +      0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
  1.3364 +      0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
  1.3365 +      0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
  1.3366 +      0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
  1.3367 +      0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
  1.3368 +      0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
  1.3369 +      0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
  1.3370 +      0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
  1.3371 +      0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
  1.3372 +      0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
  1.3373 +      0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
  1.3374 +      0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
  1.3375 +      0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
  1.3376 +      0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
  1.3377 +      0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
  1.3378 +      0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
  1.3379 +      0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
  1.3380 +      0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
  1.3381 +      0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
  1.3382 +      0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
  1.3383 +      0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
  1.3384 +      0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
  1.3385 +      0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
  1.3386 +      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,
  1.3387 +      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,
  1.3388 +      0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3389 +      0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
  1.3390 +      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,
  1.3391 +      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,
  1.3392 +      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,
  1.3393 +      0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
  1.3394 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
  1.3395 +      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,
  1.3396 +      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,
  1.3397 +      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,
  1.3398 +      0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
  1.3399 +      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,
  1.3400 +      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,
  1.3401 +      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,
  1.3402 +      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,
  1.3403 +      0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3404 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
  1.3405 +      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,
  1.3406 +      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,
  1.3407 +      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,
  1.3408 +      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,
  1.3409 +      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,
  1.3410 +      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,
  1.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,
  1.3412 +      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,
  1.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,
  1.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,
  1.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,
  1.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,
  1.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,
  1.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,
  1.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,
  1.3420 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3421 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3422 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3423 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.3424 +
  1.3425 +    // Definition of a 19x38 font.
  1.3426 +    const unsigned int font19x38[19*38*256/32] = {
  1.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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3428 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3429 +      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,
  1.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,0x3800007,0x3c003,0x86000000,
  1.3431 +      0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
  1.3432 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3433 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3434 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3435 +      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,
  1.3436 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
  1.3437 +      0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
  1.3438 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3439 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3440 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3441 +      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,
  1.3442 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
  1.3443 +      0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0,
  1.3444 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3445 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3446 +      0x0,0x0,0x0,0x0,0x0,0x0,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,
  1.3447 +      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,
  1.3448 +      0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
  1.3449 +      0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3450 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3451 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3452 +      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,
  1.3453 +      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,
  1.3454 +      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,
  1.3455 +      0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3456 +      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,
  1.3457 +      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,
  1.3458 +      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,
  1.3459 +      0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
  1.3460 +      0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
  1.3461 +      0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3462 +      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,
  1.3463 +      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,
  1.3464 +      0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
  1.3465 +      0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
  1.3466 +      0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3467 +      0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
  1.3468 +      0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3469 +      0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
  1.3470 +      0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
  1.3471 +      0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
  1.3472 +      0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
  1.3473 +      0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
  1.3474 +      0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
  1.3475 +      0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
  1.3476 +      0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
  1.3477 +      0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
  1.3478 +      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,
  1.3479 +      0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
  1.3480 +      0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
  1.3481 +      0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
  1.3482 +      0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
  1.3483 +      0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
  1.3484 +      0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
  1.3485 +      0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
  1.3486 +      0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
  1.3487 +      0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3488 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
  1.3489 +      0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
  1.3490 +      0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
  1.3491 +      0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
  1.3492 +      0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
  1.3493 +      0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
  1.3494 +      0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
  1.3495 +      0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
  1.3496 +      0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
  1.3497 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
  1.3498 +      0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
  1.3499 +      0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
  1.3500 +      0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
  1.3501 +      0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
  1.3502 +      0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
  1.3503 +      0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
  1.3504 +      0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
  1.3505 +      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,
  1.3506 +      0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
  1.3507 +      0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
  1.3508 +      0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
  1.3509 +      0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
  1.3510 +      0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
  1.3511 +      0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
  1.3512 +      0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
  1.3513 +      0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
  1.3514 +      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,
  1.3515 +      0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
  1.3516 +      0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
  1.3517 +      0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
  1.3518 +      0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
  1.3519 +      0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
  1.3520 +      0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
  1.3521 +      0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
  1.3522 +      0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
  1.3523 +      0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
  1.3524 +      0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3525 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
  1.3526 +      0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
  1.3527 +      0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
  1.3528 +      0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
  1.3529 +      0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
  1.3530 +      0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
  1.3531 +      0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
  1.3532 +      0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
  1.3533 +      0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
  1.3534 +      0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
  1.3535 +      0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3536 +      0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
  1.3537 +      0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
  1.3538 +      0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
  1.3539 +      0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
  1.3540 +      0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
  1.3541 +      0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
  1.3542 +      0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
  1.3543 +      0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
  1.3544 +      0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
  1.3545 +      0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
  1.3546 +      0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
  1.3547 +      0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
  1.3548 +      0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
  1.3549 +      0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
  1.3550 +      0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
  1.3551 +      0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
  1.3552 +      0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
  1.3553 +      0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
  1.3554 +      0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
  1.3555 +      0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
  1.3556 +      0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
  1.3557 +      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,
  1.3558 +      0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
  1.3559 +      0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
  1.3560 +      0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
  1.3561 +      0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
  1.3562 +      0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
  1.3563 +      0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
  1.3564 +      0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
  1.3565 +      0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
  1.3566 +      0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
  1.3567 +      0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
  1.3568 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
  1.3569 +      0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
  1.3570 +      0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
  1.3571 +      0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
  1.3572 +      0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
  1.3573 +      0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
  1.3574 +      0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
  1.3575 +      0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
  1.3576 +      0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
  1.3577 +      0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
  1.3578 +      0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3579 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
  1.3580 +      0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
  1.3581 +      0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
  1.3582 +      0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
  1.3583 +      0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
  1.3584 +      0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
  1.3585 +      0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
  1.3586 +      0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
  1.3587 +      0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
  1.3588 +      0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
  1.3589 +      0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3590 +      0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
  1.3591 +      0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
  1.3592 +      0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
  1.3593 +      0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
  1.3594 +      0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
  1.3595 +      0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
  1.3596 +      0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
  1.3597 +      0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
  1.3598 +      0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
  1.3599 +      0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
  1.3600 +      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,
  1.3601 +      0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
  1.3602 +      0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
  1.3603 +      0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
  1.3604 +      0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
  1.3605 +      0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
  1.3606 +      0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
  1.3607 +      0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
  1.3608 +      0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
  1.3609 +      0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
  1.3610 +      0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
  1.3611 +      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,
  1.3612 +      0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
  1.3613 +      0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
  1.3614 +      0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
  1.3615 +      0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
  1.3616 +      0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
  1.3617 +      0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
  1.3618 +      0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
  1.3619 +      0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
  1.3620 +      0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
  1.3621 +      0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3622 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
  1.3623 +      0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
  1.3624 +      0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
  1.3625 +      0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
  1.3626 +      0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
  1.3627 +      0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
  1.3628 +      0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
  1.3629 +      0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
  1.3630 +      0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
  1.3631 +      0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
  1.3632 +      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,
  1.3633 +      0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
  1.3634 +      0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
  1.3635 +      0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
  1.3636 +      0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
  1.3637 +      0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
  1.3638 +      0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
  1.3639 +      0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
  1.3640 +      0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
  1.3641 +      0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
  1.3642 +      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,
  1.3643 +      0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
  1.3644 +      0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
  1.3645 +      0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
  1.3646 +      0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
  1.3647 +      0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
  1.3648 +      0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
  1.3649 +      0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
  1.3650 +      0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
  1.3651 +      0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
  1.3652 +      0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3653 +      0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
  1.3654 +      0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
  1.3655 +      0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
  1.3656 +      0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
  1.3657 +      0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
  1.3658 +      0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
  1.3659 +      0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
  1.3660 +      0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
  1.3661 +      0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
  1.3662 +      0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
  1.3663 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
  1.3664 +      0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
  1.3665 +      0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
  1.3666 +      0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
  1.3667 +      0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
  1.3668 +      0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
  1.3669 +      0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
  1.3670 +      0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
  1.3671 +      0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
  1.3672 +      0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
  1.3673 +      0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3674 +      0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
  1.3675 +      0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
  1.3676 +      0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
  1.3677 +      0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
  1.3678 +      0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
  1.3679 +      0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
  1.3680 +      0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
  1.3681 +      0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
  1.3682 +      0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
  1.3683 +      0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3684 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
  1.3685 +      0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
  1.3686 +      0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
  1.3687 +      0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
  1.3688 +      0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
  1.3689 +      0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
  1.3690 +      0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
  1.3691 +      0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
  1.3692 +      0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
  1.3693 +      0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
  1.3694 +      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,
  1.3695 +      0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
  1.3696 +      0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
  1.3697 +      0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
  1.3698 +      0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
  1.3699 +      0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
  1.3700 +      0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
  1.3701 +      0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
  1.3702 +      0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
  1.3703 +      0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
  1.3704 +      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,
  1.3705 +      0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
  1.3706 +      0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
  1.3707 +      0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  1.3708 +      0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
  1.3709 +      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,
  1.3710 +      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,
  1.3711 +      0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
  1.3712 +      0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
  1.3713 +      0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  1.3714 +      0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
  1.3715 +      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,
  1.3716 +      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,
  1.3717 +      0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
  1.3718 +      0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
  1.3719 +      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,
  1.3720 +      0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
  1.3721 +      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,
  1.3722 +      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,
  1.3723 +      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,
  1.3724 +      0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
  1.3725 +      0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
  1.3726 +      0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
  1.3727 +      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,
  1.3728 +      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,
  1.3729 +      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,
  1.3730 +      0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
  1.3731 +      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,
  1.3732 +      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,
  1.3733 +      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,
  1.3734 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3735 +      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,
  1.3736 +      0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3737 +      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,
  1.3738 +      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,
  1.3739 +      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,
  1.3740 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3741 +      0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
  1.3742 +      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,
  1.3743 +      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,
  1.3744 +      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,
  1.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,
  1.3746 +      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,
  1.3747 +      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,
  1.3748 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3749 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.3750 +
  1.3751 +    // Definition of a 29x57 font.
  1.3752 +    const unsigned int font29x57[29*57*256/32] = {
  1.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,
  1.3754 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3755 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3756 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3757 +      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,
  1.3758 +      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,
  1.3759 +      0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
  1.3760 +      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,
  1.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,
  1.3762 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,0x0,0x0,
  1.3764 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3765 +      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,
  1.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,0x3e0000,
  1.3767 +      0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
  1.3768 +      0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.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,0x0,0x0,0x0,0x0,0x0,
  1.3771 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3772 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3773 +      0x0,0x0,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,
  1.3774 +      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,
  1.3775 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
  1.3776 +      0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
  1.3777 +      0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.3779 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3780 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3781 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3782 +      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,
  1.3783 +      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,
  1.3784 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
  1.3785 +      0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
  1.3786 +      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,
  1.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,
  1.3788 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3789 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3790 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3791 +      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,
  1.3792 +      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,
  1.3793 +      0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
  1.3794 +      0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
  1.3795 +      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,
  1.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,
  1.3797 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3798 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3799 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3800 +      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,
  1.3801 +      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,
  1.3802 +      0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
  1.3803 +      0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
  1.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,
  1.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,
  1.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,
  1.3807 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3808 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.3810 +      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,
  1.3811 +      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,
  1.3812 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3813 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3814 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3815 +      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,
  1.3816 +      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,
  1.3817 +      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,
  1.3818 +      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,
  1.3819 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
  1.3820 +      0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
  1.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,
  1.3822 +      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,
  1.3823 +      0x0,0x0,0x0,0x0,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,
  1.3824 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3825 +      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,
  1.3826 +      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,
  1.3827 +      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,
  1.3828 +      0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
  1.3829 +      0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3830 +      0x0,0x0,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,
  1.3831 +      0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
  1.3832 +      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,
  1.3833 +      0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
  1.3834 +      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,
  1.3835 +      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,
  1.3836 +      0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
  1.3837 +      0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
  1.3838 +      0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
  1.3839 +      0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
  1.3840 +      0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3841 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
  1.3842 +      0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
  1.3843 +      0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
  1.3844 +      0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
  1.3845 +      0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
  1.3846 +      0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
  1.3847 +      0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
  1.3848 +      0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
  1.3849 +      0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
  1.3850 +      0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
  1.3851 +      0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
  1.3852 +      0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
  1.3853 +      0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
  1.3854 +      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,
  1.3855 +      0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
  1.3856 +      0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
  1.3857 +      0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
  1.3858 +      0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
  1.3859 +      0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3860 +      0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
  1.3861 +      0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
  1.3862 +      0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
  1.3863 +      0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
  1.3864 +      0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
  1.3865 +      0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
  1.3866 +      0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
  1.3867 +      0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
  1.3868 +      0x0,0x0,0x0,0x0,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,
  1.3869 +      0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
  1.3870 +      0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
  1.3871 +      0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
  1.3872 +      0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
  1.3873 +      0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
  1.3874 +      0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
  1.3875 +      0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
  1.3876 +      0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
  1.3877 +      0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
  1.3878 +      0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
  1.3879 +      0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
  1.3880 +      0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
  1.3881 +      0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
  1.3882 +      0x0,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,
  1.3883 +      0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
  1.3884 +      0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
  1.3885 +      0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
  1.3886 +      0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
  1.3887 +      0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
  1.3888 +      0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3889 +      0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
  1.3890 +      0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
  1.3891 +      0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
  1.3892 +      0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
  1.3893 +      0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
  1.3894 +      0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
  1.3895 +      0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3896 +      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,
  1.3897 +      0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
  1.3898 +      0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
  1.3899 +      0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
  1.3900 +      0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
  1.3901 +      0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
  1.3902 +      0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
  1.3903 +      0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
  1.3904 +      0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
  1.3905 +      0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  1.3906 +      0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
  1.3907 +      0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
  1.3908 +      0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
  1.3909 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3910 +      0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
  1.3911 +      0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
  1.3912 +      0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
  1.3913 +      0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
  1.3914 +      0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
  1.3915 +      0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
  1.3916 +      0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
  1.3917 +      0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
  1.3918 +      0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
  1.3919 +      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
  1.3920 +      0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
  1.3921 +      0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
  1.3922 +      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,
  1.3923 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
  1.3924 +      0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
  1.3925 +      0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
  1.3926 +      0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
  1.3927 +      0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
  1.3928 +      0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
  1.3929 +      0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
  1.3930 +      0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
  1.3931 +      0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
  1.3932 +      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
  1.3933 +      0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3934 +      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,
  1.3935 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
  1.3936 +      0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
  1.3937 +      0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
  1.3938 +      0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
  1.3939 +      0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
  1.3940 +      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,
  1.3941 +      0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
  1.3942 +      0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
  1.3943 +      0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
  1.3944 +      0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
  1.3945 +      0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
  1.3946 +      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,
  1.3947 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.3948 +      0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
  1.3949 +      0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
  1.3950 +      0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
  1.3951 +      0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
  1.3952 +      0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
  1.3953 +      0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
  1.3954 +      0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
  1.3955 +      0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
  1.3956 +      0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
  1.3957 +      0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
  1.3958 +      0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
  1.3959 +      0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
  1.3960 +      0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
  1.3961 +      0x0,0x0,0x0,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,
  1.3962 +      0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
  1.3963 +      0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
  1.3964 +      0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
  1.3965 +      0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
  1.3966 +      0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
  1.3967 +      0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
  1.3968 +      0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
  1.3969 +      0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
  1.3970 +      0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
  1.3971 +      0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
  1.3972 +      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
  1.3973 +      0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
  1.3974 +      0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
  1.3975 +      0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
  1.3976 +      0x0,0x0,0x0,0x0,0x0,0x0,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,
  1.3977 +      0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
  1.3978 +      0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
  1.3979 +      0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
  1.3980 +      0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
  1.3981 +      0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
  1.3982 +      0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
  1.3983 +      0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
  1.3984 +      0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
  1.3985 +      0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
  1.3986 +      0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
  1.3987 +      0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
  1.3988 +      0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
  1.3989 +      0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
  1.3990 +      0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
  1.3991 +      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,
  1.3992 +      0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
  1.3993 +      0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
  1.3994 +      0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
  1.3995 +      0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
  1.3996 +      0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
  1.3997 +      0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
  1.3998 +      0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
  1.3999 +      0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
  1.4000 +      0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
  1.4001 +      0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
  1.4002 +      0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
  1.4003 +      0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
  1.4004 +      0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
  1.4005 +      0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
  1.4006 +      0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
  1.4007 +      0x0,0x0,0x0,0x0,0x0,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,
  1.4008 +      0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
  1.4009 +      0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
  1.4010 +      0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
  1.4011 +      0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
  1.4012 +      0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
  1.4013 +      0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
  1.4014 +      0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
  1.4015 +      0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
  1.4016 +      0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
  1.4017 +      0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
  1.4018 +      0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
  1.4019 +      0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
  1.4020 +      0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
  1.4021 +      0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
  1.4022 +      0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4023 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
  1.4024 +      0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
  1.4025 +      0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
  1.4026 +      0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
  1.4027 +      0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
  1.4028 +      0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
  1.4029 +      0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
  1.4030 +      0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
  1.4031 +      0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
  1.4032 +      0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
  1.4033 +      0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
  1.4034 +      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
  1.4035 +      0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
  1.4036 +      0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
  1.4037 +      0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
  1.4038 +      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,
  1.4039 +      0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
  1.4040 +      0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
  1.4041 +      0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
  1.4042 +      0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
  1.4043 +      0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
  1.4044 +      0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
  1.4045 +      0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
  1.4046 +      0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
  1.4047 +      0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
  1.4048 +      0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
  1.4049 +      0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
  1.4050 +      0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
  1.4051 +      0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
  1.4052 +      0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
  1.4053 +      0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4054 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
  1.4055 +      0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
  1.4056 +      0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
  1.4057 +      0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
  1.4058 +      0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
  1.4059 +      0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
  1.4060 +      0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
  1.4061 +      0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
  1.4062 +      0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
  1.4063 +      0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
  1.4064 +      0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
  1.4065 +      0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
  1.4066 +      0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
  1.4067 +      0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
  1.4068 +      0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
  1.4069 +      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,
  1.4070 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
  1.4071 +      0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
  1.4072 +      0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
  1.4073 +      0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
  1.4074 +      0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
  1.4075 +      0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
  1.4076 +      0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
  1.4077 +      0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
  1.4078 +      0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
  1.4079 +      0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
  1.4080 +      0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
  1.4081 +      0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
  1.4082 +      0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
  1.4083 +      0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
  1.4084 +      0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4085 +      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,
  1.4086 +      0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
  1.4087 +      0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
  1.4088 +      0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
  1.4089 +      0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
  1.4090 +      0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
  1.4091 +      0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
  1.4092 +      0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
  1.4093 +      0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
  1.4094 +      0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
  1.4095 +      0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
  1.4096 +      0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
  1.4097 +      0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
  1.4098 +      0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
  1.4099 +      0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
  1.4100 +      0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4101 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
  1.4102 +      0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
  1.4103 +      0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
  1.4104 +      0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
  1.4105 +      0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
  1.4106 +      0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
  1.4107 +      0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
  1.4108 +      0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
  1.4109 +      0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
  1.4110 +      0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
  1.4111 +      0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
  1.4112 +      0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
  1.4113 +      0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
  1.4114 +      0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
  1.4115 +      0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
  1.4116 +      0x0,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,
  1.4117 +      0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
  1.4118 +      0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
  1.4119 +      0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
  1.4120 +      0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
  1.4121 +      0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
  1.4122 +      0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
  1.4123 +      0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
  1.4124 +      0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
  1.4125 +      0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
  1.4126 +      0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
  1.4127 +      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
  1.4128 +      0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
  1.4129 +      0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
  1.4130 +      0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
  1.4131 +      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,
  1.4132 +      0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
  1.4133 +      0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
  1.4134 +      0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
  1.4135 +      0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
  1.4136 +      0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
  1.4137 +      0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
  1.4138 +      0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
  1.4139 +      0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
  1.4140 +      0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
  1.4141 +      0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
  1.4142 +      0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  1.4143 +      0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
  1.4144 +      0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
  1.4145 +      0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
  1.4146 +      0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4147 +      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,
  1.4148 +      0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
  1.4149 +      0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
  1.4150 +      0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
  1.4151 +      0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
  1.4152 +      0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
  1.4153 +      0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
  1.4154 +      0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
  1.4155 +      0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
  1.4156 +      0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
  1.4157 +      0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
  1.4158 +      0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
  1.4159 +      0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
  1.4160 +      0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
  1.4161 +      0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
  1.4162 +      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,
  1.4163 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
  1.4164 +      0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
  1.4165 +      0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
  1.4166 +      0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
  1.4167 +      0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
  1.4168 +      0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
  1.4169 +      0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
  1.4170 +      0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
  1.4171 +      0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
  1.4172 +      0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
  1.4173 +      0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  1.4174 +      0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
  1.4175 +      0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
  1.4176 +      0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
  1.4177 +      0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4178 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
  1.4179 +      0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
  1.4180 +      0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
  1.4181 +      0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
  1.4182 +      0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
  1.4183 +      0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
  1.4184 +      0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
  1.4185 +      0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
  1.4186 +      0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
  1.4187 +      0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
  1.4188 +      0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
  1.4189 +      0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
  1.4190 +      0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
  1.4191 +      0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
  1.4192 +      0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4193 +      0x0,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,
  1.4194 +      0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
  1.4195 +      0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
  1.4196 +      0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
  1.4197 +      0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
  1.4198 +      0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
  1.4199 +      0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
  1.4200 +      0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
  1.4201 +      0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
  1.4202 +      0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
  1.4203 +      0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
  1.4204 +      0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
  1.4205 +      0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
  1.4206 +      0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
  1.4207 +      0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4208 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
  1.4209 +      0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
  1.4210 +      0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
  1.4211 +      0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
  1.4212 +      0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
  1.4213 +      0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
  1.4214 +      0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
  1.4215 +      0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
  1.4216 +      0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
  1.4217 +      0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
  1.4218 +      0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
  1.4219 +      0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
  1.4220 +      0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
  1.4221 +      0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
  1.4222 +      0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4223 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
  1.4224 +      0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
  1.4225 +      0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
  1.4226 +      0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
  1.4227 +      0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
  1.4228 +      0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
  1.4229 +      0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
  1.4230 +      0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
  1.4231 +      0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
  1.4232 +      0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
  1.4233 +      0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
  1.4234 +      0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
  1.4235 +      0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
  1.4236 +      0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
  1.4237 +      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,
  1.4238 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
  1.4239 +      0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
  1.4240 +      0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
  1.4241 +      0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
  1.4242 +      0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
  1.4243 +      0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
  1.4244 +      0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
  1.4245 +      0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
  1.4246 +      0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
  1.4247 +      0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
  1.4248 +      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
  1.4249 +      0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
  1.4250 +      0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
  1.4251 +      0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
  1.4252 +      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,
  1.4253 +      0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
  1.4254 +      0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
  1.4255 +      0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
  1.4256 +      0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
  1.4257 +      0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
  1.4258 +      0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
  1.4259 +      0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
  1.4260 +      0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
  1.4261 +      0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
  1.4262 +      0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
  1.4263 +      0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
  1.4264 +      0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
  1.4265 +      0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
  1.4266 +      0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
  1.4267 +      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,
  1.4268 +      0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
  1.4269 +      0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
  1.4270 +      0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
  1.4271 +      0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
  1.4272 +      0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
  1.4273 +      0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
  1.4274 +      0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
  1.4275 +      0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
  1.4276 +      0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
  1.4277 +      0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
  1.4278 +      0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
  1.4279 +      0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
  1.4280 +      0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
  1.4281 +      0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
  1.4282 +      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,
  1.4283 +      0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
  1.4284 +      0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
  1.4285 +      0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
  1.4286 +      0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
  1.4287 +      0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
  1.4288 +      0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
  1.4289 +      0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
  1.4290 +      0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
  1.4291 +      0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
  1.4292 +      0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
  1.4293 +      0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
  1.4294 +      0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
  1.4295 +      0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
  1.4296 +      0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
  1.4297 +      0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4298 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
  1.4299 +      0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
  1.4300 +      0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
  1.4301 +      0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
  1.4302 +      0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
  1.4303 +      0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
  1.4304 +      0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
  1.4305 +      0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
  1.4306 +      0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
  1.4307 +      0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
  1.4308 +      0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
  1.4309 +      0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
  1.4310 +      0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
  1.4311 +      0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
  1.4312 +      0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
  1.4313 +      0x0,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,
  1.4314 +      0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
  1.4315 +      0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
  1.4316 +      0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
  1.4317 +      0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
  1.4318 +      0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
  1.4319 +      0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
  1.4320 +      0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
  1.4321 +      0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
  1.4322 +      0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
  1.4323 +      0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
  1.4324 +      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
  1.4325 +      0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
  1.4326 +      0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
  1.4327 +      0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
  1.4328 +      0x0,0x0,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,
  1.4329 +      0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
  1.4330 +      0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
  1.4331 +      0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
  1.4332 +      0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
  1.4333 +      0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
  1.4334 +      0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
  1.4335 +      0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
  1.4336 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
  1.4337 +      0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
  1.4338 +      0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
  1.4339 +      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
  1.4340 +      0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
  1.4341 +      0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
  1.4342 +      0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
  1.4343 +      0x0,0x0,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,
  1.4344 +      0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
  1.4345 +      0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
  1.4346 +      0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
  1.4347 +      0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
  1.4348 +      0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
  1.4349 +      0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
  1.4350 +      0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
  1.4351 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
  1.4352 +      0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
  1.4353 +      0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
  1.4354 +      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
  1.4355 +      0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
  1.4356 +      0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
  1.4357 +      0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
  1.4358 +      0x0,0x0,0x0,0x0,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,
  1.4359 +      0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
  1.4360 +      0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
  1.4361 +      0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
  1.4362 +      0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
  1.4363 +      0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4364 +      0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
  1.4365 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
  1.4366 +      0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
  1.4367 +      0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
  1.4368 +      0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
  1.4369 +      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,
  1.4370 +      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,
  1.4371 +      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,
  1.4372 +      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,
  1.4373 +      0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
  1.4374 +      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,
  1.4375 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
  1.4376 +      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,
  1.4377 +      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,
  1.4378 +      0x0,0x0,0x0,0x0,0x0,0x0,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,
  1.4379 +      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,
  1.4380 +      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,
  1.4381 +      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,
  1.4382 +      0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4383 +      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,
  1.4384 +      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,
  1.4385 +      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,
  1.4386 +      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,
  1.4387 +      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,
  1.4388 +      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,
  1.4389 +      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,
  1.4390 +      0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
  1.4391 +      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,
  1.4392 +      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,
  1.4393 +      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,
  1.4394 +      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,
  1.4395 +      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,
  1.4396 +      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,
  1.4397 +      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,
  1.4398 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
  1.4399 +      0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
  1.4400 +      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,
  1.4401 +      0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
  1.4402 +      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,
  1.4403 +      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,
  1.4404 +      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,
  1.4405 +      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,
  1.4406 +      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,
  1.4407 +      0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
  1.4408 +      0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4409 +      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,
  1.4410 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
  1.4411 +      0x0,0x0,0x0,0x0,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,
  1.4412 +      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,
  1.4413 +      0x0,0x0,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,
  1.4414 +      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,
  1.4415 +      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,
  1.4416 +      0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
  1.4417 +      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,
  1.4418 +      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,
  1.4419 +      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,
  1.4420 +      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,
  1.4421 +      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,
  1.4422 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4423 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4424 +      0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
  1.4425 +      0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4426 +      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,
  1.4427 +      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,
  1.4428 +      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,
  1.4429 +      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,
  1.4430 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.4432 +      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,
  1.4433 +      0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
  1.4434 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4435 +      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,
  1.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,0x1fc,0x0,0x0,
  1.4437 +      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,
  1.4438 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.4440 +      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,
  1.4441 +      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,
  1.4442 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4443 +      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,
  1.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,
  1.4445 +      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,
  1.4446 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.4448 +      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,
  1.4449 +      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,
  1.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,
  1.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,
  1.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,
  1.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,0x0,0x0,0x0,0x0,0x0,
  1.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,
  1.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,
  1.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,0xf0,0x0,0x0,0x0,
  1.4457 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4458 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4459 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
  1.4460 +      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
  1.4461 +
  1.4462 +    // Definition of a 40x38 'danger' color logo.
  1.4463 +    const unsigned char logo40x38[4576] = {
  1.4464 +      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,
  1.4465 +      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,
  1.4466 +      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,
  1.4467 +      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,
  1.4468 +      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,
  1.4469 +      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,
  1.4470 +      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,
  1.4471 +      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,
  1.4472 +      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,
  1.4473 +      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,
  1.4474 +      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,
  1.4475 +      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,
  1.4476 +      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,
  1.4477 +      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,
  1.4478 +      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,
  1.4479 +      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,
  1.4480 +      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,
  1.4481 +      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,
  1.4482 +      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,
  1.4483 +      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,
  1.4484 +      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,
  1.4485 +      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,
  1.4486 +      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,
  1.4487 +      200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
  1.4488 +
  1.4489 +    //! Display a warning message.
  1.4490 +    /**
  1.4491 +        \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
  1.4492 +    **/
  1.4493 +    inline void warn(const char *format, ...) {
  1.4494 +      if (cimg::exception_mode()>=1) {
  1.4495 +        char message[8192];
  1.4496 +        cimg_std::va_list ap;
  1.4497 +        va_start(ap,format);
  1.4498 +        cimg_std::vsprintf(message,format,ap);
  1.4499 +        va_end(ap);
  1.4500 +#ifdef cimg_strict_warnings
  1.4501 +        throw CImgWarningException(message);
  1.4502 +#else
  1.4503 +        cimg_std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
  1.4504 +#endif
  1.4505 +      }
  1.4506 +    }
  1.4507 +
  1.4508 +    // Execute an external system command.
  1.4509 +    /**
  1.4510 +       \note This function is similar to <tt>std::system()</tt>
  1.4511 +       and is here because using the <tt>std::</tt> version on
  1.4512 +       Windows may open undesired consoles.
  1.4513 +     **/
  1.4514 +    inline int system(const char *const command, const char *const module_name=0) {
  1.4515 +#if cimg_OS==2
  1.4516 +      PROCESS_INFORMATION pi;
  1.4517 +      STARTUPINFO si;
  1.4518 +      cimg_std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
  1.4519 +      cimg_std::memset(&si,0,sizeof(STARTUPINFO));
  1.4520 +      GetStartupInfo(&si);
  1.4521 +      si.cb = sizeof(si);
  1.4522 +      si.wShowWindow = SW_HIDE;
  1.4523 +      si.dwFlags |= SW_HIDE;
  1.4524 +      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
  1.4525 +      if (res) {
  1.4526 +        WaitForSingleObject(pi.hProcess, INFINITE);
  1.4527 +        CloseHandle(pi.hThread);
  1.4528 +        CloseHandle(pi.hProcess);
  1.4529 +        return 0;
  1.4530 +      } else
  1.4531 +#endif
  1.4532 +        return cimg_std::system(command);
  1.4533 +      return module_name?0:1;
  1.4534 +    }
  1.4535 +
  1.4536 +    //! Return a reference to a temporary variable of type T.
  1.4537 +    template<typename T>
  1.4538 +    inline T& temporary(const T&) {
  1.4539 +      static T temp;
  1.4540 +      return temp;
  1.4541 +    }
  1.4542 +
  1.4543 +    //! Exchange values of variables \p a and \p b.
  1.4544 +    template<typename T>
  1.4545 +    inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
  1.4546 +
  1.4547 +    //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
  1.4548 +    template<typename T1, typename T2>
  1.4549 +    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
  1.4550 +      cimg::swap(a1,b1); cimg::swap(a2,b2);
  1.4551 +    }
  1.4552 +
  1.4553 +    //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
  1.4554 +    template<typename T1, typename T2, typename T3>
  1.4555 +    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
  1.4556 +      cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
  1.4557 +    }
  1.4558 +
  1.4559 +    //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
  1.4560 +    template<typename T1, typename T2, typename T3, typename T4>
  1.4561 +    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
  1.4562 +      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
  1.4563 +    }
  1.4564 +
  1.4565 +    //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
  1.4566 +    template<typename T1, typename T2, typename T3, typename T4, typename T5>
  1.4567 +    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
  1.4568 +      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
  1.4569 +    }
  1.4570 +
  1.4571 +    //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
  1.4572 +    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
  1.4573 +    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) {
  1.4574 +      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
  1.4575 +    }
  1.4576 +
  1.4577 +    //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
  1.4578 +    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
  1.4579 +    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,
  1.4580 +                     T7& a7, T7& b7) {
  1.4581 +      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
  1.4582 +    }
  1.4583 +
  1.4584 +    //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
  1.4585 +    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
  1.4586 +    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,
  1.4587 +                     T7& a7, T7& b7, T8& a8, T8& b8) {
  1.4588 +      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
  1.4589 +    }
  1.4590 +
  1.4591 +    //! Return the current endianness of the CPU.
  1.4592 +    /**
  1.4593 +       \return \c false for "Little Endian", \c true for "Big Endian".
  1.4594 +    **/
  1.4595 +    inline bool endianness() {
  1.4596 +      const int x = 1;
  1.4597 +      return ((unsigned char*)&x)[0]?false:true;
  1.4598 +    }
  1.4599 +
  1.4600 +    //! Invert endianness of a memory buffer.
  1.4601 +    template<typename T>
  1.4602 +    inline void invert_endianness(T* const buffer, const unsigned int size) {
  1.4603 +      if (size) switch (sizeof(T)) {
  1.4604 +      case 1 : break;
  1.4605 +      case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
  1.4606 +        const unsigned short val = *(--ptr);
  1.4607 +        *ptr = (unsigned short)((val>>8)|((val<<8)));
  1.4608 +      }} break;
  1.4609 +      case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
  1.4610 +        const unsigned int val = *(--ptr);
  1.4611 +        *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
  1.4612 +      }} break;
  1.4613 +      default : { for (T* ptr = buffer+size; ptr>buffer; ) {
  1.4614 +        unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
  1.4615 +        for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
  1.4616 +      }}
  1.4617 +      }
  1.4618 +    }
  1.4619 +
  1.4620 +    //! Invert endianness of a single variable.
  1.4621 +    template<typename T>
  1.4622 +    inline T& invert_endianness(T& a) {
  1.4623 +      invert_endianness(&a,1);
  1.4624 +      return a;
  1.4625 +    }
  1.4626 +
  1.4627 +    //! Get the value of a system timer with a millisecond precision.
  1.4628 +    inline unsigned long time() {
  1.4629 +#if cimg_OS==1
  1.4630 +      struct timeval st_time;
  1.4631 +      gettimeofday(&st_time,0);
  1.4632 +      return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
  1.4633 +#elif cimg_OS==2
  1.4634 +      static SYSTEMTIME st_time;
  1.4635 +      GetSystemTime(&st_time);
  1.4636 +      return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
  1.4637 +#else
  1.4638 +      return 0;
  1.4639 +#endif
  1.4640 +    }
  1.4641 +
  1.4642 +    //! Sleep for a certain numbers of milliseconds.
  1.4643 +    /**
  1.4644 +       This function frees the CPU ressources during the sleeping time.
  1.4645 +       It may be used to temporize your program properly, without wasting CPU time.
  1.4646 +    **/
  1.4647 +    inline void sleep(const unsigned int milliseconds) {
  1.4648 +#if cimg_OS==1
  1.4649 +      struct timespec tv;
  1.4650 +      tv.tv_sec = milliseconds/1000;
  1.4651 +      tv.tv_nsec = (milliseconds%1000)*1000000;
  1.4652 +      nanosleep(&tv,0);
  1.4653 +#elif cimg_OS==2
  1.4654 +      Sleep(milliseconds);
  1.4655 +#endif
  1.4656 +    }
  1.4657 +
  1.4658 +    inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
  1.4659 +      if (!timer) timer = cimg::time();
  1.4660 +      const unsigned long current_time = cimg::time();
  1.4661 +      if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
  1.4662 +      const unsigned long time_diff = timer + milliseconds - current_time;
  1.4663 +      timer = current_time + time_diff;
  1.4664 +      cimg::sleep(time_diff);
  1.4665 +      return (unsigned int)time_diff;
  1.4666 +    }
  1.4667 +
  1.4668 +    //! Wait for a certain number of milliseconds since the last call.
  1.4669 +    /**
  1.4670 +       This function is equivalent to sleep() but the waiting time is computed with regard to the last call
  1.4671 +       of wait(). It may be used to temporize your program properly.
  1.4672 +    **/
  1.4673 +    inline unsigned int wait(const unsigned int milliseconds) {
  1.4674 +      static unsigned long timer = 0;
  1.4675 +      if (!timer) timer = cimg::time();
  1.4676 +      return _sleep(milliseconds,timer);
  1.4677 +    }
  1.4678 +
  1.4679 +    // Use a specific srand initialization to avoid multi-threads to have to the
  1.4680 +    // same series of random numbers (executed only once for a single program).
  1.4681 +    inline void srand() {
  1.4682 +      static bool first_time = true;
  1.4683 +      if (first_time) {
  1.4684 +        cimg_std::srand(cimg::time());
  1.4685 +        unsigned char *const rand_ptr = new unsigned char[1+cimg_std::rand()%2048];
  1.4686 +        cimg_std::srand((unsigned int)cimg_std::rand() + *(unsigned int*)(void*)rand_ptr);
  1.4687 +        delete[] rand_ptr;
  1.4688 +        first_time = false;
  1.4689 +      }
  1.4690 +    }
  1.4691 +
  1.4692 +    //! Return a left bitwise-rotated number.
  1.4693 +    template<typename T>
  1.4694 +    inline const T rol(const T a, const unsigned int n=1) {
  1.4695 +      return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
  1.4696 +    }
  1.4697 +
  1.4698 +    //! Return a right bitwise-rotated number.
  1.4699 +    template<typename T>
  1.4700 +    inline const T ror(const T a, const unsigned int n=1) {
  1.4701 +      return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
  1.4702 +    }
  1.4703 +
  1.4704 +    //! Return the absolute value of a number.
  1.4705 +    /**
  1.4706 +       \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
  1.4707 +       because it is able to consider a variable of any type, without cast needed.
  1.4708 +    **/
  1.4709 +    template<typename T>
  1.4710 +    inline T abs(const T a) {
  1.4711 +      return a>=0?a:-a;
  1.4712 +    }
  1.4713 +    inline bool abs(const bool a) {
  1.4714 +      return a;
  1.4715 +    }
  1.4716 +    inline unsigned char abs(const unsigned char a) {
  1.4717 +      return a;
  1.4718 +    }
  1.4719 +    inline unsigned short abs(const unsigned short a) {
  1.4720 +      return a;
  1.4721 +    }
  1.4722 +    inline unsigned int abs(const unsigned int a) {
  1.4723 +      return a;
  1.4724 +    }
  1.4725 +    inline unsigned long abs(const unsigned long a) {
  1.4726 +      return a;
  1.4727 +    }
  1.4728 +    inline double abs(const double a) {
  1.4729 +      return cimg_std::fabs(a);
  1.4730 +    }
  1.4731 +    inline float abs(const float a) {
  1.4732 +      return (float)cimg_std::fabs((double)a);
  1.4733 +    }
  1.4734 +    inline int abs(const int a) {
  1.4735 +      return cimg_std::abs(a);
  1.4736 +    }
  1.4737 +
  1.4738 +    //! Return the square of a number.
  1.4739 +    template<typename T>
  1.4740 +    inline T sqr(const T val) {
  1.4741 +      return val*val;
  1.4742 +    }
  1.4743 +
  1.4744 +    //! Return 1 + log_10(x).
  1.4745 +    inline int xln(const int x) {
  1.4746 +      return x>0?(int)(1+cimg_std::log10((double)x)):1;
  1.4747 +    }
  1.4748 +
  1.4749 +    //! Return the minimum value between two numbers.
  1.4750 +    template<typename t1, typename t2>
  1.4751 +    inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
  1.4752 +      typedef typename cimg::superset<t1,t2>::type t1t2;
  1.4753 +      return (t1t2)(a<=b?a:b);
  1.4754 +    }
  1.4755 +
  1.4756 +    //! Return the minimum value between three numbers.
  1.4757 +    template<typename t1, typename t2, typename t3>
  1.4758 +    inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
  1.4759 +      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
  1.4760 +      return (t1t2t3)cimg::min(cimg::min(a,b),c);
  1.4761 +    }
  1.4762 +
  1.4763 +    //! Return the minimum value between four numbers.
  1.4764 +    template<typename t1, typename t2, typename t3, typename t4>
  1.4765 +    inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
  1.4766 +      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
  1.4767 +      return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
  1.4768 +    }
  1.4769 +
  1.4770 +    //! Return the maximum value between two numbers.
  1.4771 +    template<typename t1, typename t2>
  1.4772 +    inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
  1.4773 +      typedef typename cimg::superset<t1,t2>::type t1t2;
  1.4774 +      return (t1t2)(a>=b?a:b);
  1.4775 +    }
  1.4776 +
  1.4777 +    //! Return the maximum value between three numbers.
  1.4778 +    template<typename t1, typename t2, typename t3>
  1.4779 +    inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
  1.4780 +      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
  1.4781 +      return (t1t2t3)cimg::max(cimg::max(a,b),c);
  1.4782 +    }
  1.4783 +
  1.4784 +    //! Return the maximum value between four numbers.
  1.4785 +    template<typename t1, typename t2, typename t3, typename t4>
  1.4786 +    inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
  1.4787 +      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
  1.4788 +      return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
  1.4789 +    }
  1.4790 +
  1.4791 +    //! Return the sign of a number.
  1.4792 +    template<typename T>
  1.4793 +    inline T sign(const T x) {
  1.4794 +      return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
  1.4795 +    }
  1.4796 +
  1.4797 +    //! Return the nearest power of 2 higher than a given number.
  1.4798 +    template<typename T>
  1.4799 +    inline unsigned long nearest_pow2(const T x) {
  1.4800 +      unsigned long i = 1;
  1.4801 +      while (x>i) i<<=1;
  1.4802 +      return i;
  1.4803 +    }
  1.4804 +
  1.4805 +    //! Return the modulo of a number.
  1.4806 +    /**
  1.4807 +       \note This modulo function accepts negative and floating-points modulo numbers, as well as
  1.4808 +       variable of any type.
  1.4809 +    **/
  1.4810 +    template<typename T>
  1.4811 +    inline T mod(const T& x, const T& m) {
  1.4812 +      const double dx = (double)x, dm = (double)m;
  1.4813 +      if (x<0) { return (T)(dm+dx+dm*cimg_std::floor(-dx/dm)); }
  1.4814 +      return (T)(dx-dm*cimg_std::floor(dx/dm));
  1.4815 +    }
  1.4816 +    inline int mod(const bool x, const bool m) {
  1.4817 +      return m?(x?1:0):0;
  1.4818 +    }
  1.4819 +    inline int mod(const char x, const char m) {
  1.4820 +      return x>=0?x%m:(x%m?m+x%m:0);
  1.4821 +    }
  1.4822 +    inline int mod(const short x, const short m) {
  1.4823 +      return x>=0?x%m:(x%m?m+x%m:0);
  1.4824 +    }
  1.4825 +    inline int mod(const int x, const int m) {
  1.4826 +      return x>=0?x%m:(x%m?m+x%m:0);
  1.4827 +    }
  1.4828 +    inline int mod(const long x, const long m) {
  1.4829 +      return x>=0?x%m:(x%m?m+x%m:0);
  1.4830 +    }
  1.4831 +    inline int mod(const unsigned char x, const unsigned char m) {
  1.4832 +      return x%m;
  1.4833 +    }
  1.4834 +    inline int mod(const unsigned short x, const unsigned short m) {
  1.4835 +      return x%m;
  1.4836 +    }
  1.4837 +    inline int mod(const unsigned int x, const unsigned int m) {
  1.4838 +      return x%m;
  1.4839 +    }
  1.4840 +    inline int mod(const unsigned long x, const unsigned long m) {
  1.4841 +      return x%m;
  1.4842 +    }
  1.4843 +
  1.4844 +    //! Return the minmod of two numbers.
  1.4845 +    /**
  1.4846 +       <i>minmod(\p a,\p b)</i> is defined to be :
  1.4847 +       - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
  1.4848 +       - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
  1.4849 +    **/
  1.4850 +    template<typename T>
  1.4851 +    inline T minmod(const T a, const T b) {
  1.4852 +      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
  1.4853 +    }
  1.4854 +
  1.4855 +    //! Return a random variable between [0,1] with respect to an uniform distribution.
  1.4856 +    inline double rand() {
  1.4857 +      static bool first_time = true;
  1.4858 +      if (first_time) { cimg::srand(); first_time = false; }
  1.4859 +      return (double)cimg_std::rand()/RAND_MAX;
  1.4860 +    }
  1.4861 +
  1.4862 +    //! Return a random variable between [-1,1] with respect to an uniform distribution.
  1.4863 +    inline double crand() {
  1.4864 +      return 1-2*cimg::rand();
  1.4865 +    }
  1.4866 +
  1.4867 +    //! Return a random variable following a gaussian distribution and a standard deviation of 1.
  1.4868 +    inline double grand() {
  1.4869 +      double x1, w;
  1.4870 +      do {
  1.4871 +        const double x2 = 2*cimg::rand() - 1.0;
  1.4872 +        x1 = 2*cimg::rand()-1.0;
  1.4873 +        w = x1*x1 + x2*x2;
  1.4874 +      } while (w<=0 || w>=1.0);
  1.4875 +      return x1*cimg_std::sqrt((-2*cimg_std::log(w))/w);
  1.4876 +    }
  1.4877 +
  1.4878 +    //! Return a random variable following a Poisson distribution of parameter z.
  1.4879 +    inline unsigned int prand(const double z) {
  1.4880 +      if (z<=1.0e-10) return 0;
  1.4881 +      if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
  1.4882 +      unsigned int k = 0;
  1.4883 +      const double y = std::exp(-z);
  1.4884 +      for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
  1.4885 +      return k-1;
  1.4886 +    }
  1.4887 +
  1.4888 +    //! Return a rounded number.
  1.4889 +    /**
  1.4890 +       \param x is the number to be rounded.
  1.4891 +       \param y is the rounding precision.
  1.4892 +       \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward).
  1.4893 +    **/
  1.4894 +    inline double round(const double x, const double y, const int rounding_type=0) {
  1.4895 +      if (y<=0) return x;
  1.4896 +      const double delta = cimg::mod(x,y);
  1.4897 +      if (delta==0.0) return x;
  1.4898 +      const double
  1.4899 +        backward = x - delta,
  1.4900 +        forward = backward + y;
  1.4901 +      return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
  1.4902 +    }
  1.4903 +
  1.4904 +    inline double _pythagore(double a, double b) {
  1.4905 +      const double absa = cimg::abs(a), absb = cimg::abs(b);
  1.4906 +      if (absa>absb) { const double tmp = absb/absa; return absa*cimg_std::sqrt(1.0+tmp*tmp); }
  1.4907 +      else { const double tmp = absa/absb; return (absb==0?0:absb*cimg_std::sqrt(1.0+tmp*tmp)); }
  1.4908 +    }
  1.4909 +
  1.4910 +    //! Remove the 'case' of an ASCII character.
  1.4911 +    inline char uncase(const char x) {
  1.4912 +      return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
  1.4913 +    }
  1.4914 +
  1.4915 +    //! Remove the 'case' of a C string.
  1.4916 +    /**
  1.4917 +       Acts in-place.
  1.4918 +    **/
  1.4919 +    inline void uncase(char *const string) {
  1.4920 +      if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
  1.4921 +    }
  1.4922 +
  1.4923 +    //! Read a float number from a C-string.
  1.4924 +    /**
  1.4925 +       \note This function is quite similar to <tt>std::atof()</tt>,
  1.4926 +       but that it allows the retrieval of fractions as in "1/2".
  1.4927 +    **/
  1.4928 +    inline float atof(const char *const str) {
  1.4929 +      float x = 0,y = 1;
  1.4930 +      if (!str) return 0; else { cimg_std::sscanf(str,"%g/%g",&x,&y); return x/y; }
  1.4931 +    }
  1.4932 +
  1.4933 +    //! Compute the length of a C-string.
  1.4934 +    /**
  1.4935 +       \note This function is similar to <tt>std::strlen()</tt>
  1.4936 +       and is here because some old compilers do not
  1.4937 +       define the <tt>std::</tt> version.
  1.4938 +    **/
  1.4939 +    inline int strlen(const char *const s) {
  1.4940 +      if (!s) return -1;
  1.4941 +      int k = 0;
  1.4942 +      for (const char *ns = s; *ns; ++ns) ++k;
  1.4943 +      return k;
  1.4944 +    }
  1.4945 +
  1.4946 +    //! Compare the first \p n characters of two C-strings.
  1.4947 +    /**
  1.4948 +       \note This function is similar to <tt>std::strncmp()</tt>
  1.4949 +       and is here because some old compilers do not
  1.4950 +       define the <tt>std::</tt> version.
  1.4951 +    **/
  1.4952 +    inline int strncmp(const char *const s1, const char *const s2, const int l) {
  1.4953 +      if (!s1) return s2?-1:0;
  1.4954 +      const char *ns1 = s1, *ns2 = s2;
  1.4955 +      int k, diff = 0; for (k = 0; k<l && !(diff = *ns1-*ns2); ++k) { ++ns1; ++ns2; }
  1.4956 +      return k!=l?diff:0;
  1.4957 +    }
  1.4958 +
  1.4959 +    //! Compare the first \p n characters of two C-strings, ignoring the case.
  1.4960 +    /**
  1.4961 +       \note This function is similar to <tt>std::strncasecmp()</tt>
  1.4962 +       and is here because some old compilers do not
  1.4963 +       define the <tt>std::</tt> version.
  1.4964 +    **/
  1.4965 +    inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
  1.4966 +      if (!s1) return s2?-1:0;
  1.4967 +      const char *ns1 = s1, *ns2 = s2;
  1.4968 +      int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
  1.4969 +      return k!=l?diff:0;
  1.4970 +    }
  1.4971 +
  1.4972 +    //! Compare two C-strings.
  1.4973 +    /**
  1.4974 +       \note This function is similar to <tt>std::strcmp()</tt>
  1.4975 +       and is here because some old compilers do not
  1.4976 +       define the <tt>std::</tt> version.
  1.4977 +    **/
  1.4978 +    inline int strcmp(const char *const s1, const char *const s2) {
  1.4979 +      const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
  1.4980 +      return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
  1.4981 +    }
  1.4982 +
  1.4983 +    //! Compare two C-strings, ignoring the case.
  1.4984 +    /**
  1.4985 +       \note This function is similar to <tt>std::strcasecmp()</tt>
  1.4986 +       and is here because some old compilers do not
  1.4987 +       define the <tt>std::</tt> version.
  1.4988 +    **/
  1.4989 +    inline int strcasecmp(const char *const s1, const char *const s2) {
  1.4990 +      const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
  1.4991 +      return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
  1.4992 +    }
  1.4993 +
  1.4994 +    //! Find a character in a C-string.
  1.4995 +    inline int strfind(const char *const s, const char c) {
  1.4996 +      if (!s) return -1;
  1.4997 +      int l; for (l = cimg::strlen(s); l>=0 && s[l]!=c; --l) {}
  1.4998 +      return l;
  1.4999 +    }
  1.5000 +
  1.5001 +    //! Remove useless delimiters on the borders of a C-string
  1.5002 +    inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
  1.5003 +      if (!s) return false;
  1.5004 +      const int l = cimg::strlen(s);
  1.5005 +      int p, q;
  1.5006 +      if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
  1.5007 +      else {
  1.5008 +        for (p = 0; p<l && s[p]==delimiter; ) ++p;
  1.5009 +        for (q = l-1; q>p && s[q]==delimiter; ) --q;
  1.5010 +      }
  1.5011 +      const int n = q - p + 1;
  1.5012 +      if (n!=l) { cimg_std::memmove(s,s+p,n); s[n] = '\0'; return true; }
  1.5013 +      return false;
  1.5014 +    }
  1.5015 +
  1.5016 +    //! Remove useless spaces and symmetric delimiters ', " and ` from a C-string.
  1.5017 +    inline void strclean(char *const s) {
  1.5018 +      if (!s) return;
  1.5019 +      strpare(s,' ',false);
  1.5020 +      for (bool need_iter = true; need_iter; ) {
  1.5021 +        need_iter = false;
  1.5022 +        need_iter |= strpare(s,'\'',true);
  1.5023 +        need_iter |= strpare(s,'\"',true);
  1.5024 +        need_iter |= strpare(s,'`',true);
  1.5025 +      }
  1.5026 +    }
  1.5027 +
  1.5028 +    //! Replace explicit escape sequences '\x' in C-strings (where x in [ntvbrfa?'"0]).
  1.5029 +    inline void strescape(char *const s) {
  1.5030 +#define cimg_strescape(ci,co) case ci: *nd = co; break;
  1.5031 +      char *ns, *nd;
  1.5032 +      for (ns = nd = s; *ns; ++ns, ++nd)
  1.5033 +        if (*ns=='\\') switch (*(++ns)) {
  1.5034 +            cimg_strescape('n','\n');
  1.5035 +            cimg_strescape('t','\t');
  1.5036 +            cimg_strescape('v','\v');
  1.5037 +            cimg_strescape('b','\b');
  1.5038 +            cimg_strescape('r','\r');
  1.5039 +            cimg_strescape('f','\f');
  1.5040 +            cimg_strescape('a','\a');
  1.5041 +            cimg_strescape('\\','\\');
  1.5042 +            cimg_strescape('\?','\?');
  1.5043 +            cimg_strescape('\'','\'');
  1.5044 +            cimg_strescape('\"','\"');
  1.5045 +            cimg_strescape('\0','\0');
  1.5046 +          }
  1.5047 +        else *nd = *ns;
  1.5048 +      *nd = 0;
  1.5049 +    }
  1.5050 +
  1.5051 +    //! Compute the basename of a filename.
  1.5052 +    inline const char* basename(const char *const s)  {
  1.5053 +      return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
  1.5054 +    }
  1.5055 +
  1.5056 +    // Generate a random filename.
  1.5057 +    inline const char* filenamerand() {
  1.5058 +      static char id[9] = { 0,0,0,0,0,0,0,0,0 };
  1.5059 +      cimg::srand();
  1.5060 +      for (unsigned int k=0; k<8; ++k) {
  1.5061 +        const int v = (int)cimg_std::rand()%3;
  1.5062 +        id[k] = (char)(v==0?('0'+(cimg_std::rand()%10)):(v==1?('a'+(cimg_std::rand()%26)):('A'+(cimg_std::rand()%26))));
  1.5063 +      }
  1.5064 +      return id;
  1.5065 +    }
  1.5066 +
  1.5067 +    // Convert filename into a Windows-style filename.
  1.5068 +    inline void winformat_string(char *const s) {
  1.5069 +      if (s && s[0]) {
  1.5070 +#if cimg_OS==2
  1.5071 +        char *const ns = new char[MAX_PATH];
  1.5072 +        if (GetShortPathNameA(s,ns,MAX_PATH)) cimg_std::strcpy(s,ns);
  1.5073 +#endif
  1.5074 +      }
  1.5075 +    }
  1.5076 +
  1.5077 +    //! Return or set path to store temporary files.
  1.5078 +    inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5079 +#define _cimg_test_temporary_path(p) \
  1.5080 +      if (!path_found) { \
  1.5081 +        cimg_std::sprintf(st_path,"%s",p); \
  1.5082 +        cimg_std::sprintf(tmp,"%s%s%s",st_path,cimg_OS==2?"\\":"/",filetmp); \
  1.5083 +        if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; } \
  1.5084 +      }
  1.5085 +      static char *st_path = 0;
  1.5086 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5087 +      if (user_path) {
  1.5088 +        if (!st_path) st_path = new char[1024];
  1.5089 +        cimg_std::memset(st_path,0,1024);
  1.5090 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5091 +      } else if (!st_path) {
  1.5092 +        st_path = new char[1024];
  1.5093 +        cimg_std::memset(st_path,0,1024);
  1.5094 +        bool path_found = false;
  1.5095 +        char tmp[1024], filetmp[512];
  1.5096 +        cimg_std::FILE *file = 0;
  1.5097 +        cimg_std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
  1.5098 +        char *tmpPath = getenv("TMP");
  1.5099 +        if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
  1.5100 +        if (tmpPath) _cimg_test_temporary_path(tmpPath);
  1.5101 +#if cimg_OS==2
  1.5102 +        _cimg_test_temporary_path("C:\\WINNT\\Temp");
  1.5103 +        _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
  1.5104 +        _cimg_test_temporary_path("C:\\Temp");
  1.5105 +        _cimg_test_temporary_path("C:");
  1.5106 +        _cimg_test_temporary_path("D:\\WINNT\\Temp");
  1.5107 +        _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
  1.5108 +        _cimg_test_temporary_path("D:\\Temp");
  1.5109 +        _cimg_test_temporary_path("D:");
  1.5110 +#else
  1.5111 +        _cimg_test_temporary_path("/tmp");
  1.5112 +        _cimg_test_temporary_path("/var/tmp");
  1.5113 +#endif
  1.5114 +        if (!path_found) {
  1.5115 +          st_path[0]='\0';
  1.5116 +          cimg_std::strcpy(tmp,filetmp);
  1.5117 +          if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; }
  1.5118 +        }
  1.5119 +        if (!path_found)
  1.5120 +          throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
  1.5121 +                                "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
  1.5122 +                                "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
  1.5123 +      }
  1.5124 +      return st_path;
  1.5125 +    }
  1.5126 +
  1.5127 +    // Return or set path to the "Program files/" directory (windows only).
  1.5128 +#if cimg_OS==2
  1.5129 +    inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5130 +      static char *st_path = 0;
  1.5131 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5132 +      if (user_path) {
  1.5133 +        if (!st_path) st_path = new char[1024];
  1.5134 +        cimg_std::memset(st_path,0,1024);
  1.5135 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5136 +      } else if (!st_path) {
  1.5137 +        st_path = new char[MAX_PATH];
  1.5138 +        cimg_std::memset(st_path,0,MAX_PATH);
  1.5139 +        // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
  1.5140 +#if !defined(__INTEL_COMPILER)
  1.5141 +        if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
  1.5142 +          const char *pfPath = getenv("PROGRAMFILES");
  1.5143 +          if (pfPath) cimg_std::strncpy(st_path,pfPath,MAX_PATH-1);
  1.5144 +          else cimg_std::strcpy(st_path,"C:\\PROGRA~1");
  1.5145 +        }
  1.5146 +#else
  1.5147 +        cimg_std::strcpy(st_path,"C:\\PROGRA~1");
  1.5148 +#endif
  1.5149 +      }
  1.5150 +      return st_path;
  1.5151 +    }
  1.5152 +#endif
  1.5153 +
  1.5154 +    //! Return or set path to the ImageMagick's \c convert tool.
  1.5155 +    inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5156 +      static char *st_path = 0;
  1.5157 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5158 +      if (user_path) {
  1.5159 +        if (!st_path) st_path = new char[1024];
  1.5160 +        cimg_std::memset(st_path,0,1024);
  1.5161 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5162 +      } else if (!st_path) {
  1.5163 +        st_path = new char[1024];
  1.5164 +        cimg_std::memset(st_path,0,1024);
  1.5165 +        bool path_found = false;
  1.5166 +        cimg_std::FILE *file = 0;
  1.5167 +#if cimg_OS==2
  1.5168 +        const char *pf_path = programfiles_path();
  1.5169 +        if (!path_found) {
  1.5170 +          cimg_std::sprintf(st_path,".\\convert.exe");
  1.5171 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5172 +        }
  1.5173 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5174 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
  1.5175 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5176 +        }}
  1.5177 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5178 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
  1.5179 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5180 +        }}
  1.5181 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5182 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
  1.5183 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5184 +        }}
  1.5185 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5186 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  1.5187 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5188 +        }}
  1.5189 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5190 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  1.5191 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5192 +        }}
  1.5193 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5194 +          cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
  1.5195 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5196 +        }}
  1.5197 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5198 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
  1.5199 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5200 +        }}
  1.5201 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5202 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
  1.5203 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5204 +        }}
  1.5205 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5206 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
  1.5207 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5208 +        }}
  1.5209 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5210 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
  1.5211 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5212 +        }}
  1.5213 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5214 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
  1.5215 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5216 +        }}
  1.5217 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5218 +          cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
  1.5219 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5220 +        }}
  1.5221 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5222 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
  1.5223 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5224 +        }}
  1.5225 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5226 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
  1.5227 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5228 +        }}
  1.5229 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5230 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
  1.5231 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5232 +        }}
  1.5233 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5234 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
  1.5235 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5236 +        }}
  1.5237 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5238 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
  1.5239 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5240 +        }}
  1.5241 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5242 +          cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
  1.5243 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5244 +        }}
  1.5245 +        if (!path_found) cimg_std::strcpy(st_path,"convert.exe");
  1.5246 +#else
  1.5247 +        if (!path_found) {
  1.5248 +          cimg_std::sprintf(st_path,"./convert");
  1.5249 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5250 +        }
  1.5251 +        if (!path_found) cimg_std::strcpy(st_path,"convert");
  1.5252 +#endif
  1.5253 +        winformat_string(st_path);
  1.5254 +      }
  1.5255 +      return st_path;
  1.5256 +    }
  1.5257 +
  1.5258 +    //! Return path of the GraphicsMagick's \c gm tool.
  1.5259 +    inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5260 +      static char *st_path = 0;
  1.5261 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5262 +      if (user_path) {
  1.5263 +        if (!st_path) st_path = new char[1024];
  1.5264 +        cimg_std::memset(st_path,0,1024);
  1.5265 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5266 +      } else if (!st_path) {
  1.5267 +        st_path = new char[1024];
  1.5268 +        cimg_std::memset(st_path,0,1024);
  1.5269 +        bool path_found = false;
  1.5270 +        cimg_std::FILE *file = 0;
  1.5271 +#if cimg_OS==2
  1.5272 +        const char* pf_path = programfiles_path();
  1.5273 +        if (!path_found) {
  1.5274 +          cimg_std::sprintf(st_path,".\\gm.exe");
  1.5275 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5276 +        }
  1.5277 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5278 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
  1.5279 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5280 +        }}
  1.5281 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5282 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
  1.5283 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5284 +        }}
  1.5285 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5286 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
  1.5287 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5288 +        }}
  1.5289 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5290 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  1.5291 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5292 +        }}
  1.5293 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5294 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  1.5295 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5296 +        }}
  1.5297 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5298 +          cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
  1.5299 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5300 +        }}
  1.5301 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5302 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
  1.5303 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5304 +        }}
  1.5305 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5306 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
  1.5307 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5308 +        }}
  1.5309 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5310 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
  1.5311 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5312 +        }}
  1.5313 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5314 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
  1.5315 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5316 +        }}
  1.5317 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5318 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
  1.5319 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5320 +        }}
  1.5321 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5322 +          cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
  1.5323 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5324 +        }}
  1.5325 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5326 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
  1.5327 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5328 +        }}
  1.5329 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5330 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
  1.5331 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5332 +        }}
  1.5333 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5334 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
  1.5335 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5336 +        }}
  1.5337 +        { for (int k=32; k>=10 && !path_found; --k) {
  1.5338 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
  1.5339 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5340 +        }}
  1.5341 +        { for (int k=9; k>=0 && !path_found; --k) {
  1.5342 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
  1.5343 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5344 +        }}
  1.5345 +        { for (int k=32; k>=0 && !path_found; --k) {
  1.5346 +          cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
  1.5347 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5348 +        }}
  1.5349 +        if (!path_found) cimg_std::strcpy(st_path,"gm.exe");
  1.5350 +#else
  1.5351 +        if (!path_found) {
  1.5352 +          cimg_std::sprintf(st_path,"./gm");
  1.5353 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5354 +        }
  1.5355 +        if (!path_found) cimg_std::strcpy(st_path,"gm");
  1.5356 +#endif
  1.5357 +        winformat_string(st_path);
  1.5358 +      }
  1.5359 +      return st_path;
  1.5360 +    }
  1.5361 +
  1.5362 +    //! Return or set path of the \c XMedcon tool.
  1.5363 +    inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5364 +      static char *st_path = 0;
  1.5365 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5366 +      if (user_path) {
  1.5367 +        if (!st_path) st_path = new char[1024];
  1.5368 +        cimg_std::memset(st_path,0,1024);
  1.5369 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5370 +      } else if (!st_path) {
  1.5371 +        st_path = new char[1024];
  1.5372 +        cimg_std::memset(st_path,0,1024);
  1.5373 +        bool path_found = false;
  1.5374 +        cimg_std::FILE *file = 0;
  1.5375 +#if cimg_OS==2
  1.5376 +        const char* pf_path = programfiles_path();
  1.5377 +        if (!path_found) {
  1.5378 +          cimg_std::sprintf(st_path,".\\medcon.bat");
  1.5379 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5380 +        }
  1.5381 +        if (!path_found) {
  1.5382 +          cimg_std::sprintf(st_path,".\\medcon.exe");
  1.5383 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5384 +        }
  1.5385 +        if (!path_found) {
  1.5386 +          cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
  1.5387 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5388 +        }
  1.5389 +        if (!path_found) {
  1.5390 +          cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
  1.5391 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5392 +        }
  1.5393 +        if (!path_found) cimg_std::strcpy(st_path,"medcon.bat");
  1.5394 +#else
  1.5395 +        if (!path_found) {
  1.5396 +          cimg_std::sprintf(st_path,"./medcon");
  1.5397 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5398 +        }
  1.5399 +        if (!path_found) cimg_std::strcpy(st_path,"medcon");
  1.5400 +#endif
  1.5401 +        winformat_string(st_path);
  1.5402 +      }
  1.5403 +      return st_path;
  1.5404 +    }
  1.5405 +
  1.5406 +    //! Return or set path to the 'ffmpeg' command.
  1.5407 +    inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5408 +      static char *st_path = 0;
  1.5409 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5410 +      if (user_path) {
  1.5411 +        if (!st_path) st_path = new char[1024];
  1.5412 +        cimg_std::memset(st_path,0,1024);
  1.5413 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5414 +      } else if (!st_path) {
  1.5415 +        st_path = new char[1024];
  1.5416 +        cimg_std::memset(st_path,0,1024);
  1.5417 +        bool path_found = false;
  1.5418 +        cimg_std::FILE *file = 0;
  1.5419 +#if cimg_OS==2
  1.5420 +        if (!path_found) {
  1.5421 +          cimg_std::sprintf(st_path,".\\ffmpeg.exe");
  1.5422 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5423 +        }
  1.5424 +        if (!path_found) cimg_std::strcpy(st_path,"ffmpeg.exe");
  1.5425 +#else
  1.5426 +        if (!path_found) {
  1.5427 +          cimg_std::sprintf(st_path,"./ffmpeg");
  1.5428 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5429 +        }
  1.5430 +        if (!path_found) cimg_std::strcpy(st_path,"ffmpeg");
  1.5431 +#endif
  1.5432 +        winformat_string(st_path);
  1.5433 +      }
  1.5434 +      return st_path;
  1.5435 +    }
  1.5436 +
  1.5437 +    //! Return or set path to the 'gzip' command.
  1.5438 +    inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5439 +      static char *st_path = 0;
  1.5440 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5441 +      if (user_path) {
  1.5442 +        if (!st_path) st_path = new char[1024];
  1.5443 +        cimg_std::memset(st_path,0,1024);
  1.5444 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5445 +      } else if (!st_path) {
  1.5446 +        st_path = new char[1024];
  1.5447 +        cimg_std::memset(st_path,0,1024);
  1.5448 +        bool path_found = false;
  1.5449 +        cimg_std::FILE *file = 0;
  1.5450 +#if cimg_OS==2
  1.5451 +        if (!path_found) {
  1.5452 +          cimg_std::sprintf(st_path,".\\gzip.exe");
  1.5453 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5454 +        }
  1.5455 +        if (!path_found) cimg_std::strcpy(st_path,"gzip.exe");
  1.5456 +#else
  1.5457 +        if (!path_found) {
  1.5458 +          cimg_std::sprintf(st_path,"./gzip");
  1.5459 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5460 +        }
  1.5461 +        if (!path_found) cimg_std::strcpy(st_path,"gzip");
  1.5462 +#endif
  1.5463 +        winformat_string(st_path);
  1.5464 +      }
  1.5465 +      return st_path;
  1.5466 +    }
  1.5467 +
  1.5468 +    //! Return or set path to the 'gunzip' command.
  1.5469 +    inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5470 +      static char *st_path = 0;
  1.5471 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5472 +      if (user_path) {
  1.5473 +        if (!st_path) st_path = new char[1024];
  1.5474 +        cimg_std::memset(st_path,0,1024);
  1.5475 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5476 +      } else if (!st_path) {
  1.5477 +        st_path = new char[1024];
  1.5478 +        cimg_std::memset(st_path,0,1024);
  1.5479 +        bool path_found = false;
  1.5480 +        cimg_std::FILE *file = 0;
  1.5481 +#if cimg_OS==2
  1.5482 +        if (!path_found) {
  1.5483 +          cimg_std::sprintf(st_path,".\\gunzip.exe");
  1.5484 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5485 +        }
  1.5486 +        if (!path_found) cimg_std::strcpy(st_path,"gunzip.exe");
  1.5487 +#else
  1.5488 +        if (!path_found) {
  1.5489 +          cimg_std::sprintf(st_path,"./gunzip");
  1.5490 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5491 +        }
  1.5492 +        if (!path_found) cimg_std::strcpy(st_path,"gunzip");
  1.5493 +#endif
  1.5494 +        winformat_string(st_path);
  1.5495 +      }
  1.5496 +      return st_path;
  1.5497 +    }
  1.5498 +
  1.5499 +    //! Return or set path to the 'dcraw' command.
  1.5500 +    inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
  1.5501 +      static char *st_path = 0;
  1.5502 +      if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
  1.5503 +      if (user_path) {
  1.5504 +        if (!st_path) st_path = new char[1024];
  1.5505 +        cimg_std::memset(st_path,0,1024);
  1.5506 +        cimg_std::strncpy(st_path,user_path,1023);
  1.5507 +      } else if (!st_path) {
  1.5508 +        st_path = new char[1024];
  1.5509 +        cimg_std::memset(st_path,0,1024);
  1.5510 +        bool path_found = false;
  1.5511 +        cimg_std::FILE *file = 0;
  1.5512 +#if cimg_OS==2
  1.5513 +        if (!path_found) {
  1.5514 +          cimg_std::sprintf(st_path,".\\dcraw.exe");
  1.5515 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5516 +        }
  1.5517 +        if (!path_found) cimg_std::strcpy(st_path,"dcraw.exe");
  1.5518 +#else
  1.5519 +        if (!path_found) {
  1.5520 +          cimg_std::sprintf(st_path,"./dcraw");
  1.5521 +          if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
  1.5522 +        }
  1.5523 +        if (!path_found) cimg_std::strcpy(st_path,"dcraw");
  1.5524 +#endif
  1.5525 +        winformat_string(st_path);
  1.5526 +      }
  1.5527 +      return st_path;
  1.5528 +    }
  1.5529 +
  1.5530 +    //! Split a filename into two strings 'body' and 'extension'.
  1.5531 +    inline const char *split_filename(const char *const filename, char *const body=0) {
  1.5532 +      if (!filename) { if (body) body[0]='\0'; return 0; }
  1.5533 +      int l = cimg::strfind(filename,'.');
  1.5534 +      if (l>=0) { if (body) { cimg_std::strncpy(body,filename,l); body[l]='\0'; }}
  1.5535 +      else { if (body) cimg_std::strcpy(body,filename); l = (int)cimg::strlen(filename)-1; }
  1.5536 +      return filename+l+1;
  1.5537 +    }
  1.5538 +
  1.5539 +    //! Create a numbered version of a filename.
  1.5540 +    inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
  1.5541 +      if (!filename) { if (string) string[0]='\0'; return 0; }
  1.5542 +      char format[1024],body[1024];
  1.5543 +      const char *ext = cimg::split_filename(filename,body);
  1.5544 +      if (n>0) cimg_std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
  1.5545 +      else cimg_std::sprintf(format,"%s_%%d.%s",body,ext);
  1.5546 +      cimg_std::sprintf(string,format,number);
  1.5547 +      return string;
  1.5548 +    }
  1.5549 +
  1.5550 +    //! Open a file, and check for possible errors.
  1.5551 +    inline cimg_std::FILE *fopen(const char *const path, const char *const mode) {
  1.5552 +      if(!path || !mode)
  1.5553 +        throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
  1.5554 +                                    path?path:"(null)",mode?mode:"(null)");
  1.5555 +      if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
  1.5556 +      cimg_std::FILE *dest = cimg_std::fopen(path,mode);
  1.5557 +      if (!dest)
  1.5558 +        throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
  1.5559 +                              path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
  1.5560 +      return dest;
  1.5561 +    }
  1.5562 +
  1.5563 +    //! Close a file, and check for possible errors.
  1.5564 +    inline int fclose(cimg_std::FILE *file) {
  1.5565 +      if (!file) warn("cimg::fclose() : Can't close (null) file");
  1.5566 +      if (!file || file==stdin || file==stdout) return 0;
  1.5567 +      const int errn = cimg_std::fclose(file);
  1.5568 +      if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
  1.5569 +      return errn;
  1.5570 +    }
  1.5571 +
  1.5572 +    //! Try to guess the image format of a filename, using its magick numbers.
  1.5573 +    inline const char *file_type(cimg_std::FILE *const file, const char *const filename) {
  1.5574 +      static const char
  1.5575 +        *const _pnm = "pnm",
  1.5576 +        *const _bmp = "bmp",
  1.5577 +        *const _gif = "gif",
  1.5578 +        *const _jpeg = "jpeg",
  1.5579 +        *const _off = "off",
  1.5580 +        *const _pan = "pan",
  1.5581 +        *const _png = "png",
  1.5582 +        *const _tiff = "tiff";
  1.5583 +      if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
  1.5584 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
  1.5585 +      const char *ftype = 0, *head;
  1.5586 +      char header[2048], item[1024];
  1.5587 +      const unsigned char *const uheader = (unsigned char*)header;
  1.5588 +      int err;
  1.5589 +      const unsigned int siz = (unsigned int)cimg_std::fread(header,2048,1,nfile);   // Read first 2048 bytes.
  1.5590 +      if (!file) cimg::fclose(nfile);
  1.5591 +      if (!ftype) { // Check for BMP format.
  1.5592 +        if (header[0]=='B' && header[1]=='M') ftype = _bmp;
  1.5593 +      }
  1.5594 +      if (!ftype) { // Check for GIF format.
  1.5595 +        if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
  1.5596 +            (header[4]=='7' || header[4]=='9')) ftype = _gif;
  1.5597 +      }
  1.5598 +      if (!ftype) { // Check for JPEG format.
  1.5599 +        if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
  1.5600 +      }
  1.5601 +      if (!ftype) { // Check for OFF format.
  1.5602 +        if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
  1.5603 +      }
  1.5604 +      if (!ftype) { // Check for PAN format.
  1.5605 +        if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
  1.5606 +            header[5]=='R' && header[6]=='E') ftype = _pan;
  1.5607 +      }
  1.5608 +      if (!ftype) { // Check for PNG format.
  1.5609 +        if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
  1.5610 +            uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
  1.5611 +      }
  1.5612 +      if (!ftype) { // Check for PNM format.
  1.5613 +        head = header;
  1.5614 +        while (head<header+siz && (err=cimg_std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
  1.5615 +          head+=1+(err?cimg::strlen(item):0);
  1.5616 +        if (cimg_std::sscanf(item," P%d",&err)==1) ftype = _pnm;
  1.5617 +      }
  1.5618 +      if (!ftype) { // Check for TIFF format.
  1.5619 +        if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
  1.5620 +      }
  1.5621 +      return ftype;
  1.5622 +    }
  1.5623 +
  1.5624 +    //! Read file data, and check for possible errors.
  1.5625 +    template<typename T>
  1.5626 +    inline int fread(T *const ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
  1.5627 +      if (!ptr || nmemb<=0 || !stream)
  1.5628 +        throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
  1.5629 +                                    nmemb,sizeof(T),stream,ptr);
  1.5630 +      const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
  1.5631 +      unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
  1.5632 +      do {
  1.5633 +        ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
  1.5634 +        lalread = (unsigned int)cimg_std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
  1.5635 +        alread+=lalread;
  1.5636 +        toread-=lalread;
  1.5637 +      } while (ltoread==lalread && toread>0);
  1.5638 +      if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
  1.5639 +      return alread;
  1.5640 +    }
  1.5641 +
  1.5642 +    //! Write data to a file, and check for possible errors.
  1.5643 +    template<typename T>
  1.5644 +    inline int fwrite(const T *ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
  1.5645 +      if (!ptr || !stream)
  1.5646 +        throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
  1.5647 +                                    nmemb,sizeof(T),stream,ptr);
  1.5648 +      if (nmemb<=0) return 0;
  1.5649 +      const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
  1.5650 +      unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
  1.5651 +      do {
  1.5652 +        ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
  1.5653 +        lalwrite = (unsigned int)cimg_std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
  1.5654 +        alwrite+=lalwrite;
  1.5655 +        towrite-=lalwrite;
  1.5656 +      } while (ltowrite==lalwrite && towrite>0);
  1.5657 +      if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
  1.5658 +      return alwrite;
  1.5659 +    }
  1.5660 +
  1.5661 +    inline const char* option(const char *const name, const int argc, const char *const *const argv,
  1.5662 +                              const char *defaut, const char *const usage=0) {
  1.5663 +      static bool first = true, visu = false;
  1.5664 +      const char *res = 0;
  1.5665 +      if (first) {
  1.5666 +        first=false;
  1.5667 +        visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
  1.5668 +        visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
  1.5669 +        visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
  1.5670 +      }
  1.5671 +      if (!name && visu) {
  1.5672 +        if (usage) {
  1.5673 +          cimg_std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
  1.5674 +          cimg_std::fprintf(cimg_stdout," : %s",usage);
  1.5675 +          cimg_std::fprintf(cimg_stdout," (%s, %s)\n\n",__DATE__,__TIME__);
  1.5676 +        }
  1.5677 +        if (defaut) cimg_std::fprintf(cimg_stdout,"%s\n",defaut);
  1.5678 +      }
  1.5679 +      if (name) {
  1.5680 +        if (argc>0) {
  1.5681 +          int k = 0;
  1.5682 +          while (k<argc && cimg::strcmp(argv[k],name)) ++k;
  1.5683 +          res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
  1.5684 +        } else res = defaut;
  1.5685 +        if (visu && usage) cimg_std::fprintf(cimg_stdout,"    %s%-16s%s %-24s %s%s%s\n",
  1.5686 +                                        cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
  1.5687 +      }
  1.5688 +      return res;
  1.5689 +    }
  1.5690 +
  1.5691 +    inline bool option(const char *const name, const int argc, const char *const *const argv,
  1.5692 +                       const bool defaut, const char *const usage=0) {
  1.5693 +      const char *s = cimg::option(name,argc,argv,(char*)0);
  1.5694 +      const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
  1.5695 +      cimg::option(name,0,0,res?"true":"false",usage);
  1.5696 +      return res;
  1.5697 +    }
  1.5698 +
  1.5699 +    inline int option(const char *const name, const int argc, const char *const *const argv,
  1.5700 +                      const int defaut, const char *const usage=0) {
  1.5701 +      const char *s = cimg::option(name,argc,argv,(char*)0);
  1.5702 +      const int res = s?cimg_std::atoi(s):defaut;
  1.5703 +      char tmp[256];
  1.5704 +      cimg_std::sprintf(tmp,"%d",res);
  1.5705 +      cimg::option(name,0,0,tmp,usage);
  1.5706 +      return res;
  1.5707 +    }
  1.5708 +
  1.5709 +    inline char option(const char *const name, const int argc, const char *const *const argv,
  1.5710 +                       const char defaut, const char *const usage=0) {
  1.5711 +      const char *s = cimg::option(name,argc,argv,(char*)0);
  1.5712 +      const char res = s?s[0]:defaut;
  1.5713 +      char tmp[8];
  1.5714 +      tmp[0] = res; tmp[1] ='\0';
  1.5715 +      cimg::option(name,0,0,tmp,usage);
  1.5716 +      return res;
  1.5717 +    }
  1.5718 +
  1.5719 +    inline float option(const char *const name, const int argc, const char *const *const argv,
  1.5720 +                        const float defaut, const char *const usage=0) {
  1.5721 +      const char *s = cimg::option(name,argc,argv,(char*)0);
  1.5722 +      const float res = s?cimg::atof(s):defaut;
  1.5723 +      char tmp[256];
  1.5724 +      cimg_std::sprintf(tmp,"%g",res);
  1.5725 +      cimg::option(name,0,0,tmp,usage);
  1.5726 +      return res;
  1.5727 +    }
  1.5728 +
  1.5729 +    inline double option(const char *const name, const int argc, const char *const *const argv,
  1.5730 +                         const double defaut, const char *const usage=0) {
  1.5731 +      const char *s = cimg::option(name,argc,argv,(char*)0);
  1.5732 +      const double res = s?cimg::atof(s):defaut;
  1.5733 +      char tmp[256];
  1.5734 +      cimg_std::sprintf(tmp,"%g",res);
  1.5735 +      cimg::option(name,0,0,tmp,usage);
  1.5736 +      return res;
  1.5737 +    }
  1.5738 +
  1.5739 +    inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
  1.5740 +      for (int k = 1, pos = 0; k<argc;) {
  1.5741 +        const char *const item = argv[k];
  1.5742 +        bool option = (*item=='-'), single_option = false;
  1.5743 +        if (option) {
  1.5744 +          va_list ap;
  1.5745 +          va_start(ap,nb_singles);
  1.5746 +          for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
  1.5747 +          va_end(ap);
  1.5748 +        }
  1.5749 +        if (option) { ++k; if (!single_option) ++k; }
  1.5750 +        else { if (pos++==(int)nb) return item; else ++k; }
  1.5751 +      }
  1.5752 +      return 0;
  1.5753 +    }
  1.5754 +
  1.5755 +    //! Print informations about %CImg environement variables.
  1.5756 +    /**
  1.5757 +       Printing is done on the standard error output.
  1.5758 +    **/
  1.5759 +    inline void info() {
  1.5760 +      char tmp[1024] = { 0 };
  1.5761 +      cimg_std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
  1.5762 +                   cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
  1.5763 +                   cimg::t_normal,__DATE__,__TIME__);
  1.5764 +
  1.5765 +      cimg_std::fprintf(cimg_stdout,"  > Operating System :       %s%-13s%s %s('cimg_OS'=%d)%s\n",
  1.5766 +                   cimg::t_bold,
  1.5767 +                   cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
  1.5768 +                   cimg::t_normal,cimg::t_green,
  1.5769 +                   cimg_OS,
  1.5770 +                   cimg::t_normal);
  1.5771 +
  1.5772 +      cimg_std::fprintf(cimg_stdout,"  > CPU endianness :         %s%s Endian%s\n",
  1.5773 +                   cimg::t_bold,
  1.5774 +                   cimg::endianness()?"Big":"Little",
  1.5775 +                   cimg::t_normal);
  1.5776 +
  1.5777 +#ifdef cimg_use_visualcpp6
  1.5778 +      cimg_std::fprintf(cimg_stdout,"  > Using Visual C++ 6.0 :       %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
  1.5779 +                   cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
  1.5780 +#endif
  1.5781 +
  1.5782 +      cimg_std::fprintf(cimg_stdout,"  > Debug messages :         %s%-13s%s %s('cimg_debug'=%d)%s\n",
  1.5783 +                   cimg::t_bold,
  1.5784 +                   cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
  1.5785 +                   cimg::t_normal,cimg::t_green,
  1.5786 +                   cimg_debug,
  1.5787 +                   cimg::t_normal);
  1.5788 +
  1.5789 +      cimg_std::fprintf(cimg_stdout,"  > Stricts warnings :       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
  1.5790 +                   cimg::t_bold,
  1.5791 +#ifdef cimg_strict_warnings
  1.5792 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5793 +#else
  1.5794 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5795 +#endif
  1.5796 +                   cimg::t_normal);
  1.5797 +
  1.5798 +      cimg_std::fprintf(cimg_stdout,"  > Using VT100 messages :   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
  1.5799 +                   cimg::t_bold,
  1.5800 +#ifdef cimg_use_vt100
  1.5801 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5802 +#else
  1.5803 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5804 +#endif
  1.5805 +                   cimg::t_normal);
  1.5806 +
  1.5807 +      cimg_std::fprintf(cimg_stdout,"  > Display type :           %s%-13s%s %s('cimg_display'=%d)%s\n",
  1.5808 +                   cimg::t_bold,
  1.5809 +                   cimg_display==0?"No display":
  1.5810 +                   (cimg_display==1?"X11":
  1.5811 +                    (cimg_display==2?"Windows GDI":
  1.5812 +                     (cimg_display==3?"Carbon":"Unknow"))),
  1.5813 +                   cimg::t_normal,cimg::t_green,
  1.5814 +                   cimg_display,
  1.5815 +                   cimg::t_normal);
  1.5816 +
  1.5817 +#if cimg_display==1
  1.5818 +      cimg_std::fprintf(cimg_stdout,"  > Using XShm for X11 :     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
  1.5819 +                   cimg::t_bold,
  1.5820 +#ifdef cimg_use_xshm
  1.5821 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5822 +#else
  1.5823 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5824 +#endif
  1.5825 +                   cimg::t_normal);
  1.5826 +
  1.5827 +      cimg_std::fprintf(cimg_stdout,"  > Using XRand for X11 :    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
  1.5828 +                   cimg::t_bold,
  1.5829 +#ifdef cimg_use_xrandr
  1.5830 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5831 +#else
  1.5832 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5833 +#endif
  1.5834 +                   cimg::t_normal);
  1.5835 +#endif
  1.5836 +      cimg_std::fprintf(cimg_stdout,"  > Using OpenMP :           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
  1.5837 +                   cimg::t_bold,
  1.5838 +#ifdef cimg_use_openmp
  1.5839 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5840 +#else
  1.5841 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5842 +#endif
  1.5843 +                   cimg::t_normal);
  1.5844 +      cimg_std::fprintf(cimg_stdout,"  > Using PNG library :      %s%-13s%s %s('cimg_use_png' %s)%s\n",
  1.5845 +                   cimg::t_bold,
  1.5846 +#ifdef cimg_use_png
  1.5847 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5848 +#else
  1.5849 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5850 +#endif
  1.5851 +                   cimg::t_normal);
  1.5852 +      cimg_std::fprintf(cimg_stdout,"  > Using JPEG library :     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
  1.5853 +                   cimg::t_bold,
  1.5854 +#ifdef cimg_use_jpeg
  1.5855 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5856 +#else
  1.5857 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5858 +#endif
  1.5859 +                   cimg::t_normal);
  1.5860 +
  1.5861 +      cimg_std::fprintf(cimg_stdout,"  > Using TIFF library :     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
  1.5862 +                   cimg::t_bold,
  1.5863 +#ifdef cimg_use_tiff
  1.5864 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5865 +#else
  1.5866 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5867 +#endif
  1.5868 +                   cimg::t_normal);
  1.5869 +
  1.5870 +      cimg_std::fprintf(cimg_stdout,"  > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
  1.5871 +                   cimg::t_bold,
  1.5872 +#ifdef cimg_use_magick
  1.5873 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5874 +#else
  1.5875 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5876 +#endif
  1.5877 +                   cimg::t_normal);
  1.5878 +
  1.5879 +      cimg_std::fprintf(cimg_stdout,"  > Using FFTW3 library :    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
  1.5880 +                   cimg::t_bold,
  1.5881 +#ifdef cimg_use_fftw3
  1.5882 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5883 +#else
  1.5884 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5885 +#endif
  1.5886 +                   cimg::t_normal);
  1.5887 +
  1.5888 +      cimg_std::fprintf(cimg_stdout,"  > Using LAPACK library :   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
  1.5889 +                   cimg::t_bold,
  1.5890 +#ifdef cimg_use_lapack
  1.5891 +                   "Yes",cimg::t_normal,cimg::t_green,"defined",
  1.5892 +#else
  1.5893 +                   "No",cimg::t_normal,cimg::t_green,"undefined",
  1.5894 +#endif
  1.5895 +                   cimg::t_normal);
  1.5896 +
  1.5897 +      cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
  1.5898 +      cimg_std::fprintf(cimg_stdout,"  > Path of ImageMagick :    %s%-13s%s\n",
  1.5899 +                   cimg::t_bold,
  1.5900 +                   tmp,
  1.5901 +                   cimg::t_normal);
  1.5902 +
  1.5903 +      cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
  1.5904 +      cimg_std::fprintf(cimg_stdout,"  > Path of GraphicsMagick : %s%-13s%s\n",
  1.5905 +                   cimg::t_bold,
  1.5906 +                   tmp,
  1.5907 +                   cimg::t_normal);
  1.5908 +
  1.5909 +      cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
  1.5910 +      cimg_std::fprintf(cimg_stdout,"  > Path of 'medcon' :       %s%-13s%s\n",
  1.5911 +                   cimg::t_bold,
  1.5912 +                   tmp,
  1.5913 +                   cimg::t_normal);
  1.5914 +
  1.5915 +      cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
  1.5916 +      cimg_std::fprintf(cimg_stdout,"  > Temporary path :         %s%-13s%s\n",
  1.5917 +                   cimg::t_bold,
  1.5918 +                   tmp,
  1.5919 +                   cimg::t_normal);
  1.5920 +
  1.5921 +      cimg_std::fprintf(cimg_stdout,"\n");
  1.5922 +    }
  1.5923 +
  1.5924 +    // Declare LAPACK function signatures if necessary.
  1.5925 +    //
  1.5926 +#ifdef cimg_use_lapack
  1.5927 +    template<typename T>
  1.5928 +    inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
  1.5929 +      dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
  1.5930 +    }
  1.5931 +
  1.5932 +    inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
  1.5933 +      sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
  1.5934 +    }
  1.5935 +
  1.5936 +    template<typename T>
  1.5937 +    inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
  1.5938 +      dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
  1.5939 +    }
  1.5940 +
  1.5941 +    inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
  1.5942 +      sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
  1.5943 +    }
  1.5944 +
  1.5945 +    template<typename T>
  1.5946 +    inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
  1.5947 +                      T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
  1.5948 +      dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
  1.5949 +    }
  1.5950 +
  1.5951 +    inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
  1.5952 +                      float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
  1.5953 +      sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
  1.5954 +    }
  1.5955 +
  1.5956 +    template<typename T>
  1.5957 +    inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
  1.5958 +      int one = 1;
  1.5959 +      dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
  1.5960 +    }
  1.5961 +
  1.5962 +    inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
  1.5963 +      int one = 1;
  1.5964 +      sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
  1.5965 +    }
  1.5966 +
  1.5967 +    template<typename T>
  1.5968 +    inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
  1.5969 +      dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
  1.5970 +    }
  1.5971 +
  1.5972 +    inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
  1.5973 +      ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
  1.5974 +    }
  1.5975 +#endif
  1.5976 +
  1.5977 +    // End of the 'cimg' namespace
  1.5978 +  }
  1.5979 +
  1.5980 +  /*------------------------------------------------
  1.5981 +   #
  1.5982 +   #
  1.5983 +   #   Definition of mathematical operators and
  1.5984 +   #   external functions.
  1.5985 +   #
  1.5986 +   #
  1.5987 +   -------------------------------------------------*/
  1.5988 +  //
  1.5989 +  // These functions are extern to any classes and can be used for a "functional-style" programming,
  1.5990 +  // such as writting :
  1.5991 +  //                     cos(img);
  1.5992 +  // instead of          img.get_cos();
  1.5993 +  //
  1.5994 +  // Note that only the arithmetic operators and functions are implemented here.
  1.5995 +  //
  1.5996 +
  1.5997 +#ifdef cimg_use_visualcpp6
  1.5998 +  template<typename t>
  1.5999 +  inline CImg<t> operator+(const CImg<t>& img, const t val) {
  1.6000 +    return CImg<t>(img,false)+=val;
  1.6001 +  }
  1.6002 +#else
  1.6003 +  template<typename t1, typename t2>
  1.6004 +  inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
  1.6005 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6006 +    return CImg<t1t2>(img,false)+=val;
  1.6007 + }
  1.6008 +#endif
  1.6009 +
  1.6010 +#ifdef cimg_use_visualcpp6
  1.6011 +  template<typename t>
  1.6012 +  inline CImg<t> operator+(const t val, const CImg<t>& img) {
  1.6013 +    return img + val;
  1.6014 +  }
  1.6015 +#else
  1.6016 +  template<typename t1, typename t2>
  1.6017 +  inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
  1.6018 +    return img + val;
  1.6019 +  }
  1.6020 +#endif
  1.6021 +
  1.6022 +#ifdef cimg_use_visualcpp6
  1.6023 +  template<typename t>
  1.6024 +  inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
  1.6025 +    return CImgList<t>(list)+=val;
  1.6026 +  }
  1.6027 +#else
  1.6028 +  template<typename t1, typename t2>
  1.6029 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
  1.6030 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6031 +    return CImgList<t1t2>(list)+=val;
  1.6032 +  }
  1.6033 +#endif
  1.6034 +
  1.6035 +#ifdef cimg_use_visualcpp6
  1.6036 +  template<typename t>
  1.6037 +  inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
  1.6038 +    return list + val;
  1.6039 +  }
  1.6040 +#else
  1.6041 +  template<typename t1, typename t2>
  1.6042 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
  1.6043 +    return list + val;
  1.6044 +  }
  1.6045 +#endif
  1.6046 +
  1.6047 +  template<typename t1, typename t2>
  1.6048 +  inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
  1.6049 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6050 +    return CImg<t1t2>(img1,false)+=img2;
  1.6051 +  }
  1.6052 +
  1.6053 +  template<typename t1, typename t2>
  1.6054 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
  1.6055 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6056 +    return CImgList<t1t2>(list)+=img;
  1.6057 +  }
  1.6058 +
  1.6059 +  template<typename t1, typename t2>
  1.6060 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
  1.6061 +    return img + list;
  1.6062 +  }
  1.6063 +
  1.6064 +  template<typename t1, typename t2>
  1.6065 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  1.6066 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6067 +    return CImgList<t1t2>(list1)+=list2;
  1.6068 +  }
  1.6069 +
  1.6070 +#ifdef cimg_use_visualcpp6
  1.6071 +  template<typename t>
  1.6072 +  inline CImg<t> operator-(const CImg<t>& img, const t val) {
  1.6073 +    return CImg<t>(img,false)-=val;
  1.6074 +  }
  1.6075 +#else
  1.6076 +  template<typename t1, typename t2>
  1.6077 +  inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
  1.6078 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6079 +    return CImg<t1t2>(img,false)-=val;
  1.6080 +  }
  1.6081 +#endif
  1.6082 +
  1.6083 +#ifdef cimg_use_visualcpp6
  1.6084 +  template<typename t>
  1.6085 +  inline CImg<t> operator-(const t val, const CImg<t>& img) {
  1.6086 +    return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
  1.6087 +  }
  1.6088 +#else
  1.6089 +  template<typename t1, typename t2>
  1.6090 +  inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
  1.6091 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6092 +    return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
  1.6093 +  }
  1.6094 +#endif
  1.6095 +
  1.6096 +#ifdef cimg_use_visualcpp6
  1.6097 +  template<typename t>
  1.6098 +  inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
  1.6099 +    return CImgList<t>(list)-=val;
  1.6100 +  }
  1.6101 +#else
  1.6102 +  template<typename t1, typename t2>
  1.6103 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
  1.6104 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6105 +    return CImgList<t1t2>(list)-=val;
  1.6106 +  }
  1.6107 +#endif
  1.6108 +
  1.6109 +#ifdef cimg_use_visualcpp6
  1.6110 +  template<typename t>
  1.6111 +  inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
  1.6112 +    CImgList<t> res(list.size);
  1.6113 +    cimglist_for(res,l) res[l] = val - list[l];
  1.6114 +    return res;
  1.6115 +  }
  1.6116 +#else
  1.6117 +  template<typename t1, typename t2>
  1.6118 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
  1.6119 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6120 +    CImgList<t1t2> res(list.size);
  1.6121 +    cimglist_for(res,l) res[l] = val - list[l];
  1.6122 +    return res;
  1.6123 +  }
  1.6124 +#endif
  1.6125 +
  1.6126 +  template<typename t1, typename t2>
  1.6127 +  inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
  1.6128 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6129 +    return CImg<t1t2>(img1,false)-=img2;
  1.6130 +  }
  1.6131 +
  1.6132 +  template<typename t1, typename t2>
  1.6133 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
  1.6134 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6135 +    CImgList<t1t2> res(list.size);
  1.6136 +    cimglist_for(res,l) res[l] = img - list[l];
  1.6137 +    return res;
  1.6138 +  }
  1.6139 +
  1.6140 +  template<typename t1, typename t2>
  1.6141 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
  1.6142 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6143 +    return CImgList<t1t2>(list)-=img;
  1.6144 +  }
  1.6145 +
  1.6146 +  template<typename t1, typename t2>
  1.6147 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  1.6148 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6149 +    return CImgList<t1t2>(list1)-=list2;
  1.6150 +  }
  1.6151 +
  1.6152 +#ifdef cimg_use_visualcpp6
  1.6153 +  template<typename t>
  1.6154 +  inline CImg<t> operator*(const CImg<t>& img, const double val) {
  1.6155 +    return CImg<t>(img,false)*=val;
  1.6156 +  }
  1.6157 +#else
  1.6158 +  template<typename t1, typename t2>
  1.6159 +  inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
  1.6160 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6161 +    return CImg<t1t2>(img,false)*=val;
  1.6162 +  }
  1.6163 +#endif
  1.6164 +
  1.6165 +#ifdef cimg_use_visualcpp6
  1.6166 +  template<typename t>
  1.6167 +  inline CImg<t> operator*(const double val, const CImg<t>& img) {
  1.6168 +    return img*val;
  1.6169 +  }
  1.6170 +#else
  1.6171 +  template<typename t1, typename t2>
  1.6172 +  inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
  1.6173 +    return img*val;
  1.6174 +  }
  1.6175 +#endif
  1.6176 +
  1.6177 +#ifdef cimg_use_visualcpp6
  1.6178 +  template<typename t>
  1.6179 +  inline CImgList<t> operator*(const CImgList<t>& list, const double val) {
  1.6180 +    return CImgList<t>(list)*=val;
  1.6181 +  }
  1.6182 +#else
  1.6183 +  template<typename t1, typename t2>
  1.6184 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
  1.6185 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6186 +    return CImgList<t1t2>(list)*=val;
  1.6187 +  }
  1.6188 +#endif
  1.6189 +
  1.6190 +#ifdef cimg_use_visualcpp6
  1.6191 +  template<typename t>
  1.6192 +  inline CImgList<t> operator*(const double val, const CImgList<t>& list) {
  1.6193 +    return list*val;
  1.6194 +  }
  1.6195 +#else
  1.6196 +  template<typename t1, typename t2>
  1.6197 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
  1.6198 +    return list*val;
  1.6199 +  }
  1.6200 +#endif
  1.6201 +
  1.6202 +  template<typename t1, typename t2>
  1.6203 +  inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
  1.6204 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6205 +    if (img1.width!=img2.height)
  1.6206 +      throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
  1.6207 +                                  img1.width,img1.height,img2.width,img2.height);
  1.6208 +    CImg<t1t2> res(img2.width,img1.height);
  1.6209 +    t1t2 val;
  1.6210 +#ifdef cimg_use_openmp
  1.6211 +#pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
  1.6212 +#endif
  1.6213 +    cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
  1.6214 +    return res;
  1.6215 +  }
  1.6216 +
  1.6217 +  template<typename t1, typename t2>
  1.6218 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
  1.6219 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6220 +    CImgList<t1t2> res(list.size);
  1.6221 +    cimglist_for(res,l) res[l] = img*list[l];
  1.6222 +    return res;
  1.6223 +  }
  1.6224 +
  1.6225 +  template<typename t1, typename t2>
  1.6226 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
  1.6227 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6228 +    CImgList<t1t2> res(list.size);
  1.6229 +    cimglist_for(res,l) res[l] = list[l]*img;
  1.6230 +    return res;
  1.6231 +  }
  1.6232 +
  1.6233 +  template<typename t1, typename t2>
  1.6234 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  1.6235 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6236 +    CImgList<t1t2> res(cimg::min(list1.size,list2.size));
  1.6237 +    cimglist_for(res,l) res[l] = list1[l]*list2[l];
  1.6238 +    return res;
  1.6239 +  }
  1.6240 +
  1.6241 +#ifdef cimg_use_visualcpp6
  1.6242 +  template<typename t>
  1.6243 +  inline CImg<t> operator/(const CImg<t>& img, const double val) {
  1.6244 +    return CImg<t>(img,false)/=val;
  1.6245 +  }
  1.6246 +#else
  1.6247 +  template<typename t1, typename t2>
  1.6248 +  inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
  1.6249 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6250 +    return CImg<t1t2>(img,false)/=val;
  1.6251 +  }
  1.6252 +#endif
  1.6253 +
  1.6254 +#ifdef cimg_use_visualcpp6
  1.6255 +  template<typename t>
  1.6256 +  inline CImg<t> operator/(const double val, CImg<t>& img) {
  1.6257 +    return val*img.get_invert();
  1.6258 +  }
  1.6259 +#else
  1.6260 +  template<typename t1, typename t2>
  1.6261 +  inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
  1.6262 +    return val*img.get_invert();
  1.6263 +  }
  1.6264 +#endif
  1.6265 +
  1.6266 +#ifdef cimg_use_visualcpp6
  1.6267 +  template<typename t>
  1.6268 +  inline CImgList<t> operator/(const CImgList<t>& list, const double val) {
  1.6269 +    return CImgList<t>(list)/=val;
  1.6270 +  }
  1.6271 +#else
  1.6272 +  template<typename t1, typename t2>
  1.6273 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
  1.6274 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6275 +    return CImgList<t1t2>(list)/=val;
  1.6276 +  }
  1.6277 +#endif
  1.6278 +
  1.6279 +#ifdef cimg_use_visualcpp6
  1.6280 +  template<typename t>
  1.6281 +  inline CImgList<t> operator/(const double val, const CImgList<t>& list) {
  1.6282 +    CImgList<t> res(list.size);
  1.6283 +    cimglist_for(res,l) res[l] = val/list[l];
  1.6284 +    return res;
  1.6285 +  }
  1.6286 +#else
  1.6287 +  template<typename t1, typename t2>
  1.6288 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
  1.6289 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6290 +    CImgList<t1t2> res(list.size);
  1.6291 +    cimglist_for(res,l) res[l] = val/list[l];
  1.6292 +    return res;
  1.6293 +  }
  1.6294 +#endif
  1.6295 +
  1.6296 +  template<typename t1, typename t2>
  1.6297 +  inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
  1.6298 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6299 +    return CImg<t1t2>(img1,false)*=img2.get_invert();
  1.6300 +  }
  1.6301 +
  1.6302 +  template<typename t1, typename t2>
  1.6303 +  inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
  1.6304 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6305 +    CImgList<t1t2> res(list.size);
  1.6306 +    cimglist_for(res,l) res[l] = img/list[l];
  1.6307 +    return res;
  1.6308 +  }
  1.6309 +
  1.6310 +  template<typename t1, typename t2>
  1.6311 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
  1.6312 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6313 +    return CImgList<t1t2>(list)/=img;
  1.6314 +  }
  1.6315 +
  1.6316 +  template<typename t1, typename t2>
  1.6317 +  inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
  1.6318 +    typedef typename cimg::superset<t1,t2>::type t1t2;
  1.6319 +    return CImgList<t1t2>(list1)/=list2;
  1.6320 +  }
  1.6321 +
  1.6322 +  template<typename T>
  1.6323 +  inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
  1.6324 +    return instance.get_sqr();
  1.6325 +  }
  1.6326 +
  1.6327 +  template<typename T>
  1.6328 +  inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
  1.6329 +    return instance.get_sqrt();
  1.6330 +  }
  1.6331 +
  1.6332 +  template<typename T>
  1.6333 +  inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
  1.6334 +    return instance.get_exp();
  1.6335 +  }
  1.6336 +
  1.6337 +  template<typename T>
  1.6338 +  inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
  1.6339 +    return instance.get_log();
  1.6340 +  }
  1.6341 +
  1.6342 +  template<typename T>
  1.6343 +  inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
  1.6344 +    return instance.get_log10();
  1.6345 +  }
  1.6346 +
  1.6347 +  template<typename T>
  1.6348 +  inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
  1.6349 +    return instance.get_abs();
  1.6350 +  }
  1.6351 +
  1.6352 +  template<typename T>
  1.6353 +  inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
  1.6354 +    return instance.get_cos();
  1.6355 +  }
  1.6356 +
  1.6357 +  template<typename T>
  1.6358 +  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
  1.6359 +    return instance.get_sin();
  1.6360 +  }
  1.6361 +
  1.6362 +  template<typename T>
  1.6363 +  inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
  1.6364 +    return instance.get_tan();
  1.6365 +  }
  1.6366 +
  1.6367 +  template<typename T>
  1.6368 +  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
  1.6369 +    return instance.get_acos();
  1.6370 +  }
  1.6371 +
  1.6372 +  template<typename T>
  1.6373 +  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
  1.6374 +    return instance.get_asin();
  1.6375 +  }
  1.6376 +
  1.6377 +  template<typename T>
  1.6378 +  inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
  1.6379 +    return instance.get_atan();
  1.6380 +  }
  1.6381 +
  1.6382 +  template<typename T>
  1.6383 +  inline CImg<T> transpose(const CImg<T>& instance) {
  1.6384 +    return instance.get_transpose();
  1.6385 +  }
  1.6386 +
  1.6387 +  template<typename T>
  1.6388 +  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
  1.6389 +    return instance.get_invert();
  1.6390 +  }
  1.6391 +
  1.6392 +  template<typename T>
  1.6393 +  inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
  1.6394 +    return instance.get_pseudoinvert();
  1.6395 +  }
  1.6396 +
  1.6397 +  /*-------------------------------------------
  1.6398 +   #
  1.6399 +   #
  1.6400 +   #
  1.6401 +   # Definition of the CImgDisplay structure
  1.6402 +   #
  1.6403 +   #
  1.6404 +   #
  1.6405 +   --------------------------------------------*/
  1.6406 +
  1.6407 +  //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
  1.6408 +  /**
  1.6409 +     Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
  1.6410 +     of a \c CImgList<T> image list inside. When a display is created, associated window events
  1.6411 +     (such as mouse motion, keyboard and window size changes) are handled and can be easily
  1.6412 +     detected by testing specific \c CImgDisplay data fields.
  1.6413 +     See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
  1.6414 +  **/
  1.6415 +
  1.6416 +  struct CImgDisplay {
  1.6417 +
  1.6418 +    //! Width of the display
  1.6419 +    unsigned int width;
  1.6420 +
  1.6421 +    //! Height of the display
  1.6422 +    unsigned int height;
  1.6423 +
  1.6424 +    //! Normalization type used for the display
  1.6425 +    unsigned int normalization;
  1.6426 +
  1.6427 +    //! Display title
  1.6428 +    char* title;
  1.6429 +
  1.6430 +    //! X-pos of the display on the screen
  1.6431 +    volatile int window_x;
  1.6432 +
  1.6433 +    //! Y-pos of the display on the screen
  1.6434 +    volatile int window_y;
  1.6435 +
  1.6436 +    //! Width of the underlying window
  1.6437 +    volatile unsigned int window_width;
  1.6438 +
  1.6439 +    //! Height of the underlying window
  1.6440 +    volatile unsigned int window_height;
  1.6441 +
  1.6442 +    //! X-coordinate of the mouse pointer on the display
  1.6443 +    volatile int mouse_x;
  1.6444 +
  1.6445 +    //! Y-coordinate of the mouse pointer on the display
  1.6446 +    volatile int mouse_y;
  1.6447 +
  1.6448 +    //! Button state of the mouse
  1.6449 +    volatile unsigned int buttons[512];
  1.6450 +    volatile unsigned int& button;
  1.6451 +
  1.6452 +    //! Wheel state of the mouse
  1.6453 +    volatile int wheel;
  1.6454 +
  1.6455 +    //! Key value if pressed
  1.6456 +    volatile unsigned int& key;
  1.6457 +    volatile unsigned int keys[512];
  1.6458 +
  1.6459 +    //! Key value if released
  1.6460 +    volatile unsigned int& released_key;
  1.6461 +    volatile unsigned int released_keys[512];
  1.6462 +
  1.6463 +    //! Closed state of the window
  1.6464 +    volatile bool is_closed;
  1.6465 +
  1.6466 +    //! Resized state of the window
  1.6467 +    volatile bool is_resized;
  1.6468 +
  1.6469 +    //! Moved state of the window
  1.6470 +    volatile bool is_moved;
  1.6471 +
  1.6472 +    //! Event state of the window
  1.6473 +    volatile bool is_event;
  1.6474 +
  1.6475 +    //! Current state of the corresponding key (exists for all referenced keys).
  1.6476 +    volatile bool is_keyESC;
  1.6477 +    volatile bool is_keyF1;
  1.6478 +    volatile bool is_keyF2;
  1.6479 +    volatile bool is_keyF3;
  1.6480 +    volatile bool is_keyF4;
  1.6481 +    volatile bool is_keyF5;
  1.6482 +    volatile bool is_keyF6;
  1.6483 +    volatile bool is_keyF7;
  1.6484 +    volatile bool is_keyF8;
  1.6485 +    volatile bool is_keyF9;
  1.6486 +    volatile bool is_keyF10;
  1.6487 +    volatile bool is_keyF11;
  1.6488 +    volatile bool is_keyF12;
  1.6489 +    volatile bool is_keyPAUSE;
  1.6490 +    volatile bool is_key1;
  1.6491 +    volatile bool is_key2;
  1.6492 +    volatile bool is_key3;
  1.6493 +    volatile bool is_key4;
  1.6494 +    volatile bool is_key5;
  1.6495 +    volatile bool is_key6;
  1.6496 +    volatile bool is_key7;
  1.6497 +    volatile bool is_key8;
  1.6498 +    volatile bool is_key9;
  1.6499 +    volatile bool is_key0;
  1.6500 +    volatile bool is_keyBACKSPACE;
  1.6501 +    volatile bool is_keyINSERT;
  1.6502 +    volatile bool is_keyHOME;
  1.6503 +    volatile bool is_keyPAGEUP;
  1.6504 +    volatile bool is_keyTAB;
  1.6505 +    volatile bool is_keyQ;
  1.6506 +    volatile bool is_keyW;
  1.6507 +    volatile bool is_keyE;
  1.6508 +    volatile bool is_keyR;
  1.6509 +    volatile bool is_keyT;
  1.6510 +    volatile bool is_keyY;
  1.6511 +    volatile bool is_keyU;
  1.6512 +    volatile bool is_keyI;
  1.6513 +    volatile bool is_keyO;
  1.6514 +    volatile bool is_keyP;
  1.6515 +    volatile bool is_keyDELETE;
  1.6516 +    volatile bool is_keyEND;
  1.6517 +    volatile bool is_keyPAGEDOWN;
  1.6518 +    volatile bool is_keyCAPSLOCK;
  1.6519 +    volatile bool is_keyA;
  1.6520 +    volatile bool is_keyS;
  1.6521 +    volatile bool is_keyD;
  1.6522 +    volatile bool is_keyF;
  1.6523 +    volatile bool is_keyG;
  1.6524 +    volatile bool is_keyH;
  1.6525 +    volatile bool is_keyJ;
  1.6526 +    volatile bool is_keyK;
  1.6527 +    volatile bool is_keyL;
  1.6528 +    volatile bool is_keyENTER;
  1.6529 +    volatile bool is_keySHIFTLEFT;
  1.6530 +    volatile bool is_keyZ;
  1.6531 +    volatile bool is_keyX;
  1.6532 +    volatile bool is_keyC;
  1.6533 +    volatile bool is_keyV;
  1.6534 +    volatile bool is_keyB;
  1.6535 +    volatile bool is_keyN;
  1.6536 +    volatile bool is_keyM;
  1.6537 +    volatile bool is_keySHIFTRIGHT;
  1.6538 +    volatile bool is_keyARROWUP;
  1.6539 +    volatile bool is_keyCTRLLEFT;
  1.6540 +    volatile bool is_keyAPPLEFT;
  1.6541 +    volatile bool is_keyALT;
  1.6542 +    volatile bool is_keySPACE;
  1.6543 +    volatile bool is_keyALTGR;
  1.6544 +    volatile bool is_keyAPPRIGHT;
  1.6545 +    volatile bool is_keyMENU;
  1.6546 +    volatile bool is_keyCTRLRIGHT;
  1.6547 +    volatile bool is_keyARROWLEFT;
  1.6548 +    volatile bool is_keyARROWDOWN;
  1.6549 +    volatile bool is_keyARROWRIGHT;
  1.6550 +    volatile bool is_keyPAD0;
  1.6551 +    volatile bool is_keyPAD1;
  1.6552 +    volatile bool is_keyPAD2;
  1.6553 +    volatile bool is_keyPAD3;
  1.6554 +    volatile bool is_keyPAD4;
  1.6555 +    volatile bool is_keyPAD5;
  1.6556 +    volatile bool is_keyPAD6;
  1.6557 +    volatile bool is_keyPAD7;
  1.6558 +    volatile bool is_keyPAD8;
  1.6559 +    volatile bool is_keyPAD9;
  1.6560 +    volatile bool is_keyPADADD;
  1.6561 +    volatile bool is_keyPADSUB;
  1.6562 +    volatile bool is_keyPADMUL;
  1.6563 +    volatile bool is_keyPADDIV;
  1.6564 +
  1.6565 +    //! Fullscreen state of the display
  1.6566 +    bool is_fullscreen;
  1.6567 +
  1.6568 +    float fps_fps, min, max;
  1.6569 +    unsigned long timer, fps_frames, fps_timer;
  1.6570 +
  1.6571 +#ifdef cimgdisplay_plugin
  1.6572 +#include cimgdisplay_plugin
  1.6573 +#endif
  1.6574 +#ifdef cimgdisplay_plugin1
  1.6575 +#include cimgdisplay_plugin1
  1.6576 +#endif
  1.6577 +#ifdef cimgdisplay_plugin2
  1.6578 +#include cimgdisplay_plugin2
  1.6579 +#endif
  1.6580 +#ifdef cimgdisplay_plugin3
  1.6581 +#include cimgdisplay_plugin3
  1.6582 +#endif
  1.6583 +#ifdef cimgdisplay_plugin4
  1.6584 +#include cimgdisplay_plugin4
  1.6585 +#endif
  1.6586 +#ifdef cimgdisplay_plugin5
  1.6587 +#include cimgdisplay_plugin5
  1.6588 +#endif
  1.6589 +#ifdef cimgdisplay_plugin6
  1.6590 +#include cimgdisplay_plugin6
  1.6591 +#endif
  1.6592 +#ifdef cimgdisplay_plugin7
  1.6593 +#include cimgdisplay_plugin7
  1.6594 +#endif
  1.6595 +#ifdef cimgdisplay_plugin8
  1.6596 +#include cimgdisplay_plugin8
  1.6597 +#endif
  1.6598 +
  1.6599 +    //! Create an empty display window.
  1.6600 +    CImgDisplay():
  1.6601 +      width(0),height(0),normalization(0),title(0),
  1.6602 +      window_x(0),window_y(0),window_width(0),window_height(0),
  1.6603 +      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  1.6604 +      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
  1.6605 +      min(0),max(0) {}
  1.6606 +
  1.6607 +    //! Create a display window with a specified size \p pwidth x \p height.
  1.6608 +    /** \param dimw Width of the display window.
  1.6609 +        \param dimh Height of the display window.
  1.6610 +        \param title Title of the display window.
  1.6611 +        \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
  1.6612 +        \param fullscreen_flag : Fullscreen mode.
  1.6613 +        \param closed_flag : Initially visible mode.
  1.6614 +        A black image will be initially displayed in the display window.
  1.6615 +    **/
  1.6616 +    CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  1.6617 +                const unsigned int normalization_type=3,
  1.6618 +                const bool fullscreen_flag=false, const bool closed_flag=false):
  1.6619 +      width(0),height(0),normalization(0),title(0),
  1.6620 +      window_x(0),window_y(0),window_width(0),window_height(0),
  1.6621 +      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  1.6622 +      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
  1.6623 +      min(0),max(0) {
  1.6624 +      assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  1.6625 +    }
  1.6626 +
  1.6627 +    //! Create a display window from an image.
  1.6628 +    /** \param img : Image that will be used to create the display window.
  1.6629 +        \param title : Title of the display window
  1.6630 +        \param normalization_type : Normalization type of the display window.
  1.6631 +        \param fullscreen_flag : Fullscreen mode.
  1.6632 +        \param closed_flag : Initially visible mode.
  1.6633 +    **/
  1.6634 +    template<typename T>
  1.6635 +    CImgDisplay(const CImg<T>& img, const char *title=0,
  1.6636 +                const unsigned int normalization_type=3,
  1.6637 +                const bool fullscreen_flag=false, const bool closed_flag=false):
  1.6638 +      width(0),height(0),normalization(0),title(0),
  1.6639 +      window_x(0),window_y(0),window_width(0),window_height(0),
  1.6640 +      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  1.6641 +      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  1.6642 +      assign(img,title,normalization_type,fullscreen_flag,closed_flag);
  1.6643 +    }
  1.6644 +
  1.6645 +    //! Create a display window from an image list.
  1.6646 +    /** \param list : The list of images to display.
  1.6647 +        \param title : Title of the display window
  1.6648 +        \param normalization_type : Normalization type of the display window.
  1.6649 +        \param fullscreen_flag : Fullscreen mode.
  1.6650 +        \param closed_flag : Initially visible mode.
  1.6651 +    **/
  1.6652 +    template<typename T>
  1.6653 +    CImgDisplay(const CImgList<T>& list, const char *title=0,
  1.6654 +                const unsigned int normalization_type=3,
  1.6655 +                const bool fullscreen_flag=false, const bool closed_flag=false):
  1.6656 +      width(0),height(0),normalization(0),title(0),
  1.6657 +      window_x(0),window_y(0),window_width(0),window_height(0),
  1.6658 +      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  1.6659 +      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  1.6660 +      assign(list,title,normalization_type,fullscreen_flag,closed_flag);
  1.6661 +    }
  1.6662 +
  1.6663 +    //! Create a display window by copying another one.
  1.6664 +    /**
  1.6665 +        \param disp  : Display window to copy.
  1.6666 +    **/
  1.6667 +    CImgDisplay(const CImgDisplay& disp):
  1.6668 +      width(0),height(0),normalization(0),title(0),
  1.6669 +      window_x(0),window_y(0),window_width(0),window_height(0),
  1.6670 +      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
  1.6671 +      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
  1.6672 +      assign(disp);
  1.6673 +    }
  1.6674 +
  1.6675 +    //! Destructor.
  1.6676 +    ~CImgDisplay() {
  1.6677 +      assign();
  1.6678 +    }
  1.6679 +
  1.6680 +    //! Assignment operator.
  1.6681 +    CImgDisplay& operator=(const CImgDisplay& disp) {
  1.6682 +      return assign(disp);
  1.6683 +    }
  1.6684 +
  1.6685 +    //! Return true is display is empty.
  1.6686 +    bool is_empty() const {
  1.6687 +      return (!width || !height);
  1.6688 +    }
  1.6689 +
  1.6690 +    //! Return true if display is not empty.
  1.6691 +    operator bool() const {
  1.6692 +      return !is_empty();
  1.6693 +    }
  1.6694 +
  1.6695 +    //! Return display width.
  1.6696 +    int dimx() const {
  1.6697 +      return (int)width;
  1.6698 +    }
  1.6699 +
  1.6700 +    //! Return display height.
  1.6701 +    int dimy() const {
  1.6702 +      return (int)height;
  1.6703 +    }
  1.6704 +
  1.6705 +    //! Return display window width.
  1.6706 +    int window_dimx() const {
  1.6707 +      return (int)window_width;
  1.6708 +    }
  1.6709 +
  1.6710 +    //! Return display window height.
  1.6711 +    int window_dimy() const {
  1.6712 +      return (int)window_height;
  1.6713 +    }
  1.6714 +
  1.6715 +    //! Return X-coordinate of the window.
  1.6716 +    int window_posx() const {
  1.6717 +      return window_x;
  1.6718 +    }
  1.6719 +
  1.6720 +    //! Return Y-coordinate of the window.
  1.6721 +    int window_posy() const {
  1.6722 +      return window_y;
  1.6723 +    }
  1.6724 +
  1.6725 +    //! Synchronized waiting function. Same as cimg::wait().
  1.6726 +    CImgDisplay& wait(const unsigned int milliseconds) {
  1.6727 +      cimg::_sleep(milliseconds,timer);
  1.6728 +      return *this;
  1.6729 +    }
  1.6730 +
  1.6731 +    //! Wait for an event occuring on the current display.
  1.6732 +    CImgDisplay& wait() {
  1.6733 +      if (!is_empty()) wait(*this);
  1.6734 +      return *this;
  1.6735 +    }
  1.6736 +
  1.6737 +    //! Wait for any event occuring on the display \c disp1.
  1.6738 +    static void wait(CImgDisplay& disp1) {
  1.6739 +      disp1.is_event = 0;
  1.6740 +      while (!disp1.is_event) wait_all();
  1.6741 +    }
  1.6742 +
  1.6743 +    //! Wait for any event occuring either on the display \c disp1 or \c disp2.
  1.6744 +    static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
  1.6745 +      disp1.is_event = disp2.is_event = 0;
  1.6746 +      while (!disp1.is_event && !disp2.is_event) wait_all();
  1.6747 +    }
  1.6748 +
  1.6749 +    //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
  1.6750 +    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
  1.6751 +      disp1.is_event = disp2.is_event = disp3.is_event = 0;
  1.6752 +      while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
  1.6753 +    }
  1.6754 +
  1.6755 +    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
  1.6756 +    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
  1.6757 +      disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
  1.6758 +      while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
  1.6759 +    }
  1.6760 +
  1.6761 +    //! Return the frame per second rate.
  1.6762 +    float frames_per_second() {
  1.6763 +      if (!fps_timer) fps_timer = cimg::time();
  1.6764 +      const float delta = (cimg::time()-fps_timer)/1000.0f;
  1.6765 +      ++fps_frames;
  1.6766 +      if (delta>=1) {
  1.6767 +        fps_fps = fps_frames/delta;
  1.6768 +        fps_frames = 0;
  1.6769 +        fps_timer = cimg::time();
  1.6770 +      }
  1.6771 +      return fps_fps;
  1.6772 +    }
  1.6773 +
  1.6774 +    //! Display an image list CImgList<T> into a display window.
  1.6775 +    /** First, all images of the list are appended into a single image used for visualization,
  1.6776 +        then this image is displayed in the current display window.
  1.6777 +        \param list     : The list of images to display.
  1.6778 +        \param axis     : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
  1.6779 +        \param align : Defines the relative alignment of images when displaying images of different sizes.
  1.6780 +        Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
  1.6781 +    **/
  1.6782 +    template<typename T>
  1.6783 +    CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
  1.6784 +      return display(list.get_append(axis,align));
  1.6785 +    }
  1.6786 +
  1.6787 +    //! Display an image CImg<T> into a display window.
  1.6788 +    template<typename T>
  1.6789 +    CImgDisplay& operator<<(const CImg<T>& img) {
  1.6790 +      return display(img);
  1.6791 +    }
  1.6792 +
  1.6793 +    //! Display an image CImg<T> into a display window.
  1.6794 +    template<typename T>
  1.6795 +    CImgDisplay& operator<<(const CImgList<T>& list) {
  1.6796 +      return display(list);
  1.6797 +    }
  1.6798 +
  1.6799 +    //! Resize a display window with the size of an image.
  1.6800 +    /** \param img    : Input image. \p image.width and \p image.height give the new dimensions of the display window.
  1.6801 +        \param redraw : If \p true (default), the current displayed image in the display window will
  1.6802 +        be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
  1.6803 +    **/
  1.6804 +    template<typename T>
  1.6805 +    CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
  1.6806 +      return resize(img.width,img.height,redraw);
  1.6807 +    }
  1.6808 +
  1.6809 +    //! Resize a display window using the size of the given display \p disp.
  1.6810 +    CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
  1.6811 +      return resize(disp.width,disp.height,redraw);
  1.6812 +    }
  1.6813 +
  1.6814 +    //! Resize a display window in its current size.
  1.6815 +    CImgDisplay& resize(const bool redraw=true) {
  1.6816 +      resize(window_width,window_height,redraw);
  1.6817 +      return *this;
  1.6818 +    }
  1.6819 +
  1.6820 +    //! Set fullscreen mode.
  1.6821 +    CImgDisplay& fullscreen(const bool redraw=true) {
  1.6822 +      if (is_empty() || is_fullscreen) return *this;
  1.6823 +      return toggle_fullscreen(redraw);
  1.6824 +    }
  1.6825 +
  1.6826 +    //! Set normal screen mode.
  1.6827 +    CImgDisplay& normalscreen(const bool redraw=true) {
  1.6828 +      if (is_empty() || !is_fullscreen) return *this;
  1.6829 +      return toggle_fullscreen(redraw);
  1.6830 +    }
  1.6831 +
  1.6832 +    // Inner routine used for fast resizing of buffer to display size.
  1.6833 +    template<typename t, typename T>
  1.6834 +    static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
  1.6835 +                               t *ptrd, const unsigned int wd, const unsigned int hd) {
  1.6836 +      unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
  1.6837 +      float s, curr, old;
  1.6838 +      s = (float)ws/wd;
  1.6839 +      poffx = offx; curr = 0; for (unsigned int x=0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
  1.6840 +      s = (float)hs/hd;
  1.6841 +      poffy = offy; curr = 0; for (unsigned int y=0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
  1.6842 +      *poffy = 0;
  1.6843 +      poffy = offy;
  1.6844 +      {for (unsigned int y=0; y<hd; ) {
  1.6845 +        const T *ptr = ptrs;
  1.6846 +        poffx = offx;
  1.6847 +        for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
  1.6848 +        ++y;
  1.6849 +        unsigned int dy=*(poffy++);
  1.6850 +        for (;!dy && y<hd; cimg_std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
  1.6851 +        ptrs+=dy;
  1.6852 +      }}
  1.6853 +      delete[] offx; delete[] offy;
  1.6854 +    }
  1.6855 +
  1.6856 +    //! Clear all events of the current display.
  1.6857 +    CImgDisplay& flush() {
  1.6858 +      cimg_std::memset((void*)buttons,0,512*sizeof(unsigned int));
  1.6859 +      cimg_std::memset((void*)keys,0,512*sizeof(unsigned int));
  1.6860 +      cimg_std::memset((void*)released_keys,0,512*sizeof(unsigned int));
  1.6861 +      is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
  1.6862 +        is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
  1.6863 +        is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
  1.6864 +        is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
  1.6865 +        is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
  1.6866 +        is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
  1.6867 +        is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keyALT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
  1.6868 +        is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
  1.6869 +        is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
  1.6870 +        is_keyPADMUL = is_keyPADDIV = false;
  1.6871 +      is_resized = is_moved = is_event = false;
  1.6872 +      fps_timer = fps_frames = timer = wheel = 0;
  1.6873 +      mouse_x = mouse_y = -1;
  1.6874 +      fps_fps = 0;
  1.6875 +      return *this;
  1.6876 +    }
  1.6877 +
  1.6878 +    // Update 'is_key' fields.
  1.6879 +    void update_iskey(const unsigned int key, const bool pressed=true) {
  1.6880 +#define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
  1.6881 +      _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
  1.6882 +      _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
  1.6883 +      _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
  1.6884 +      _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
  1.6885 +      _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
  1.6886 +      _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
  1.6887 +      _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
  1.6888 +      _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
  1.6889 +      _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
  1.6890 +      _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
  1.6891 +      _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
  1.6892 +      _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
  1.6893 +      _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
  1.6894 +      _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
  1.6895 +      _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
  1.6896 +      _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
  1.6897 +      _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
  1.6898 +      _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
  1.6899 +      _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
  1.6900 +      _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
  1.6901 +      _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
  1.6902 +      _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
  1.6903 +      _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
  1.6904 +      _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
  1.6905 +      _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
  1.6906 +    }
  1.6907 +
  1.6908 +    //! Test if any key has been pressed.
  1.6909 +    bool is_key(const bool remove=false) {
  1.6910 +      for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
  1.6911 +      return false;
  1.6912 +    }
  1.6913 +
  1.6914 +    //! Test if a key has been pressed.
  1.6915 +    bool is_key(const unsigned int key1, const bool remove) {
  1.6916 +      for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
  1.6917 +      return false;
  1.6918 +    }
  1.6919 +
  1.6920 +    //! Test if a key sequence has been typed.
  1.6921 +    bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
  1.6922 +      const unsigned int seq[] = { key1, key2 };
  1.6923 +      return is_key(seq,2,remove);
  1.6924 +    }
  1.6925 +
  1.6926 +    //! Test if a key sequence has been typed.
  1.6927 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
  1.6928 +      const unsigned int seq[] = { key1, key2, key3 };
  1.6929 +      return is_key(seq,3,remove);
  1.6930 +    }
  1.6931 +
  1.6932 +    //! Test if a key sequence has been typed.
  1.6933 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6934 +                 const unsigned int key4, const bool remove) {
  1.6935 +      const unsigned int seq[] = { key1, key2, key3, key4 };
  1.6936 +      return is_key(seq,4,remove);
  1.6937 +    }
  1.6938 +
  1.6939 +    //! Test if a key sequence has been typed.
  1.6940 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6941 +                const unsigned int key4, const unsigned int key5, const bool remove) {
  1.6942 +      const unsigned int seq[] = { key1, key2, key3, key4, key5 };
  1.6943 +      return is_key(seq,5,remove);
  1.6944 +    }
  1.6945 +
  1.6946 +    //! Test if a key sequence has been typed.
  1.6947 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6948 +                const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
  1.6949 +      const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
  1.6950 +      return is_key(seq,6,remove);
  1.6951 +    }
  1.6952 +
  1.6953 +    //! Test if a key sequence has been typed.
  1.6954 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6955 +                const unsigned int key4, const unsigned int key5, const unsigned int key6,
  1.6956 +                const unsigned int key7, const bool remove) {
  1.6957 +      const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
  1.6958 +      return is_key(seq,7,remove);
  1.6959 +    }
  1.6960 +
  1.6961 +    //! Test if a key sequence has been typed.
  1.6962 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6963 +                const unsigned int key4, const unsigned int key5, const unsigned int key6,
  1.6964 +                const unsigned int key7, const unsigned int key8, const bool remove) {
  1.6965 +      const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
  1.6966 +      return is_key(seq,8,remove);
  1.6967 +    }
  1.6968 +
  1.6969 +    //! Test if a key sequence has been typed.
  1.6970 +    bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
  1.6971 +                const unsigned int key4, const unsigned int key5, const unsigned int key6,
  1.6972 +                const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
  1.6973 +      const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
  1.6974 +      return is_key(seq,9,remove);
  1.6975 +    }
  1.6976 +
  1.6977 +    //! Test if a key sequence has been typed.
  1.6978 +    bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
  1.6979 +      if (keyseq && N) {
  1.6980 +        const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
  1.6981 +        for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
  1.6982 +          if (*(pk++)==k) {
  1.6983 +            bool res = true;
  1.6984 +            const unsigned int *ps = ps_end, *pk2 = pk;
  1.6985 +            for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
  1.6986 +            if (res) {
  1.6987 +              if (remove) cimg_std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
  1.6988 +              return true;
  1.6989 +            }
  1.6990 +          }
  1.6991 +        }
  1.6992 +      }
  1.6993 +      return false;
  1.6994 +    }
  1.6995 +
  1.6996 +    // Find the good width and height of a window to display an image (internal routine).
  1.6997 +#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
  1.6998 +    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
  1.6999 +                                   const int dmin=128, const int dmax=-85,const bool return_last=false) {
  1.7000 +      unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
  1.7001 +      const unsigned int
  1.7002 +        sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
  1.7003 +        mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
  1.7004 +        mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
  1.7005 +        Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
  1.7006 +        Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
  1.7007 +      if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
  1.7008 +      if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
  1.7009 +      if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
  1.7010 +      if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
  1.7011 +      if (nw<mw) nw = mw;
  1.7012 +      if (nh<mh) nh = mh;
  1.7013 +      if (return_last) return nh;
  1.7014 +      return nw;
  1.7015 +    }
  1.7016 +
  1.7017 +    // When no display available
  1.7018 +    //---------------------------
  1.7019 +#if cimg_display==0
  1.7020 +
  1.7021 +    //! Return the width of the screen resolution.
  1.7022 +    static int screen_dimx() {
  1.7023 +      return 0;
  1.7024 +    }
  1.7025 +
  1.7026 +    //! Return the height of the screen resolution.
  1.7027 +    static int screen_dimy() {
  1.7028 +      return 0;
  1.7029 +    }
  1.7030 +
  1.7031 +    //! Wait for a window event in any CImg window.
  1.7032 +    static void wait_all() {}
  1.7033 +
  1.7034 +    //! In-place version of the destructor.
  1.7035 +    CImgDisplay& assign() {
  1.7036 +      return *this;
  1.7037 +    }
  1.7038 +
  1.7039 +    //! In-place version of the previous constructor.
  1.7040 +    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  1.7041 +                        const unsigned int normalization_type=3,
  1.7042 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7043 +      throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
  1.7044 +      const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  1.7045 +      avoid_warning = 0;
  1.7046 +      return *this;
  1.7047 +    }
  1.7048 +
  1.7049 +    //! In-place version of the previous constructor.
  1.7050 +    template<typename T>
  1.7051 +    CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  1.7052 +                        const unsigned int normalization_type=3,
  1.7053 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7054 +      throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
  1.7055 +      const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  1.7056 +      avoid_warning = 0;
  1.7057 +      return assign(0,0);
  1.7058 +    }
  1.7059 +
  1.7060 +    //! In-place version of the previous constructor.
  1.7061 +    template<typename T>
  1.7062 +    CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  1.7063 +                        const unsigned int normalization_type=3,
  1.7064 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7065 +      throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
  1.7066 +      const char* avoid_warning = title + list.size + normalization_type + (int)fullscreen_flag + (int)closed_flag;
  1.7067 +      avoid_warning = 0;
  1.7068 +      return assign(0,0);
  1.7069 +    }
  1.7070 +
  1.7071 +    //! In-place version of the previous constructor.
  1.7072 +    CImgDisplay& assign(const CImgDisplay &disp) {
  1.7073 +      return assign(disp.width,disp.height);
  1.7074 +    }
  1.7075 +
  1.7076 +    //! Resize window.
  1.7077 +    CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
  1.7078 +      int avoid_warning = width | height | (int)redraw;
  1.7079 +      avoid_warning = 0;
  1.7080 +      return *this;
  1.7081 +    }
  1.7082 +
  1.7083 +    //! Toggle fullscreen mode.
  1.7084 +    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  1.7085 +      bool avoid_warning = redraw;
  1.7086 +      avoid_warning = false;
  1.7087 +      return *this;
  1.7088 +    }
  1.7089 +
  1.7090 +    //! Show a closed display.
  1.7091 +    CImgDisplay& show() {
  1.7092 +      return *this;
  1.7093 +    }
  1.7094 +
  1.7095 +    //! Close a visible display.
  1.7096 +    CImgDisplay& close() {
  1.7097 +      return *this;
  1.7098 +    }
  1.7099 +
  1.7100 +    //! Move window.
  1.7101 +    CImgDisplay& move(const int posx, const int posy) {
  1.7102 +      int avoid_warning = posx | posy;
  1.7103 +      avoid_warning = 0;
  1.7104 +      return *this;
  1.7105 +    }
  1.7106 +
  1.7107 +    //! Show mouse pointer.
  1.7108 +    CImgDisplay& show_mouse() {
  1.7109 +      return *this;
  1.7110 +    }
  1.7111 +
  1.7112 +    //! Hide mouse pointer.
  1.7113 +    CImgDisplay& hide_mouse() {
  1.7114 +      return *this;
  1.7115 +    }
  1.7116 +
  1.7117 +    //! Move mouse pointer to a specific location.
  1.7118 +    CImgDisplay& set_mouse(const int posx, const int posy) {
  1.7119 +      int avoid_warning = posx | posy;
  1.7120 +      avoid_warning = 0;
  1.7121 +      return *this;
  1.7122 +    }
  1.7123 +
  1.7124 +    //! Set the window title.
  1.7125 +    CImgDisplay& set_title(const char *format, ...) {
  1.7126 +      const char *avoid_warning = format;
  1.7127 +      avoid_warning = 0;
  1.7128 +      return *this;
  1.7129 +    }
  1.7130 +
  1.7131 +    //! Display an image in a window.
  1.7132 +    template<typename T>
  1.7133 +    CImgDisplay& display(const CImg<T>& img) {
  1.7134 +      unsigned int avoid_warning = img.width;
  1.7135 +      avoid_warning = 0;
  1.7136 +      return *this;
  1.7137 +    }
  1.7138 +
  1.7139 +    //! Re-paint image content in window.
  1.7140 +    CImgDisplay& paint() {
  1.7141 +      return *this;
  1.7142 +    }
  1.7143 +
  1.7144 +    //! Render image buffer into GDI native image format.
  1.7145 +    template<typename T>
  1.7146 +    CImgDisplay& render(const CImg<T>& img) {
  1.7147 +      unsigned int avoid_warning = img.width;
  1.7148 +      avoid_warning = 0;
  1.7149 +      return *this;
  1.7150 +    }
  1.7151 +
  1.7152 +    //! Take a snapshot of the display in the specified image.
  1.7153 +    template<typename T>
  1.7154 +    const CImgDisplay& snapshot(CImg<T>& img) const {
  1.7155 +      img.assign(width,height,1,3,0);
  1.7156 +      return *this;
  1.7157 +    }
  1.7158 +
  1.7159 +    // X11-based display
  1.7160 +    //-------------------
  1.7161 +#elif cimg_display==1
  1.7162 +    Atom wm_delete_window, wm_delete_protocol;
  1.7163 +    Window window, background_window;
  1.7164 +    Colormap colormap;
  1.7165 +    XImage *image;
  1.7166 +    void *data;
  1.7167 +#ifdef cimg_use_xshm
  1.7168 +    XShmSegmentInfo *shminfo;
  1.7169 +#endif
  1.7170 +
  1.7171 +    static int screen_dimx() {
  1.7172 +      int res = 0;
  1.7173 +      if (!cimg::X11attr().display) {
  1.7174 +        Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
  1.7175 +        if (!disp)
  1.7176 +          throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
  1.7177 +        res = DisplayWidth(disp,DefaultScreen(disp));
  1.7178 +        XCloseDisplay(disp);
  1.7179 +      } else {
  1.7180 +#ifdef cimg_use_xrandr
  1.7181 +        if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
  1.7182 +          res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
  1.7183 +        else
  1.7184 +#endif
  1.7185 +          res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  1.7186 +      }
  1.7187 +      return res;
  1.7188 +    }
  1.7189 +
  1.7190 +    static int screen_dimy() {
  1.7191 +      int res = 0;
  1.7192 +      if (!cimg::X11attr().display) {
  1.7193 +        Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY") ? cimg_std::getenv("DISPLAY") : ":0.0"));
  1.7194 +        if (!disp)
  1.7195 +          throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
  1.7196 +        res = DisplayHeight(disp,DefaultScreen(disp));
  1.7197 +        XCloseDisplay(disp);
  1.7198 +      } else {
  1.7199 +#ifdef cimg_use_xrandr
  1.7200 +        if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
  1.7201 +          res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
  1.7202 +        else
  1.7203 +#endif
  1.7204 +          res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  1.7205 +      }
  1.7206 +      return res;
  1.7207 +    }
  1.7208 +
  1.7209 +    static void wait_all() {
  1.7210 +      if (cimg::X11attr().display) {
  1.7211 +        XLockDisplay(cimg::X11attr().display);
  1.7212 +        bool flag = true;
  1.7213 +        XEvent event;
  1.7214 +        while (flag) {
  1.7215 +          XNextEvent(cimg::X11attr().display, &event);
  1.7216 +          for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
  1.7217 +            if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
  1.7218 +              cimg::X11attr().wins[i]->_handle_events(&event);
  1.7219 +              if (cimg::X11attr().wins[i]->is_event) flag = false;
  1.7220 +            }
  1.7221 +        }
  1.7222 +        XUnlockDisplay(cimg::X11attr().display);
  1.7223 +      }
  1.7224 +    }
  1.7225 +
  1.7226 +    void _handle_events(const XEvent *const pevent) {
  1.7227 +      XEvent event = *pevent;
  1.7228 +      switch (event.type) {
  1.7229 +      case ClientMessage : {
  1.7230 +        if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
  1.7231 +            (int)event.xclient.data.l[0]==(int)wm_delete_window) {
  1.7232 +          XUnmapWindow(cimg::X11attr().display,window);
  1.7233 +          mouse_x = mouse_y = -1;
  1.7234 +          if (button) { cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
  1.7235 +          if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
  1.7236 +          if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
  1.7237 +          is_closed = is_event = true;
  1.7238 +        }
  1.7239 +      } break;
  1.7240 +      case ConfigureNotify : {
  1.7241 +        while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
  1.7242 +        const unsigned int
  1.7243 +          nw = event.xconfigure.width,
  1.7244 +          nh = event.xconfigure.height;
  1.7245 +        const int
  1.7246 +          nx = event.xconfigure.x,
  1.7247 +          ny = event.xconfigure.y;
  1.7248 +        if (nw && nh && (nw!=window_width || nh!=window_height)) {
  1.7249 +          window_width = nw;
  1.7250 +          window_height = nh;
  1.7251 +          mouse_x = mouse_y = -1;
  1.7252 +          XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
  1.7253 +          is_resized = is_event = true;
  1.7254 +        }
  1.7255 +        if (nx!=window_x || ny!=window_y) {
  1.7256 +          window_x = nx;
  1.7257 +          window_y = ny;
  1.7258 +          is_moved = is_event = true;
  1.7259 +        }
  1.7260 +      } break;
  1.7261 +      case Expose : {
  1.7262 +        while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
  1.7263 +        _paint(false);
  1.7264 +        if (is_fullscreen) {
  1.7265 +          XWindowAttributes attr;
  1.7266 +          XGetWindowAttributes(cimg::X11attr().display, window, &attr);
  1.7267 +          while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
  1.7268 +          XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
  1.7269 +        }
  1.7270 +      } break;
  1.7271 +      case ButtonPress : {
  1.7272 +        do {
  1.7273 +        mouse_x = event.xmotion.x;
  1.7274 +        mouse_y = event.xmotion.y;
  1.7275 +        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  1.7276 +          switch (event.xbutton.button) {
  1.7277 +          case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
  1.7278 +          case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
  1.7279 +          case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
  1.7280 +          }
  1.7281 +        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
  1.7282 +      } break;
  1.7283 +      case ButtonRelease : {
  1.7284 +        do {
  1.7285 +        mouse_x = event.xmotion.x;
  1.7286 +        mouse_y = event.xmotion.y;
  1.7287 +        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  1.7288 +          switch (event.xbutton.button) {
  1.7289 +          case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
  1.7290 +          case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
  1.7291 +          case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
  1.7292 +          case 4 : ++wheel; is_event = true; break;
  1.7293 +          case 5 : --wheel; is_event = true; break;
  1.7294 +          }
  1.7295 +        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
  1.7296 +      } break;
  1.7297 +      case KeyPress : {
  1.7298 +        char tmp;
  1.7299 +        KeySym ksym;
  1.7300 +        XLookupString(&event.xkey,&tmp,1,&ksym,0);
  1.7301 +        update_iskey((unsigned int)ksym,true);
  1.7302 +        if (key) cimg_std::memmove((void*)(keys+1),(void*)keys,512-1);
  1.7303 +        key = (unsigned int)ksym;
  1.7304 +        if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
  1.7305 +        is_event = true;
  1.7306 +      } break;
  1.7307 +      case KeyRelease : {
  1.7308 +        char tmp;
  1.7309 +        KeySym ksym;
  1.7310 +        XLookupString(&event.xkey,&tmp,1,&ksym,0);
  1.7311 +        update_iskey((unsigned int)ksym,false);
  1.7312 +        if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
  1.7313 +        if (released_key) cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
  1.7314 +        released_key = (unsigned int)ksym;
  1.7315 +        is_event = true;
  1.7316 +      } break;
  1.7317 +      case EnterNotify: {
  1.7318 +        while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
  1.7319 +        mouse_x = event.xmotion.x;
  1.7320 +        mouse_y = event.xmotion.y;
  1.7321 +        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  1.7322 +      } break;
  1.7323 +      case LeaveNotify : {
  1.7324 +        while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
  1.7325 +        mouse_x = mouse_y =-1;
  1.7326 +        is_event = true;
  1.7327 +      } break;
  1.7328 +      case MotionNotify : {
  1.7329 +        while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
  1.7330 +        mouse_x = event.xmotion.x;
  1.7331 +        mouse_y = event.xmotion.y;
  1.7332 +        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
  1.7333 +        is_event = true;
  1.7334 +      } break;
  1.7335 +      }
  1.7336 +    }
  1.7337 +
  1.7338 +    static void* _events_thread(void *arg) {
  1.7339 +      arg = 0;
  1.7340 +      XEvent event;
  1.7341 +      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
  1.7342 +      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
  1.7343 +      for (;;) {
  1.7344 +        XLockDisplay(cimg::X11attr().display);
  1.7345 +        bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
  1.7346 +        if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
  1.7347 +                                                      ExposureMask|StructureNotifyMask|ButtonPressMask|
  1.7348 +                                                      KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
  1.7349 +                                                      ButtonReleaseMask|KeyReleaseMask,&event);
  1.7350 +        if (event_flag) {
  1.7351 +          for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
  1.7352 +            if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
  1.7353 +              cimg::X11attr().wins[i]->_handle_events(&event);
  1.7354 +        }
  1.7355 +        XUnlockDisplay(cimg::X11attr().display);
  1.7356 +        pthread_testcancel();
  1.7357 +        cimg::sleep(7);
  1.7358 +      }
  1.7359 +      return 0;
  1.7360 +    }
  1.7361 +
  1.7362 +    void _set_colormap(Colormap& colormap, const unsigned int dim) {
  1.7363 +      XColor palette[256];
  1.7364 +      switch (dim) {
  1.7365 +      case 1 : { // palette for greyscale images
  1.7366 +        for (unsigned int index=0; index<256; ++index) {
  1.7367 +          palette[index].pixel = index;
  1.7368 +          palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
  1.7369 +          palette[index].flags = DoRed | DoGreen | DoBlue;
  1.7370 +        }
  1.7371 +      } break;
  1.7372 +      case 2 : { // palette for RG images
  1.7373 +        for (unsigned int index=0, r=8; r<256; r+=16)
  1.7374 +          for (unsigned int g=8; g<256; g+=16) {
  1.7375 +            palette[index].pixel = index;
  1.7376 +            palette[index].red = palette[index].blue = (unsigned short)(r<<8);
  1.7377 +            palette[index].green = (unsigned short)(g<<8);
  1.7378 +            palette[index++].flags = DoRed | DoGreen | DoBlue;
  1.7379 +          }
  1.7380 +      } break;
  1.7381 +      default : { // palette for RGB images
  1.7382 +        for (unsigned int index=0, r=16; r<256; r+=32)
  1.7383 +          for (unsigned int g=16; g<256; g+=32)
  1.7384 +            for (unsigned int b=32; b<256; b+=64) {
  1.7385 +              palette[index].pixel = index;
  1.7386 +              palette[index].red = (unsigned short)(r<<8);
  1.7387 +              palette[index].green = (unsigned short)(g<<8);
  1.7388 +              palette[index].blue = (unsigned short)(b<<8);
  1.7389 +              palette[index++].flags = DoRed | DoGreen | DoBlue;
  1.7390 +            }
  1.7391 +      }
  1.7392 +      }
  1.7393 +      XStoreColors(cimg::X11attr().display,colormap,palette,256);
  1.7394 +    }
  1.7395 +
  1.7396 +    void _map_window() {
  1.7397 +      XWindowAttributes attr;
  1.7398 +      XEvent event;
  1.7399 +      bool exposed = false, mapped = false;
  1.7400 +      XMapRaised(cimg::X11attr().display,window);
  1.7401 +      XSync(cimg::X11attr().display,False);
  1.7402 +      do {
  1.7403 +        XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
  1.7404 +        switch (event.type) {
  1.7405 +        case MapNotify : mapped = true; break;
  1.7406 +        case Expose : exposed = true; break;
  1.7407 +        default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
  1.7408 +        }
  1.7409 +      } while (!(exposed && mapped));
  1.7410 +      do {
  1.7411 +        XGetWindowAttributes(cimg::X11attr().display, window, &attr);
  1.7412 +        if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
  1.7413 +      } while (attr.map_state != IsViewable);
  1.7414 +      window_x = attr.x;
  1.7415 +      window_y = attr.y;
  1.7416 +    }
  1.7417 +
  1.7418 +    void _paint(const bool wait_expose=true) {
  1.7419 +      if (!is_closed) {
  1.7420 +        if (wait_expose) {
  1.7421 +          static XEvent event;
  1.7422 +          event.xexpose.type = Expose;
  1.7423 +          event.xexpose.serial = 0;
  1.7424 +          event.xexpose.send_event = True;
  1.7425 +          event.xexpose.display = cimg::X11attr().display;
  1.7426 +          event.xexpose.window = window;
  1.7427 +          event.xexpose.x = 0;
  1.7428 +          event.xexpose.y = 0;
  1.7429 +          event.xexpose.width = dimx();
  1.7430 +          event.xexpose.height = dimy();
  1.7431 +          event.xexpose.count = 0;
  1.7432 +          XSendEvent(cimg::X11attr().display, window, False, 0, &event);
  1.7433 +        } else {
  1.7434 +#ifdef cimg_use_xshm
  1.7435 +          if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
  1.7436 +          else
  1.7437 +#endif
  1.7438 +            XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
  1.7439 +          XSync(cimg::X11attr().display, False);
  1.7440 +        }
  1.7441 +      }
  1.7442 +    }
  1.7443 +
  1.7444 +    template<typename T>
  1.7445 +    void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
  1.7446 +      foo = 0;
  1.7447 +#ifdef cimg_use_xshm
  1.7448 +      if (shminfo) {
  1.7449 +        XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
  1.7450 +        XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7451 +                                         cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
  1.7452 +        if (!nimage) {
  1.7453 +          delete nshminfo;
  1.7454 +          return;
  1.7455 +        } else {
  1.7456 +          nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
  1.7457 +          if (nshminfo->shmid==-1) {
  1.7458 +            XDestroyImage(nimage);
  1.7459 +            delete nshminfo;
  1.7460 +            return;
  1.7461 +          } else {
  1.7462 +            nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
  1.7463 +            if (nshminfo->shmaddr==(char*)-1) {
  1.7464 +              shmctl(nshminfo->shmid,IPC_RMID,0);
  1.7465 +              XDestroyImage(nimage);
  1.7466 +              delete nshminfo;
  1.7467 +              return;
  1.7468 +            } else {
  1.7469 +              nshminfo->readOnly = False;
  1.7470 +              cimg::X11attr().shm_enabled = true;
  1.7471 +              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
  1.7472 +              XShmAttach(cimg::X11attr().display, nshminfo);
  1.7473 +              XSync(cimg::X11attr().display, False);
  1.7474 +              XSetErrorHandler(oldXErrorHandler);
  1.7475 +              if (!cimg::X11attr().shm_enabled) {
  1.7476 +                shmdt(nshminfo->shmaddr);
  1.7477 +                shmctl(nshminfo->shmid,IPC_RMID,0);
  1.7478 +                XDestroyImage(nimage);
  1.7479 +                delete nshminfo;
  1.7480 +                return;
  1.7481 +              } else {
  1.7482 +                T *const ndata = (T*)nimage->data;
  1.7483 +                if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
  1.7484 +                else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
  1.7485 +                XShmDetach(cimg::X11attr().display, shminfo);
  1.7486 +                XDestroyImage(image);
  1.7487 +                shmdt(shminfo->shmaddr);
  1.7488 +                shmctl(shminfo->shmid,IPC_RMID,0);
  1.7489 +                delete shminfo;
  1.7490 +                shminfo = nshminfo;
  1.7491 +                image = nimage;
  1.7492 +                data = (void*)ndata;
  1.7493 +              }
  1.7494 +            }
  1.7495 +          }
  1.7496 +        }
  1.7497 +      } else
  1.7498 +#endif
  1.7499 +        {
  1.7500 +          T *ndata = (T*)cimg_std::malloc(ndimx*ndimy*sizeof(T));
  1.7501 +          if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
  1.7502 +          else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
  1.7503 +          data = (void*)ndata;
  1.7504 +          XDestroyImage(image);
  1.7505 +          image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7506 +                               cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
  1.7507 +        }
  1.7508 +    }
  1.7509 +
  1.7510 +    void _init_fullscreen() {
  1.7511 +      background_window = 0;
  1.7512 +      if (is_fullscreen && !is_closed) {
  1.7513 +#ifdef cimg_use_xrandr
  1.7514 +        int foo;
  1.7515 +        if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
  1.7516 +          XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
  1.7517 +          if (!cimg::X11attr().resolutions) {
  1.7518 +            cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
  1.7519 +            cimg::X11attr().nb_resolutions = (unsigned int)foo;
  1.7520 +          }
  1.7521 +          if (cimg::X11attr().resolutions) {
  1.7522 +            cimg::X11attr().curr_resolution = 0;
  1.7523 +            for (unsigned int i=0; i<cimg::X11attr().nb_resolutions; ++i) {
  1.7524 +              const unsigned int
  1.7525 +                nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
  1.7526 +                nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
  1.7527 +              if (nw>=width && nh>=height &&
  1.7528 +                  nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
  1.7529 +                  nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
  1.7530 +                cimg::X11attr().curr_resolution = i;
  1.7531 +            }
  1.7532 +            if (cimg::X11attr().curr_resolution>0) {
  1.7533 +              XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
  1.7534 +              XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
  1.7535 +                                 cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
  1.7536 +              XRRFreeScreenConfigInfo(config);
  1.7537 +              XSync(cimg::X11attr().display, False);
  1.7538 +            }
  1.7539 +          }
  1.7540 +        }
  1.7541 +        if (!cimg::X11attr().resolutions)
  1.7542 +          cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
  1.7543 +#endif
  1.7544 +        const unsigned int sx = screen_dimx(), sy = screen_dimy();
  1.7545 +        XSetWindowAttributes winattr;
  1.7546 +        winattr.override_redirect = True;
  1.7547 +        if (sx!=width || sy!=height) {
  1.7548 +          background_window = XCreateWindow(cimg::X11attr().display,
  1.7549 +                                            RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
  1.7550 +                                            sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
  1.7551 +          const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  1.7552 +          void *background_data = cimg_std::malloc(bufsize);
  1.7553 +          cimg_std::memset(background_data,0,bufsize);
  1.7554 +          XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7555 +                                                  cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
  1.7556 +          XEvent event;
  1.7557 +          XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
  1.7558 +          XMapRaised(cimg::X11attr().display,background_window);
  1.7559 +          do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
  1.7560 +          while (event.type!=MapNotify);
  1.7561 +#ifdef cimg_use_xshm
  1.7562 +          if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
  1.7563 +          else
  1.7564 +#endif
  1.7565 +            XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
  1.7566 +          XWindowAttributes attr;
  1.7567 +          XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
  1.7568 +          while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
  1.7569 +          XDestroyImage(background_image);
  1.7570 +        }
  1.7571 +      }
  1.7572 +    }
  1.7573 +
  1.7574 +    void _desinit_fullscreen() {
  1.7575 +      if (is_fullscreen) {
  1.7576 +        XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
  1.7577 +#ifdef cimg_use_xrandr
  1.7578 +        if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
  1.7579 +          XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
  1.7580 +          XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
  1.7581 +                             0, cimg::X11attr().curr_rotation, CurrentTime);
  1.7582 +          XRRFreeScreenConfigInfo(config);
  1.7583 +          XSync(cimg::X11attr().display, False);
  1.7584 +          cimg::X11attr().curr_resolution = 0;
  1.7585 +        }
  1.7586 +#endif
  1.7587 +        if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
  1.7588 +        background_window = 0;
  1.7589 +        is_fullscreen = false;
  1.7590 +      }
  1.7591 +    }
  1.7592 +
  1.7593 +    static int _assign_xshm(Display *dpy, XErrorEvent *error) {
  1.7594 +      dpy = 0; error = 0;
  1.7595 +      cimg::X11attr().shm_enabled = false;
  1.7596 +      return 0;
  1.7597 +    }
  1.7598 +
  1.7599 +    void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  1.7600 +                 const unsigned int normalization_type=3,
  1.7601 +                 const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7602 +
  1.7603 +      // Allocate space for window title
  1.7604 +      const int s = cimg::strlen(ptitle)+1;
  1.7605 +      char *tmp_title = s?new char[s]:0;
  1.7606 +      if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  1.7607 +
  1.7608 +      // Destroy previous display window if existing
  1.7609 +      if (!is_empty()) assign();
  1.7610 +
  1.7611 +      // Open X11 display if necessary.
  1.7612 +      if (!cimg::X11attr().display) {
  1.7613 +        static bool xinit_threads = false;
  1.7614 +        if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
  1.7615 +        cimg::X11attr().nb_wins = 0;
  1.7616 +        cimg::X11attr().display = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
  1.7617 +        if (!cimg::X11attr().display)
  1.7618 +          throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
  1.7619 +        cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
  1.7620 +        if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
  1.7621 +          throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
  1.7622 +                                     "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
  1.7623 +        cimg::X11attr().gc = new GC;
  1.7624 +        *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  1.7625 +        Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
  1.7626 +        XVisualInfo vtemplate;
  1.7627 +        vtemplate.visualid = XVisualIDFromVisual(visual);
  1.7628 +        int nb_visuals;
  1.7629 +        XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
  1.7630 +        if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
  1.7631 +        cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
  1.7632 +        XFree(vinfo);
  1.7633 +        XLockDisplay(cimg::X11attr().display);
  1.7634 +        cimg::X11attr().event_thread = new pthread_t;
  1.7635 +        pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
  1.7636 +      } else XLockDisplay(cimg::X11attr().display);
  1.7637 +
  1.7638 +      // Set display variables
  1.7639 +      width = cimg::min(dimw,(unsigned int)screen_dimx());
  1.7640 +      height = cimg::min(dimh,(unsigned int)screen_dimy());
  1.7641 +      normalization = normalization_type<4?normalization_type:3;
  1.7642 +      is_fullscreen = fullscreen_flag;
  1.7643 +      window_x = window_y = 0;
  1.7644 +      is_closed = closed_flag;
  1.7645 +      title = tmp_title;
  1.7646 +      flush();
  1.7647 +
  1.7648 +      // Create X11 window and palette (if 8bits display)
  1.7649 +      if (is_fullscreen) {
  1.7650 +        if (!is_closed) _init_fullscreen();
  1.7651 +        const unsigned int sx = screen_dimx(), sy = screen_dimy();
  1.7652 +        XSetWindowAttributes winattr;
  1.7653 +        winattr.override_redirect = True;
  1.7654 +        window = XCreateWindow(cimg::X11attr().display,
  1.7655 +                               RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7656 +                               (sx-width)/2,(sy-height)/2,
  1.7657 +                               width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
  1.7658 +      } else
  1.7659 +        window = XCreateSimpleWindow(cimg::X11attr().display,
  1.7660 +                                     RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7661 +                                     0,0,width,height,2,0,0x0L);
  1.7662 +      XStoreName(cimg::X11attr().display,window,title?title:" ");
  1.7663 +      if (cimg::X11attr().nb_bits==8) {
  1.7664 +        colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
  1.7665 +                                                                                DefaultScreen(cimg::X11attr().display)),AllocAll);
  1.7666 +        _set_colormap(colormap,3);
  1.7667 +        XSetWindowColormap(cimg::X11attr().display,window,colormap);
  1.7668 +      }
  1.7669 +      window_width = width;
  1.7670 +      window_height = height;
  1.7671 +
  1.7672 +      // Create XImage
  1.7673 +      const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  1.7674 +#ifdef cimg_use_xshm
  1.7675 +      shminfo = 0;
  1.7676 +      if (XShmQueryExtension(cimg::X11attr().display)) {
  1.7677 +        shminfo = new XShmSegmentInfo;
  1.7678 +        image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7679 +                                cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
  1.7680 +        if (!image) {
  1.7681 +          delete shminfo;
  1.7682 +          shminfo = 0;
  1.7683 +        } else {
  1.7684 +          shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
  1.7685 +          if (shminfo->shmid==-1) {
  1.7686 +            XDestroyImage(image);
  1.7687 +            delete shminfo;
  1.7688 +            shminfo = 0;
  1.7689 +          } else {
  1.7690 +            shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
  1.7691 +            if (shminfo->shmaddr==(char*)-1) {
  1.7692 +              shmctl(shminfo->shmid,IPC_RMID,0);
  1.7693 +              XDestroyImage(image);
  1.7694 +              delete shminfo;
  1.7695 +              shminfo = 0;
  1.7696 +            } else {
  1.7697 +              shminfo->readOnly = False;
  1.7698 +              cimg::X11attr().shm_enabled = true;
  1.7699 +              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
  1.7700 +              XShmAttach(cimg::X11attr().display, shminfo);
  1.7701 +              XSync(cimg::X11attr().display, False);
  1.7702 +              XSetErrorHandler(oldXErrorHandler);
  1.7703 +              if (!cimg::X11attr().shm_enabled) {
  1.7704 +                shmdt(shminfo->shmaddr);
  1.7705 +                shmctl(shminfo->shmid,IPC_RMID,0);
  1.7706 +                XDestroyImage(image);
  1.7707 +                delete shminfo;
  1.7708 +                shminfo = 0;
  1.7709 +              }
  1.7710 +            }
  1.7711 +          }
  1.7712 +        }
  1.7713 +      }
  1.7714 +      if (!shminfo)
  1.7715 +#endif
  1.7716 +        {
  1.7717 +          data = cimg_std::malloc(bufsize);
  1.7718 +          image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
  1.7719 +                               cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
  1.7720 +        }
  1.7721 +
  1.7722 +      wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
  1.7723 +      wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
  1.7724 +      XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
  1.7725 +      XSelectInput(cimg::X11attr().display,window,
  1.7726 +                   ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
  1.7727 +                   EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
  1.7728 +      if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
  1.7729 +      cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
  1.7730 +      if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
  1.7731 +      XUnlockDisplay(cimg::X11attr().display);
  1.7732 +    }
  1.7733 +
  1.7734 +    CImgDisplay& assign() {
  1.7735 +      if (is_empty()) return *this;
  1.7736 +      XLockDisplay(cimg::X11attr().display);
  1.7737 +
  1.7738 +      // Remove display window from event thread list.
  1.7739 +      unsigned int i;
  1.7740 +      for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
  1.7741 +      for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
  1.7742 +      --cimg::X11attr().nb_wins;
  1.7743 +
  1.7744 +      // Destroy window, image, colormap and title.
  1.7745 +      if (is_fullscreen && !is_closed) _desinit_fullscreen();
  1.7746 +      XDestroyWindow(cimg::X11attr().display,window);
  1.7747 +      window = 0;
  1.7748 +#ifdef cimg_use_xshm
  1.7749 +      if (shminfo) {
  1.7750 +        XShmDetach(cimg::X11attr().display, shminfo);
  1.7751 +        XDestroyImage(image);
  1.7752 +        shmdt(shminfo->shmaddr);
  1.7753 +        shmctl(shminfo->shmid,IPC_RMID,0);
  1.7754 +        delete shminfo;
  1.7755 +        shminfo = 0;
  1.7756 +      } else
  1.7757 +#endif
  1.7758 +        XDestroyImage(image);
  1.7759 +      data = 0; image = 0;
  1.7760 +      if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
  1.7761 +      colormap = 0;
  1.7762 +      XSync(cimg::X11attr().display, False);
  1.7763 +
  1.7764 +      // Reset display variables
  1.7765 +      if (title) delete[] title;
  1.7766 +      width = height = normalization = window_width = window_height = 0;
  1.7767 +      window_x = window_y = 0;
  1.7768 +      is_fullscreen = false;
  1.7769 +      is_closed = true;
  1.7770 +      min = max = 0;
  1.7771 +      title = 0;
  1.7772 +      flush();
  1.7773 +
  1.7774 +      // End event thread and close display if necessary
  1.7775 +      XUnlockDisplay(cimg::X11attr().display);
  1.7776 +
  1.7777 +      /* The code below was used to close the X11 display when not used anymore,
  1.7778 +         unfortunately, since the latest Xorg versions, it randomely hangs, so
  1.7779 +         I prefer to remove it. A fix would be needed anyway.
  1.7780 +
  1.7781 +         if (!cimg::X11attr().nb_wins) {
  1.7782 +         // Kill event thread
  1.7783 +         pthread_cancel(*cimg::X11attr().event_thread);
  1.7784 +         XUnlockDisplay(cimg::X11attr().display);
  1.7785 +         pthread_join(*cimg::X11attr().event_thread,0);
  1.7786 +         delete cimg::X11attr().event_thread;
  1.7787 +         cimg::X11attr().event_thread = 0;
  1.7788 +         XCloseDisplay(cimg::X11attr().display);
  1.7789 +         cimg::X11attr().display = 0;
  1.7790 +         delete cimg::X11attr().gc;
  1.7791 +         cimg::X11attr().gc = 0;
  1.7792 +         } else XUnlockDisplay(cimg::X11attr().display);
  1.7793 +      */
  1.7794 +      return *this;
  1.7795 +    }
  1.7796 +
  1.7797 +    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  1.7798 +                        const unsigned int normalization_type=3,
  1.7799 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7800 +      if (!dimw || !dimh) return assign();
  1.7801 +      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  1.7802 +      min = max = 0;
  1.7803 +      cimg_std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
  1.7804 +                          (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
  1.7805 +      return paint();
  1.7806 +    }
  1.7807 +
  1.7808 +    template<typename T>
  1.7809 +    CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  1.7810 +                        const unsigned int normalization_type=3,
  1.7811 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7812 +      if (!img) return assign();
  1.7813 +      CImg<T> tmp;
  1.7814 +      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.7815 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.7816 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.7817 +      return render(nimg).paint();
  1.7818 +    }
  1.7819 +
  1.7820 +    template<typename T>
  1.7821 +    CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  1.7822 +                        const unsigned int normalization_type=3,
  1.7823 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.7824 +      if (!list) return assign();
  1.7825 +      CImg<T> tmp;
  1.7826 +      const CImg<T> img = list.get_append('x','p'),
  1.7827 +        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.7828 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.7829 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.7830 +      return render(nimg).paint();
  1.7831 +    }
  1.7832 +
  1.7833 +    CImgDisplay& assign(const CImgDisplay& win) {
  1.7834 +      if (!win) return assign();
  1.7835 +      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  1.7836 +      cimg_std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
  1.7837 +                                 cimg::X11attr().nb_bits==16?sizeof(unsigned short):
  1.7838 +                                 sizeof(unsigned int))*width*height);
  1.7839 +      return paint();
  1.7840 +    }
  1.7841 +
  1.7842 +    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  1.7843 +      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  1.7844 +      if (is_empty()) return assign(nwidth,nheight);
  1.7845 +      const unsigned int
  1.7846 +        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
  1.7847 +        tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
  1.7848 +        dimx = tmpdimx?tmpdimx:1,
  1.7849 +        dimy = tmpdimy?tmpdimy:1;
  1.7850 +      XLockDisplay(cimg::X11attr().display);
  1.7851 +      if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
  1.7852 +      if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
  1.7853 +      case 8 :  { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
  1.7854 +      case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
  1.7855 +      default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
  1.7856 +      }
  1.7857 +      window_width = width = dimx; window_height = height = dimy;
  1.7858 +      is_resized = false;
  1.7859 +      XUnlockDisplay(cimg::X11attr().display);
  1.7860 +      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  1.7861 +      if (redraw) return paint();
  1.7862 +      return *this;
  1.7863 +    }
  1.7864 +
  1.7865 +    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  1.7866 +      if (is_empty()) return *this;
  1.7867 +      if (redraw) {
  1.7868 +        const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
  1.7869 +        void *odata = cimg_std::malloc(bufsize);
  1.7870 +        cimg_std::memcpy(odata,data,bufsize);
  1.7871 +        assign(width,height,title,normalization,!is_fullscreen,false);
  1.7872 +        cimg_std::memcpy(data,odata,bufsize);
  1.7873 +        cimg_std::free(odata);
  1.7874 +        return paint(false);
  1.7875 +      }
  1.7876 +      return assign(width,height,title,normalization,!is_fullscreen,false);
  1.7877 +    }
  1.7878 +
  1.7879 +    CImgDisplay& show() {
  1.7880 +      if (!is_empty() && is_closed) {
  1.7881 +        XLockDisplay(cimg::X11attr().display);
  1.7882 +        if (is_fullscreen) _init_fullscreen();
  1.7883 +        _map_window();
  1.7884 +        is_closed = false;
  1.7885 +        XUnlockDisplay(cimg::X11attr().display);
  1.7886 +        return paint();
  1.7887 +      }
  1.7888 +      return *this;
  1.7889 +    }
  1.7890 +
  1.7891 +    CImgDisplay& close() {
  1.7892 +      if (!is_empty() && !is_closed) {
  1.7893 +        XLockDisplay(cimg::X11attr().display);
  1.7894 +        if (is_fullscreen) _desinit_fullscreen();
  1.7895 +        XUnmapWindow(cimg::X11attr().display,window);
  1.7896 +        window_x = window_y = -1;
  1.7897 +        is_closed = true;
  1.7898 +        XUnlockDisplay(cimg::X11attr().display);
  1.7899 +      }
  1.7900 +      return *this;
  1.7901 +    }
  1.7902 +
  1.7903 +    CImgDisplay& move(const int posx, const int posy) {
  1.7904 +      if (is_empty()) return *this;
  1.7905 +      show();
  1.7906 +      XLockDisplay(cimg::X11attr().display);
  1.7907 +      XMoveWindow(cimg::X11attr().display,window,posx,posy);
  1.7908 +      window_x = posx; window_y = posy;
  1.7909 +      is_moved = false;
  1.7910 +      XUnlockDisplay(cimg::X11attr().display);
  1.7911 +      return paint();
  1.7912 +    }
  1.7913 +
  1.7914 +    CImgDisplay& show_mouse() {
  1.7915 +      if (is_empty()) return *this;
  1.7916 +      XLockDisplay(cimg::X11attr().display);
  1.7917 +      XDefineCursor(cimg::X11attr().display,window,None);
  1.7918 +      XUnlockDisplay(cimg::X11attr().display);
  1.7919 +      return *this;
  1.7920 +    }
  1.7921 +
  1.7922 +    CImgDisplay& hide_mouse() {
  1.7923 +      if (is_empty()) return *this;
  1.7924 +      XLockDisplay(cimg::X11attr().display);
  1.7925 +      const char pix_data[8] = { 0 };
  1.7926 +      XColor col;
  1.7927 +      col.red = col.green = col.blue = 0;
  1.7928 +      Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
  1.7929 +      Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
  1.7930 +      XFreePixmap(cimg::X11attr().display,pix);
  1.7931 +      XDefineCursor(cimg::X11attr().display,window,cur);
  1.7932 +      XUnlockDisplay(cimg::X11attr().display);
  1.7933 +      return *this;
  1.7934 +    }
  1.7935 +
  1.7936 +    CImgDisplay& set_mouse(const int posx, const int posy) {
  1.7937 +      if (is_empty() || is_closed) return *this;
  1.7938 +      XLockDisplay(cimg::X11attr().display);
  1.7939 +      XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
  1.7940 +      mouse_x = posx; mouse_y = posy;
  1.7941 +      is_moved = false;
  1.7942 +      XSync(cimg::X11attr().display, False);
  1.7943 +      XUnlockDisplay(cimg::X11attr().display);
  1.7944 +      return *this;
  1.7945 +    }
  1.7946 +
  1.7947 +    CImgDisplay& set_title(const char *format, ...) {
  1.7948 +      if (is_empty()) return *this;
  1.7949 +      char tmp[1024] = {0};
  1.7950 +      va_list ap;
  1.7951 +      va_start(ap, format);
  1.7952 +      cimg_std::vsprintf(tmp,format,ap);
  1.7953 +      va_end(ap);
  1.7954 +      if (title) delete[] title;
  1.7955 +      const int s = cimg::strlen(tmp)+1;
  1.7956 +      title = new char[s];
  1.7957 +      cimg_std::memcpy(title,tmp,s*sizeof(char));
  1.7958 +      XLockDisplay(cimg::X11attr().display);
  1.7959 +      XStoreName(cimg::X11attr().display,window,tmp);
  1.7960 +      XUnlockDisplay(cimg::X11attr().display);
  1.7961 +      return *this;
  1.7962 +    }
  1.7963 +
  1.7964 +    template<typename T>
  1.7965 +    CImgDisplay& display(const CImg<T>& img) {
  1.7966 +      if (img.is_empty())
  1.7967 +        throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
  1.7968 +      if (is_empty()) assign(img.width,img.height);
  1.7969 +      return render(img).paint(false);
  1.7970 +    }
  1.7971 +
  1.7972 +    CImgDisplay& paint(const bool wait_expose=true) {
  1.7973 +      if (is_empty()) return *this;
  1.7974 +      XLockDisplay(cimg::X11attr().display);
  1.7975 +      _paint(wait_expose);
  1.7976 +      XUnlockDisplay(cimg::X11attr().display);
  1.7977 +      return *this;
  1.7978 +    }
  1.7979 +
  1.7980 +    template<typename T>
  1.7981 +    CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
  1.7982 +      if (is_empty()) return *this;
  1.7983 +      if (!img)
  1.7984 +        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  1.7985 +                                    img.width,img.height,img.depth,img.dim,img.data);
  1.7986 +      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.7987 +      if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
  1.7988 +      if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
  1.7989 +
  1.7990 +      const T
  1.7991 +        *data1 = img.data,
  1.7992 +        *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
  1.7993 +        *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
  1.7994 +
  1.7995 +      if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
  1.7996 +      XLockDisplay(cimg::X11attr().display);
  1.7997 +
  1.7998 +      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  1.7999 +        min = max = 0;
  1.8000 +        switch (cimg::X11attr().nb_bits) {
  1.8001 +        case 8 : { // 256 color palette, no normalization
  1.8002 +          _set_colormap(colormap,img.dim);
  1.8003 +          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
  1.8004 +          unsigned char *ptrd = (unsigned char*)ndata;
  1.8005 +          switch (img.dim) {
  1.8006 +          case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
  1.8007 +            break;
  1.8008 +          case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8009 +              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
  1.8010 +              (*ptrd++) = (R&0xf0) | (G>>4);
  1.8011 +            } break;
  1.8012 +          default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8013 +              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
  1.8014 +              (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
  1.8015 +            }
  1.8016 +          }
  1.8017 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
  1.8018 +        } break;
  1.8019 +        case 16 : { // 16 bits colors, no normalization
  1.8020 +          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
  1.8021 +          unsigned char *ptrd = (unsigned char*)ndata;
  1.8022 +          const unsigned int M = 248;
  1.8023 +          switch (img.dim) {
  1.8024 +          case 1 :
  1.8025 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8026 +              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
  1.8027 +              *(ptrd++) = (val&M) | (G>>3);
  1.8028 +              *(ptrd++) = (G<<5) | (G>>1);
  1.8029 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8030 +              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
  1.8031 +              *(ptrd++) = (G<<5) | (G>>1);
  1.8032 +              *(ptrd++) = (val&M) | (G>>3);
  1.8033 +            }
  1.8034 +            break;
  1.8035 +          case 2 :
  1.8036 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8037 +              const unsigned char G = (unsigned char)*(data2++)>>2;
  1.8038 +              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  1.8039 +              *(ptrd++) = (G<<5);
  1.8040 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8041 +              const unsigned char G = (unsigned char)*(data2++)>>2;
  1.8042 +              *(ptrd++) = (G<<5);
  1.8043 +              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  1.8044 +            }
  1.8045 +            break;
  1.8046 +          default :
  1.8047 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8048 +              const unsigned char G = (unsigned char)*(data2++)>>2;
  1.8049 +              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  1.8050 +              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
  1.8051 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8052 +              const unsigned char G = (unsigned char)*(data2++)>>2;
  1.8053 +              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
  1.8054 +              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
  1.8055 +            }
  1.8056 +          }
  1.8057 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
  1.8058 +        } break;
  1.8059 +        default : { // 24 bits colors, no normalization
  1.8060 +          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
  1.8061 +          if (sizeof(int)==4) { // 32 bits int uses optimized version
  1.8062 +            unsigned int *ptrd = ndata;
  1.8063 +            switch (img.dim) {
  1.8064 +            case 1 :
  1.8065 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8066 +                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8067 +                  const unsigned char val = (unsigned char)*(data1++);
  1.8068 +                  *(ptrd++) = (val<<16) | (val<<8) | val;
  1.8069 +                }
  1.8070 +              else
  1.8071 +               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8072 +                  const unsigned char val = (unsigned char)*(data1++)<<8;
  1.8073 +                  *(ptrd++) = (val<<16) | (val<<8) | val;
  1.8074 +                }
  1.8075 +              break;
  1.8076 +            case 2 :
  1.8077 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8078 +               for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8079 +                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
  1.8080 +              else
  1.8081 +               for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8082 +                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
  1.8083 +              break;
  1.8084 +            default :
  1.8085 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8086 +               for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8087 +                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  1.8088 +              else
  1.8089 +               for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8090 +                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
  1.8091 +            }
  1.8092 +          } else {
  1.8093 +            unsigned char *ptrd = (unsigned char*)ndata;
  1.8094 +            switch (img.dim) {
  1.8095 +            case 1 :
  1.8096 +              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8097 +                *(ptrd++) = 0;
  1.8098 +                *(ptrd++) = (unsigned char)*(data1++);
  1.8099 +                *(ptrd++) = 0;
  1.8100 +                *(ptrd++) = 0;
  1.8101 +              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8102 +                *(ptrd++) = 0;
  1.8103 +                *(ptrd++) = 0;
  1.8104 +                *(ptrd++) = (unsigned char)*(data1++);
  1.8105 +                *(ptrd++) = 0;
  1.8106 +              }
  1.8107 +              break;
  1.8108 +            case 2 :
  1.8109 +              if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
  1.8110 +              for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8111 +                *(ptrd++) = 0;
  1.8112 +                *(ptrd++) = (unsigned char)*(data2++);
  1.8113 +                *(ptrd++) = (unsigned char)*(data1++);
  1.8114 +                *(ptrd++) = 0;
  1.8115 +              }
  1.8116 +              break;
  1.8117 +            default :
  1.8118 +              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8119 +                *(ptrd++) = 0;
  1.8120 +                *(ptrd++) = (unsigned char)*(data1++);
  1.8121 +                *(ptrd++) = (unsigned char)*(data2++);
  1.8122 +                *(ptrd++) = (unsigned char)*(data3++);
  1.8123 +              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8124 +                *(ptrd++) = (unsigned char)*(data3++);
  1.8125 +                *(ptrd++) = (unsigned char)*(data2++);
  1.8126 +                *(ptrd++) = (unsigned char)*(data1++);
  1.8127 +                *(ptrd++) = 0;
  1.8128 +              }
  1.8129 +            }
  1.8130 +          }
  1.8131 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
  1.8132 +        }
  1.8133 +        };
  1.8134 +      } else {
  1.8135 +        if (normalization==3) {
  1.8136 +          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  1.8137 +          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
  1.8138 +        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  1.8139 +        const float delta = max-min, mm = delta?delta:1.0f;
  1.8140 +        switch (cimg::X11attr().nb_bits) {
  1.8141 +        case 8 : { // 256 color palette, with normalization
  1.8142 +          _set_colormap(colormap,img.dim);
  1.8143 +          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
  1.8144 +          unsigned char *ptrd = (unsigned char*)ndata;
  1.8145 +          switch (img.dim) {
  1.8146 +          case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8147 +            const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8148 +            *(ptrd++) = R;
  1.8149 +          } break;
  1.8150 +          case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8151 +            const unsigned char
  1.8152 +              R = (unsigned char)(255*(*(data1++)-min)/mm),
  1.8153 +              G = (unsigned char)(255*(*(data2++)-min)/mm);
  1.8154 +            (*ptrd++) = (R&0xf0) | (G>>4);
  1.8155 +          } break;
  1.8156 +          default :
  1.8157 +            for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8158 +              const unsigned char
  1.8159 +                R = (unsigned char)(255*(*(data1++)-min)/mm),
  1.8160 +                G = (unsigned char)(255*(*(data2++)-min)/mm),
  1.8161 +                B = (unsigned char)(255*(*(data3++)-min)/mm);
  1.8162 +              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
  1.8163 +            }
  1.8164 +          }
  1.8165 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
  1.8166 +        } break;
  1.8167 +        case 16 : { // 16 bits colors, with normalization
  1.8168 +          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
  1.8169 +          unsigned char *ptrd = (unsigned char*)ndata;
  1.8170 +          const unsigned int M = 248;
  1.8171 +          switch (img.dim) {
  1.8172 +          case 1 :
  1.8173 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8174 +              const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
  1.8175 +              *(ptrd++) = (val&M) | (G>>3);
  1.8176 +              *(ptrd++) = (G<<5) | (val>>3);
  1.8177 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8178 +              const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
  1.8179 +              *(ptrd++) = (G<<5) | (val>>3);
  1.8180 +              *(ptrd++) = (val&M) | (G>>3);
  1.8181 +            }
  1.8182 +            break;
  1.8183 +          case 2 :
  1.8184 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8185 +              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  1.8186 +              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  1.8187 +              *(ptrd++) = (G<<5);
  1.8188 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8189 +              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  1.8190 +              *(ptrd++) = (G<<5);
  1.8191 +              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  1.8192 +            }
  1.8193 +            break;
  1.8194 +          default :
  1.8195 +            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8196 +              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  1.8197 +              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  1.8198 +              *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
  1.8199 +            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8200 +              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
  1.8201 +              *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
  1.8202 +              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
  1.8203 +            }
  1.8204 +          }
  1.8205 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
  1.8206 +        } break;
  1.8207 +        default : { // 24 bits colors, with normalization
  1.8208 +          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
  1.8209 +          if (sizeof(int)==4) { // 32 bits int uses optimized version
  1.8210 +            unsigned int *ptrd = ndata;
  1.8211 +            switch (img.dim) {
  1.8212 +            case 1 :
  1.8213 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8214 +                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8215 +                  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8216 +                  *(ptrd++) = (val<<16) | (val<<8) | val;
  1.8217 +                }
  1.8218 +              else
  1.8219 +                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8220 +                  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8221 +                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
  1.8222 +                }
  1.8223 +              break;
  1.8224 +            case 2 :
  1.8225 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8226 +                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8227 +                  *(ptrd++) =
  1.8228 +                    ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
  1.8229 +                    ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
  1.8230 +              else
  1.8231 +                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8232 +                  *(ptrd++) =
  1.8233 +                    ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
  1.8234 +                    ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
  1.8235 +              break;
  1.8236 +            default :
  1.8237 +              if (cimg::X11attr().byte_order==cimg::endianness())
  1.8238 +                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8239 +                  *(ptrd++) =
  1.8240 +                    ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
  1.8241 +                    ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
  1.8242 +                    (unsigned char)(255*(*(data3++)-min)/mm);
  1.8243 +              else
  1.8244 +                for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8245 +                  *(ptrd++) =
  1.8246 +                    ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
  1.8247 +                    ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
  1.8248 +                    ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
  1.8249 +            }
  1.8250 +          } else {
  1.8251 +            unsigned char *ptrd = (unsigned char*)ndata;
  1.8252 +            switch (img.dim) {
  1.8253 +            case 1 :
  1.8254 +              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8255 +                const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8256 +                (*ptrd++) = 0;
  1.8257 +                (*ptrd++) = val;
  1.8258 +                (*ptrd++) = val;
  1.8259 +                (*ptrd++) = val;
  1.8260 +              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8261 +                const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8262 +                (*ptrd++) = val;
  1.8263 +                (*ptrd++) = val;
  1.8264 +                (*ptrd++) = val;
  1.8265 +                (*ptrd++) = 0;
  1.8266 +              }
  1.8267 +              break;
  1.8268 +            case 2 :
  1.8269 +              if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
  1.8270 +              for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8271 +                (*ptrd++) = 0;
  1.8272 +                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  1.8273 +                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8274 +                (*ptrd++) = 0;
  1.8275 +              }
  1.8276 +              break;
  1.8277 +            default :
  1.8278 +              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8279 +                (*ptrd++) = 0;
  1.8280 +                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8281 +                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  1.8282 +                (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
  1.8283 +              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8284 +                (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
  1.8285 +                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
  1.8286 +                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8287 +                (*ptrd++) = 0;
  1.8288 +              }
  1.8289 +            }
  1.8290 +          }
  1.8291 +          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
  1.8292 +        }
  1.8293 +        }
  1.8294 +      }
  1.8295 +      XUnlockDisplay(cimg::X11attr().display);
  1.8296 +      return *this;
  1.8297 +    }
  1.8298 +
  1.8299 +    template<typename T>
  1.8300 +    const CImgDisplay& snapshot(CImg<T>& img) const {
  1.8301 +      if (is_empty()) img.assign();
  1.8302 +      else {
  1.8303 +        img.assign(width,height,1,3);
  1.8304 +        T
  1.8305 +          *data1 = img.ptr(0,0,0,0),
  1.8306 +          *data2 = img.ptr(0,0,0,1),
  1.8307 +          *data3 = img.ptr(0,0,0,2);
  1.8308 +        if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
  1.8309 +        switch (cimg::X11attr().nb_bits) {
  1.8310 +        case 8 : {
  1.8311 +          unsigned char *ptrs = (unsigned char*)data;
  1.8312 +          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8313 +            const unsigned char val = *(ptrs++);
  1.8314 +            *(data1++) = val&0xe0;
  1.8315 +            *(data2++) = (val&0x1c)<<3;
  1.8316 +            *(data3++) = val<<6;
  1.8317 +          }
  1.8318 +        } break;
  1.8319 +        case 16 : {
  1.8320 +          unsigned char *ptrs = (unsigned char*)data;
  1.8321 +          if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8322 +            const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
  1.8323 +            *(data1++) = val0&0xf8;
  1.8324 +            *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
  1.8325 +            *(data3++) = val1<<3;
  1.8326 +          } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8327 +            const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
  1.8328 +            *(data1++) = val1&0xf8;
  1.8329 +            *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
  1.8330 +            *(data3++) = val0<<3;
  1.8331 +          }
  1.8332 +        } break;
  1.8333 +        default : {
  1.8334 +          unsigned char *ptrs = (unsigned char*)data;
  1.8335 +          if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8336 +            ++ptrs;
  1.8337 +            *(data1++) = *(ptrs++);
  1.8338 +            *(data2++) = *(ptrs++);
  1.8339 +            *(data3++) = *(ptrs++);
  1.8340 +          } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8341 +            *(data3++) = *(ptrs++);
  1.8342 +            *(data2++) = *(ptrs++);
  1.8343 +            *(data1++) = *(ptrs++);
  1.8344 +            ++ptrs;
  1.8345 +          }
  1.8346 +        }
  1.8347 +        }
  1.8348 +      }
  1.8349 +      return *this;
  1.8350 +    }
  1.8351 +
  1.8352 +    // Windows-based display
  1.8353 +    //-----------------------
  1.8354 +#elif cimg_display==2
  1.8355 +    CLIENTCREATESTRUCT ccs;
  1.8356 +    BITMAPINFO bmi;
  1.8357 +    unsigned int *data;
  1.8358 +    DEVMODE curr_mode;
  1.8359 +    HWND window;
  1.8360 +    HWND background_window;
  1.8361 +    HDC hdc;
  1.8362 +    HANDLE thread;
  1.8363 +    HANDLE created;
  1.8364 +    HANDLE mutex;
  1.8365 +    bool mouse_tracking;
  1.8366 +    bool visible_cursor;
  1.8367 +
  1.8368 +    static int screen_dimx() {
  1.8369 +      DEVMODE mode;
  1.8370 +      mode.dmSize = sizeof(DEVMODE);
  1.8371 +      mode.dmDriverExtra = 0;
  1.8372 +      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
  1.8373 +      return mode.dmPelsWidth;
  1.8374 +    }
  1.8375 +
  1.8376 +    static int screen_dimy() {
  1.8377 +      DEVMODE mode;
  1.8378 +      mode.dmSize = sizeof(DEVMODE);
  1.8379 +      mode.dmDriverExtra = 0;
  1.8380 +      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
  1.8381 +      return mode.dmPelsHeight;
  1.8382 +    }
  1.8383 +
  1.8384 +    static void wait_all() {
  1.8385 +      WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
  1.8386 +    }
  1.8387 +
  1.8388 +    static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
  1.8389 +#ifdef _WIN64
  1.8390 +      CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
  1.8391 +#else
  1.8392 +      CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
  1.8393 +#endif
  1.8394 +      MSG st_msg;
  1.8395 +
  1.8396 +      switch (msg) {
  1.8397 +      case WM_CLOSE :
  1.8398 +        disp->mouse_x = disp->mouse_y = -1;
  1.8399 +        disp->window_x = disp->window_y = 0;
  1.8400 +        if (disp->button) {
  1.8401 +          cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8402 +          disp->button = 0;
  1.8403 +        }
  1.8404 +        if (disp->key) {
  1.8405 +          cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  1.8406 +          disp->key = 0;
  1.8407 +        }
  1.8408 +        if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  1.8409 +        disp->is_closed = true;
  1.8410 +        ReleaseMutex(disp->mutex);
  1.8411 +        ShowWindow(disp->window,SW_HIDE);
  1.8412 +        disp->is_event = true;
  1.8413 +        SetEvent(cimg::Win32attr().wait_event);
  1.8414 +        return 0;
  1.8415 +      case WM_SIZE : {
  1.8416 +        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
  1.8417 +        WaitForSingleObject(disp->mutex,INFINITE);
  1.8418 +        const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
  1.8419 +        if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
  1.8420 +          disp->window_width = nw;
  1.8421 +          disp->window_height = nh;
  1.8422 +          disp->mouse_x = disp->mouse_y = -1;
  1.8423 +          disp->is_resized = disp->is_event = true;
  1.8424 +          SetEvent(cimg::Win32attr().wait_event);
  1.8425 +        }
  1.8426 +        ReleaseMutex(disp->mutex);
  1.8427 +      } break;
  1.8428 +      case WM_MOVE : {
  1.8429 +        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
  1.8430 +        WaitForSingleObject(disp->mutex,INFINITE);
  1.8431 +        const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
  1.8432 +        if (nx!=disp->window_x || ny!=disp->window_y) {
  1.8433 +          disp->window_x = nx;
  1.8434 +          disp->window_y = ny;
  1.8435 +          disp->is_moved = disp->is_event = true;
  1.8436 +          SetEvent(cimg::Win32attr().wait_event);
  1.8437 +        }
  1.8438 +        ReleaseMutex(disp->mutex);
  1.8439 +      } break;
  1.8440 +      case WM_PAINT :
  1.8441 +        disp->paint();
  1.8442 +        break;
  1.8443 +      case WM_KEYDOWN :
  1.8444 +        disp->update_iskey((unsigned int)wParam,true);
  1.8445 +        if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  1.8446 +        disp->key = (unsigned int)wParam;
  1.8447 +        if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  1.8448 +        disp->is_event = true;
  1.8449 +        SetEvent(cimg::Win32attr().wait_event);
  1.8450 +        break;
  1.8451 +      case WM_MOUSEMOVE : {
  1.8452 +        while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
  1.8453 +        disp->mouse_x = LOWORD(lParam);
  1.8454 +        disp->mouse_y = HIWORD(lParam);
  1.8455 +#if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
  1.8456 +        if (!disp->mouse_tracking) {
  1.8457 +          TRACKMOUSEEVENT tme;
  1.8458 +          tme.cbSize = sizeof(TRACKMOUSEEVENT);
  1.8459 +          tme.dwFlags = TME_LEAVE;
  1.8460 +          tme.hwndTrack = disp->window;
  1.8461 +          if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
  1.8462 +        }
  1.8463 +#endif
  1.8464 +        if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
  1.8465 +          disp->mouse_x = disp->mouse_y = -1;
  1.8466 +        disp->is_event = true;
  1.8467 +        SetEvent(cimg::Win32attr().wait_event);
  1.8468 +      } break;
  1.8469 +      case WM_MOUSELEAVE : {
  1.8470 +        disp->mouse_x = disp->mouse_y = -1;
  1.8471 +        disp->mouse_tracking = false;
  1.8472 +      } break;
  1.8473 +      case WM_LBUTTONDOWN :
  1.8474 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8475 +        disp->button|=1U;
  1.8476 +        disp->is_event = true;
  1.8477 +        SetEvent(cimg::Win32attr().wait_event);
  1.8478 +        break;
  1.8479 +      case WM_RBUTTONDOWN :
  1.8480 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8481 +        disp->button|=2U;
  1.8482 +        disp->is_event = true;
  1.8483 +        SetEvent(cimg::Win32attr().wait_event);
  1.8484 +        break;
  1.8485 +      case WM_MBUTTONDOWN :
  1.8486 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8487 +        disp->button|=4U;
  1.8488 +        disp->is_event = true;
  1.8489 +        SetEvent(cimg::Win32attr().wait_event);
  1.8490 +        break;
  1.8491 +      case 0x020A : // WM_MOUSEWHEEL:
  1.8492 +        disp->wheel+=(int)((short)HIWORD(wParam))/120;
  1.8493 +        disp->is_event = true;
  1.8494 +        SetEvent(cimg::Win32attr().wait_event);
  1.8495 +      case WM_KEYUP :
  1.8496 +        disp->update_iskey((unsigned int)wParam,false);
  1.8497 +        if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
  1.8498 +        if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
  1.8499 +        disp->released_key = (unsigned int)wParam;
  1.8500 +        disp->is_event = true;
  1.8501 +        SetEvent(cimg::Win32attr().wait_event);
  1.8502 +        break;
  1.8503 +      case WM_LBUTTONUP :
  1.8504 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8505 +        disp->button&=~1U;
  1.8506 +        disp->is_event = true;
  1.8507 +        SetEvent(cimg::Win32attr().wait_event);
  1.8508 +        break;
  1.8509 +      case WM_RBUTTONUP :
  1.8510 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8511 +        disp->button&=~2U;
  1.8512 +        disp->is_event = true;
  1.8513 +        SetEvent(cimg::Win32attr().wait_event);
  1.8514 +        break;
  1.8515 +      case WM_MBUTTONUP :
  1.8516 +        cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.8517 +        disp->button&=~4U;
  1.8518 +        disp->is_event = true;
  1.8519 +        SetEvent(cimg::Win32attr().wait_event);
  1.8520 +        break;
  1.8521 +      case WM_SETCURSOR :
  1.8522 +        if (disp->visible_cursor) ShowCursor(TRUE);
  1.8523 +        else ShowCursor(FALSE);
  1.8524 +        break;
  1.8525 +      }
  1.8526 +      return DefWindowProc(window,msg,wParam,lParam);
  1.8527 +    }
  1.8528 +
  1.8529 +    static DWORD WINAPI _events_thread(void* arg) {
  1.8530 +      CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
  1.8531 +      const char *title = (const char*)(((void**)arg)[1]);
  1.8532 +      MSG msg;
  1.8533 +      delete[] (void**)arg;
  1.8534 +      disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1.8535 +      disp->bmi.bmiHeader.biWidth = disp->width;
  1.8536 +      disp->bmi.bmiHeader.biHeight = -(int)disp->height;
  1.8537 +      disp->bmi.bmiHeader.biPlanes = 1;
  1.8538 +      disp->bmi.bmiHeader.biBitCount = 32;
  1.8539 +      disp->bmi.bmiHeader.biCompression = BI_RGB;
  1.8540 +      disp->bmi.bmiHeader.biSizeImage = 0;
  1.8541 +      disp->bmi.bmiHeader.biXPelsPerMeter = 1;
  1.8542 +      disp->bmi.bmiHeader.biYPelsPerMeter = 1;
  1.8543 +      disp->bmi.bmiHeader.biClrUsed = 0;
  1.8544 +      disp->bmi.bmiHeader.biClrImportant = 0;
  1.8545 +      disp->data = new unsigned int[disp->width*disp->height];
  1.8546 +      if (!disp->is_fullscreen) { // Normal window
  1.8547 +        RECT rect;
  1.8548 +        rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
  1.8549 +        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  1.8550 +        const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
  1.8551 +        disp->window = CreateWindowA("MDICLIENT",title?title:" ",
  1.8552 +                                     WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
  1.8553 +                                     disp->width + 2*border1, disp->height + border1 + border2,
  1.8554 +                                     0,0,0,&(disp->ccs));
  1.8555 +        if (!disp->is_closed) {
  1.8556 +          GetWindowRect(disp->window,&rect);
  1.8557 +          disp->window_x = rect.left + border1;
  1.8558 +          disp->window_y = rect.top + border2;
  1.8559 +        } else disp->window_x = disp->window_y = 0;
  1.8560 +      } else { // Fullscreen window
  1.8561 +        const unsigned int sx = screen_dimx(), sy = screen_dimy();
  1.8562 +        disp->window = CreateWindowA("MDICLIENT",title?title:" ",
  1.8563 +                                     WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
  1.8564 +                                     disp->width,disp->height,0,0,0,&(disp->ccs));
  1.8565 +        disp->window_x = disp->window_y = 0;
  1.8566 +      }
  1.8567 +      SetForegroundWindow(disp->window);
  1.8568 +      disp->hdc = GetDC(disp->window);
  1.8569 +      disp->window_width = disp->width;
  1.8570 +      disp->window_height = disp->height;
  1.8571 +      disp->flush();
  1.8572 +#ifdef _WIN64
  1.8573 +      SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
  1.8574 +      SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
  1.8575 +#else
  1.8576 +      SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
  1.8577 +      SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
  1.8578 +#endif
  1.8579 +      SetEvent(disp->created);
  1.8580 +      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
  1.8581 +      return 0;
  1.8582 +    }
  1.8583 +
  1.8584 +    CImgDisplay& _update_window_pos() {
  1.8585 +      if (!is_closed) {
  1.8586 +        RECT rect;
  1.8587 +        rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
  1.8588 +        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  1.8589 +        const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
  1.8590 +        GetWindowRect(window,&rect);
  1.8591 +        window_x = rect.left + border1;
  1.8592 +        window_y = rect.top + border2;
  1.8593 +      } else window_x = window_y = -1;
  1.8594 +      return *this;
  1.8595 +    }
  1.8596 +
  1.8597 +    void _init_fullscreen() {
  1.8598 +      background_window = 0;
  1.8599 +      if (is_fullscreen && !is_closed) {
  1.8600 +        DEVMODE mode;
  1.8601 +        unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
  1.8602 +        for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
  1.8603 +          const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
  1.8604 +          if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
  1.8605 +            bestbpp = mode.dmBitsPerPel;
  1.8606 +            ibest = imode;
  1.8607 +            bw = nw; bh = nh;
  1.8608 +          }
  1.8609 +        }
  1.8610 +        if (bestbpp) {
  1.8611 +          curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
  1.8612 +          EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
  1.8613 +          EnumDisplaySettings(0,ibest,&mode);
  1.8614 +          ChangeDisplaySettings(&mode,0);
  1.8615 +        } else curr_mode.dmSize = 0;
  1.8616 +
  1.8617 +        const unsigned int sx = screen_dimx(), sy = screen_dimy();
  1.8618 +        if (sx!=width || sy!=height) {
  1.8619 +          CLIENTCREATESTRUCT background_ccs;
  1.8620 +          background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
  1.8621 +          SetForegroundWindow(background_window);
  1.8622 +        }
  1.8623 +      } else curr_mode.dmSize = 0;
  1.8624 +    }
  1.8625 +
  1.8626 +    void _desinit_fullscreen() {
  1.8627 +      if (is_fullscreen) {
  1.8628 +        if (background_window) DestroyWindow(background_window);
  1.8629 +        background_window = 0;
  1.8630 +        if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
  1.8631 +        is_fullscreen = false;
  1.8632 +      }
  1.8633 +    }
  1.8634 +
  1.8635 +    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  1.8636 +                         const unsigned int normalization_type=3,
  1.8637 +                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.8638 +
  1.8639 +      // Allocate space for window title
  1.8640 +      const int s = cimg::strlen(ptitle)+1;
  1.8641 +      char *tmp_title = s?new char[s]:0;
  1.8642 +      if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  1.8643 +
  1.8644 +      // Destroy previous window if existing
  1.8645 +      if (!is_empty()) assign();
  1.8646 +
  1.8647 +      // Set display variables
  1.8648 +      width = cimg::min(dimw,(unsigned int)screen_dimx());
  1.8649 +      height = cimg::min(dimh,(unsigned int)screen_dimy());
  1.8650 +      normalization = normalization_type<4?normalization_type:3;
  1.8651 +      is_fullscreen = fullscreen_flag;
  1.8652 +      window_x = window_y = 0;
  1.8653 +      is_closed = closed_flag;
  1.8654 +      visible_cursor = true;
  1.8655 +      mouse_tracking = false;
  1.8656 +      title = tmp_title;
  1.8657 +      flush();
  1.8658 +      if (is_fullscreen) _init_fullscreen();
  1.8659 +
  1.8660 +      // Create event thread
  1.8661 +      void *arg = (void*)(new void*[2]);
  1.8662 +      ((void**)arg)[0]=(void*)this;
  1.8663 +      ((void**)arg)[1]=(void*)title;
  1.8664 +      unsigned long ThreadID = 0;
  1.8665 +      mutex = CreateMutex(0,FALSE,0);
  1.8666 +      created = CreateEvent(0,FALSE,FALSE,0);
  1.8667 +      thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
  1.8668 +      WaitForSingleObject(created,INFINITE);
  1.8669 +      return *this;
  1.8670 +    }
  1.8671 +
  1.8672 +    CImgDisplay& assign() {
  1.8673 +      if (is_empty()) return *this;
  1.8674 +      DestroyWindow(window);
  1.8675 +      TerminateThread(thread,0);
  1.8676 +      if (data) delete[] data;
  1.8677 +      if (title) delete[] title;
  1.8678 +      if (is_fullscreen) _desinit_fullscreen();
  1.8679 +      width = height = normalization = window_width = window_height = 0;
  1.8680 +      window_x = window_y = 0;
  1.8681 +      is_fullscreen = false;
  1.8682 +      is_closed = true;
  1.8683 +      min = max = 0;
  1.8684 +      title = 0;
  1.8685 +      flush();
  1.8686 +      return *this;
  1.8687 +    }
  1.8688 +
  1.8689 +    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  1.8690 +                        const unsigned int normalization_type=3,
  1.8691 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.8692 +      if (!dimw || !dimh) return assign();
  1.8693 +      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  1.8694 +      min = max = 0;
  1.8695 +      cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
  1.8696 +      return paint();
  1.8697 +    }
  1.8698 +
  1.8699 +    template<typename T>
  1.8700 +    CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  1.8701 +                        const unsigned int normalization_type=3,
  1.8702 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.8703 +      if (!img) return assign();
  1.8704 +      CImg<T> tmp;
  1.8705 +      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.8706 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.8707 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.8708 +      return display(nimg);
  1.8709 +    }
  1.8710 +
  1.8711 +    template<typename T>
  1.8712 +    CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  1.8713 +                        const unsigned int normalization_type=3,
  1.8714 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.8715 +      if (!list) return assign();
  1.8716 +      CImg<T> tmp;
  1.8717 +      const CImg<T> img = list.get_append('x','p'),
  1.8718 +        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.8719 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.8720 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.8721 +      return display(nimg);
  1.8722 +    }
  1.8723 +
  1.8724 +    CImgDisplay& assign(const CImgDisplay& win) {
  1.8725 +      if (!win) return assign();
  1.8726 +      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  1.8727 +      cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
  1.8728 +      return paint();
  1.8729 +    }
  1.8730 +
  1.8731 +    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  1.8732 +      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  1.8733 +      if (is_empty()) return assign(nwidth,nheight);
  1.8734 +      const unsigned int
  1.8735 +        tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
  1.8736 +        tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
  1.8737 +        dimx = tmpdimx?tmpdimx:1,
  1.8738 +        dimy = tmpdimy?tmpdimy:1;
  1.8739 +      if (window_width!=dimx || window_height!=dimy) {
  1.8740 +        RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
  1.8741 +        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  1.8742 +        const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
  1.8743 +        SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
  1.8744 +      }
  1.8745 +      if (width!=dimx || height!=dimy) {
  1.8746 +        unsigned int *ndata = new unsigned int[dimx*dimy];
  1.8747 +        if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
  1.8748 +        else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
  1.8749 +        delete[] data;
  1.8750 +        data = ndata;
  1.8751 +        bmi.bmiHeader.biWidth = dimx;
  1.8752 +        bmi.bmiHeader.biHeight = -(int)dimy;
  1.8753 +        width = dimx;
  1.8754 +        height = dimy;
  1.8755 +      }
  1.8756 +      window_width = dimx; window_height = dimy;
  1.8757 +      is_resized = false;
  1.8758 +      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  1.8759 +      if (redraw) return paint();
  1.8760 +      return *this;
  1.8761 +    }
  1.8762 +
  1.8763 +    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  1.8764 +      if (is_empty()) return *this;
  1.8765 +      if (redraw) {
  1.8766 +        const unsigned int bufsize = width*height*4;
  1.8767 +        void *odata = cimg_std::malloc(bufsize);
  1.8768 +        cimg_std::memcpy(odata,data,bufsize);
  1.8769 +        assign(width,height,title,normalization,!is_fullscreen,false);
  1.8770 +        cimg_std::memcpy(data,odata,bufsize);
  1.8771 +        cimg_std::free(odata);
  1.8772 +        return paint();
  1.8773 +      }
  1.8774 +      return assign(width,height,title,normalization,!is_fullscreen,false);
  1.8775 +    }
  1.8776 +
  1.8777 +    CImgDisplay& show() {
  1.8778 +      if (is_empty()) return *this;
  1.8779 +      if (is_closed) {
  1.8780 +        is_closed = false;
  1.8781 +        if (is_fullscreen) _init_fullscreen();
  1.8782 +        ShowWindow(window,SW_SHOW);
  1.8783 +        _update_window_pos();
  1.8784 +      }
  1.8785 +      return paint();
  1.8786 +    }
  1.8787 +
  1.8788 +    CImgDisplay& close() {
  1.8789 +      if (is_empty()) return *this;
  1.8790 +      if (!is_closed && !is_fullscreen) {
  1.8791 +        if (is_fullscreen) _desinit_fullscreen();
  1.8792 +        ShowWindow(window,SW_HIDE);
  1.8793 +        is_closed = true;
  1.8794 +        window_x = window_y = 0;
  1.8795 +      }
  1.8796 +      return *this;
  1.8797 +    }
  1.8798 +
  1.8799 +    CImgDisplay& move(const int posx, const int posy) {
  1.8800 +      if (is_empty()) return *this;
  1.8801 +      if (!is_fullscreen) {
  1.8802 +        RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
  1.8803 +        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  1.8804 +        const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
  1.8805 +        SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
  1.8806 +      } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
  1.8807 +      window_x = posx;
  1.8808 +      window_y = posy;
  1.8809 +      is_moved = false;
  1.8810 +      return show();
  1.8811 +    }
  1.8812 +
  1.8813 +    CImgDisplay& show_mouse() {
  1.8814 +      if (is_empty()) return *this;
  1.8815 +      visible_cursor = true;
  1.8816 +      ShowCursor(TRUE);
  1.8817 +      SendMessage(window,WM_SETCURSOR,0,0);
  1.8818 +      return *this;
  1.8819 +    }
  1.8820 +
  1.8821 +    CImgDisplay& hide_mouse() {
  1.8822 +      if (is_empty()) return *this;
  1.8823 +      visible_cursor = false;
  1.8824 +      ShowCursor(FALSE);
  1.8825 +      SendMessage(window,WM_SETCURSOR,0,0);
  1.8826 +      return *this;
  1.8827 +    }
  1.8828 +
  1.8829 +    CImgDisplay& set_mouse(const int posx, const int posy) {
  1.8830 +      if (!is_closed && posx>=0 && posy>=0) {
  1.8831 +        _update_window_pos();
  1.8832 +        const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
  1.8833 +        if (res) { mouse_x = posx; mouse_y = posy; }
  1.8834 +      }
  1.8835 +      return *this;
  1.8836 +    }
  1.8837 +
  1.8838 +    CImgDisplay& set_title(const char *format, ...) {
  1.8839 +      if (is_empty()) return *this;
  1.8840 +      char tmp[1024] = {0};
  1.8841 +      va_list ap;
  1.8842 +      va_start(ap, format);
  1.8843 +      cimg_std::vsprintf(tmp,format,ap);
  1.8844 +      va_end(ap);
  1.8845 +      if (title) delete[] title;
  1.8846 +      const int s = cimg::strlen(tmp)+1;
  1.8847 +      title = new char[s];
  1.8848 +      cimg_std::memcpy(title,tmp,s*sizeof(char));
  1.8849 +      SetWindowTextA(window, tmp);
  1.8850 +      return *this;
  1.8851 +    }
  1.8852 +
  1.8853 +    template<typename T>
  1.8854 +    CImgDisplay& display(const CImg<T>& img) {
  1.8855 +      if (img.is_empty())
  1.8856 +        throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
  1.8857 +      if (is_empty()) assign(img.width,img.height);
  1.8858 +      return render(img).paint();
  1.8859 +    }
  1.8860 +
  1.8861 +    CImgDisplay& paint() {
  1.8862 +      if (!is_closed) {
  1.8863 +        WaitForSingleObject(mutex,INFINITE);
  1.8864 +        SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
  1.8865 +        ReleaseMutex(mutex);
  1.8866 +      }
  1.8867 +      return *this;
  1.8868 +    }
  1.8869 +
  1.8870 +    template<typename T>
  1.8871 +    CImgDisplay& render(const CImg<T>& img) {
  1.8872 +      if (is_empty()) return *this;
  1.8873 +      if (!img)
  1.8874 +        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  1.8875 +                                    img.width,img.height,img.depth,img.dim,img.data);
  1.8876 +      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.8877 +
  1.8878 +      const T
  1.8879 +        *data1 = img.data,
  1.8880 +        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
  1.8881 +        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
  1.8882 +
  1.8883 +      WaitForSingleObject(mutex,INFINITE);
  1.8884 +      unsigned int
  1.8885 +        *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
  1.8886 +        *ptrd = ndata;
  1.8887 +
  1.8888 +      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  1.8889 +        min = max = 0;
  1.8890 +        switch (img.dim) {
  1.8891 +        case 1 : {
  1.8892 +          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8893 +            const unsigned char val = (unsigned char)*(data1++);
  1.8894 +            *(ptrd++) = (val<<16) | (val<<8) | val;
  1.8895 +          }} break;
  1.8896 +        case 2 : {
  1.8897 +          for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8898 +            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
  1.8899 +        } break;
  1.8900 +        default : {
  1.8901 +          for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.8902 +            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  1.8903 +        }
  1.8904 +        }
  1.8905 +      } else {
  1.8906 +        if (normalization==3) {
  1.8907 +          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  1.8908 +          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
  1.8909 +        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  1.8910 +        const float delta = max-min, mm = delta?delta:1.0f;
  1.8911 +        switch (img.dim) {
  1.8912 +        case 1 : {
  1.8913 +          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8914 +            const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
  1.8915 +            *(ptrd++) = (val<<16) | (val<<8) | val;
  1.8916 +          }} break;
  1.8917 +        case 2 : {
  1.8918 +          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8919 +            const unsigned char
  1.8920 +              R = (unsigned char)(255*(*(data1++)-min)/mm),
  1.8921 +              G = (unsigned char)(255*(*(data2++)-min)/mm);
  1.8922 +            *(ptrd++) = (R<<16) | (G<<8);
  1.8923 +          }} break;
  1.8924 +        default : {
  1.8925 +          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8926 +            const unsigned char
  1.8927 +              R = (unsigned char)(255*(*(data1++)-min)/mm),
  1.8928 +              G = (unsigned char)(255*(*(data2++)-min)/mm),
  1.8929 +              B = (unsigned char)(255*(*(data3++)-min)/mm);
  1.8930 +            *(ptrd++) = (R<<16) | (G<<8) | B;
  1.8931 +          }}
  1.8932 +        }
  1.8933 +      }
  1.8934 +      if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
  1.8935 +      ReleaseMutex(mutex);
  1.8936 +      return *this;
  1.8937 +    }
  1.8938 +
  1.8939 +    template<typename T>
  1.8940 +    const CImgDisplay& snapshot(CImg<T>& img) const {
  1.8941 +      if (is_empty()) img.assign();
  1.8942 +      else {
  1.8943 +        img.assign(width,height,1,3);
  1.8944 +        T
  1.8945 +          *data1 = img.ptr(0,0,0,0),
  1.8946 +          *data2 = img.ptr(0,0,0,1),
  1.8947 +          *data3 = img.ptr(0,0,0,2);
  1.8948 +        unsigned int *ptrs = data;
  1.8949 +         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.8950 +          const unsigned int val = *(ptrs++);
  1.8951 +          *(data1++) = (unsigned char)(val>>16);
  1.8952 +          *(data2++) = (unsigned char)((val>>8)&0xFF);
  1.8953 +          *(data3++) = (unsigned char)(val&0xFF);
  1.8954 +        }
  1.8955 +      }
  1.8956 +      return *this;
  1.8957 +    }
  1.8958 +
  1.8959 +    // MacOSX - Carbon-based display
  1.8960 +    //-------------------------------
  1.8961 +    // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
  1.8962 +    //
  1.8963 +#elif cimg_display==3
  1.8964 +    unsigned int *data;                     // The bits of the picture
  1.8965 +    WindowRef carbonWindow;                 // The opaque carbon window struct associated with the display
  1.8966 +    MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
  1.8967 +    CGColorSpaceRef csr;                    // Needed for painting
  1.8968 +    CGDataProviderRef dataProvider;         // Needed for painting
  1.8969 +    CGImageRef imageRef;                    // The image
  1.8970 +    UInt32 lastKeyModifiers;                // Buffer storing modifiers state
  1.8971 +
  1.8972 +    // Define the kind of the queries which can be serialized using the event thread.
  1.8973 +    typedef enum {
  1.8974 +      COM_CREATEWINDOW = 0, // Create window query
  1.8975 +      COM_RELEASEWINDOW,    // Release window query
  1.8976 +      COM_SHOWWINDOW,       // Show window query
  1.8977 +      COM_HIDEWINDOW,       // Hide window query
  1.8978 +      COM_SHOWMOUSE,        // Show mouse query
  1.8979 +      COM_HIDEMOUSE,        // Hide mouse query
  1.8980 +      COM_RESIZEWINDOW,     // Resize window query
  1.8981 +      COM_MOVEWINDOW,       // Move window query
  1.8982 +      COM_SETTITLE,         // Set window title query
  1.8983 +      COM_SETMOUSEPOS       // Set cursor position query
  1.8984 +    } CImgCarbonQueryKind;
  1.8985 +
  1.8986 +    // The query destructor send to the event thread.
  1.8987 +    struct CbSerializedQuery {
  1.8988 +      CImgDisplay* sender;         // Query's sender
  1.8989 +      CImgCarbonQueryKind kind;    // The kind of the query sent to the background thread
  1.8990 +      short x, y;                  // X:Y values for move/resize operations
  1.8991 +      char *c;                     // Char values for window title
  1.8992 +      bool createFullScreenWindow; // Boolean value used for full-screen window creation
  1.8993 +      bool createClosedWindow;     // Boolean value used for closed-window creation
  1.8994 +      bool update;                 // Boolean value used for resize
  1.8995 +      bool success;                // Succes or failure of the message, used as return value
  1.8996 +      CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
  1.8997 +
  1.8998 +      inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
  1.8999 +        return CbSerializedQuery(sender, COM_RELEASEWINDOW);
  1.9000 +      }
  1.9001 +      inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
  1.9002 +        CbSerializedQuery q(sender, COM_CREATEWINDOW);
  1.9003 +        q.createFullScreenWindow = fullscreen;
  1.9004 +        q.createClosedWindow = closed;
  1.9005 +        return q;
  1.9006 +      }
  1.9007 +      inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
  1.9008 +        return CbSerializedQuery(sender, COM_SHOWWINDOW);
  1.9009 +      }
  1.9010 +      inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
  1.9011 +        return CbSerializedQuery(sender, COM_HIDEWINDOW);
  1.9012 +      }
  1.9013 +      inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
  1.9014 +        return CbSerializedQuery(sender, COM_SHOWMOUSE);
  1.9015 +      }
  1.9016 +      inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
  1.9017 +        return CbSerializedQuery(sender, COM_HIDEMOUSE);
  1.9018 +      }
  1.9019 +      inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
  1.9020 +        CbSerializedQuery q(sender, COM_RESIZEWINDOW);
  1.9021 +        q.x = x, q.y = y;
  1.9022 +        q.update = update;
  1.9023 +        return q;
  1.9024 +      }
  1.9025 +      inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
  1.9026 +        CbSerializedQuery q(sender, COM_MOVEWINDOW);
  1.9027 +        q.x = x, q.y = y;
  1.9028 +        return q;
  1.9029 +      }
  1.9030 +      inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
  1.9031 +        CbSerializedQuery q(sender, COM_SETTITLE);
  1.9032 +        q.c = c;
  1.9033 +        return q;
  1.9034 +      }
  1.9035 +      inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
  1.9036 +        CbSerializedQuery q(sender, COM_SETMOUSEPOS);
  1.9037 +        q.x = x, q.y = y;
  1.9038 +        return q;
  1.9039 +      }
  1.9040 +    };
  1.9041 +
  1.9042 +    // Send a serialized query in a synchroneous way.
  1.9043 +    // @param c Application Carbon global settings.
  1.9044 +    // @param m The query to send.
  1.9045 +    // @result Success/failure of the operation returned by the event thread.
  1.9046 +    bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
  1.9047 +      MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
  1.9048 +      MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
  1.9049 +      return m.success;
  1.9050 +    }
  1.9051 +
  1.9052 +    // Free the window attached to the current display.
  1.9053 +    // @param c Application Carbon global settings.
  1.9054 +    // @result Success/failure of the operation.
  1.9055 +    bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
  1.9056 +      if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
  1.9057 +        throw CImgDisplayException("Cannot release window associated with the current display.");
  1.9058 +      // If a window existed, ask to release it
  1.9059 +      MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
  1.9060 +      --c.windowCount; //Decrement the window count
  1.9061 +      MPExitCriticalRegion(c.windowListCR); // Unlock the list
  1.9062 +      return c.windowCount == 0;
  1.9063 +    }
  1.9064 +
  1.9065 +    // Create the window attached to the current display.
  1.9066 +    // @param c Application Carbon global settings.
  1.9067 +    // @param title The window title, if any.
  1.9068 +    // @param fullscreen Shoud we start in fullscreen mode ?
  1.9069 +    // @param create_closed If true, the window is created but not displayed.
  1.9070 +    // @result Success/failure of the operation.
  1.9071 +    void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
  1.9072 +      if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
  1.9073 +        throw CImgDisplayException("Cannot create the window associated with the current display.");
  1.9074 +      if (title) set_title(title); // Set the title, if any
  1.9075 +      // Now we can register the window
  1.9076 +      MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
  1.9077 +      ++c.windowCount; //Increment the window count
  1.9078 +      MPExitCriticalRegion(c.windowListCR); // Unlock the list
  1.9079 +    }
  1.9080 +
  1.9081 +    // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
  1.9082 +    void _CbFinalizeGraphics() {
  1.9083 +      CGImageRelease (imageRef); // Release the picture
  1.9084 +      CGDataProviderRelease(dataProvider); // Release the DP
  1.9085 +      CGColorSpaceRelease(csr); // Free the cs
  1.9086 +    }
  1.9087 +
  1.9088 +    // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
  1.9089 +    void _CbInitializeGraphics() {
  1.9090 +      csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
  1.9091 +      if (!csr)
  1.9092 +        throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
  1.9093 +      // Create the DP
  1.9094 +      dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
  1.9095 +      if (!dataProvider)
  1.9096 +        throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
  1.9097 +      // ... and finally the image.
  1.9098 +      if (cimg::endianness())
  1.9099 +        imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
  1.9100 +                                 kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
  1.9101 +      else
  1.9102 +        imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
  1.9103 +                                 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
  1.9104 +      if (!imageRef)
  1.9105 +        throw CImgDisplayException("CGImageCreate() failed.");
  1.9106 +    }
  1.9107 +
  1.9108 +    // Reinit graphic objects. Free them, then reallocate all.
  1.9109 +    // This is used when image bounds are changed or when data source get invalid.
  1.9110 +    void _CbReinitGraphics() {
  1.9111 +      MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
  1.9112 +      _CbFinalizeGraphics();
  1.9113 +      _CbInitializeGraphics();
  1.9114 +      MPExitCriticalRegion(paintCriticalRegion);
  1.9115 +    }
  1.9116 +
  1.9117 +    // Convert a point having global coordonates into the window coordonates.
  1.9118 +    // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
  1.9119 +    // @param mouseEvent The mouse event which triggered the event handler.
  1.9120 +    // @param window The window where the event occured.
  1.9121 +    // @param point The modified point struct.
  1.9122 +    // @result True if the point struct has been converted successfully.
  1.9123 +    static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
  1.9124 +      Rect bounds;
  1.9125 +      if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
  1.9126 +        point->x -= bounds.left;
  1.9127 +        point->y -= bounds.top;
  1.9128 +        HIViewRef view = NULL;
  1.9129 +        if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
  1.9130 +          return HIViewConvertPoint(point, NULL, view) == noErr;
  1.9131 +      }
  1.9132 +      return false;
  1.9133 +    }
  1.9134 +
  1.9135 +    static int screen_dimx() {
  1.9136 +      return CGDisplayPixelsWide(kCGDirectMainDisplay);
  1.9137 +    }
  1.9138 +
  1.9139 +    static int screen_dimy() {
  1.9140 +      return CGDisplayPixelsHigh(kCGDirectMainDisplay);
  1.9141 +    }
  1.9142 +
  1.9143 +    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
  1.9144 +                        const unsigned int normalization_type=3,
  1.9145 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.9146 +      if (!dimw || !dimh) return assign();
  1.9147 +      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
  1.9148 +      min = max = 0;
  1.9149 +      cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
  1.9150 +      return paint();
  1.9151 +    }
  1.9152 +
  1.9153 +    template<typename T>
  1.9154 +    CImgDisplay& assign(const CImg<T>& img, const char *title=0,
  1.9155 +                        const unsigned int normalization_type=3,
  1.9156 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.9157 +      if (!img) return assign();
  1.9158 +      CImg<T> tmp;
  1.9159 +      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.9160 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.9161 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.9162 +      return display(nimg);
  1.9163 +    }
  1.9164 +
  1.9165 +    template<typename T>
  1.9166 +    CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
  1.9167 +                        const unsigned int normalization_type=3,
  1.9168 +                        const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.9169 +      if (!list) return assign();
  1.9170 +      CImg<T> tmp;
  1.9171 +      const CImg<T> img = list.get_append('x','p'),
  1.9172 +        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.9173 +      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
  1.9174 +      if (normalization==2) min = (float)nimg.minmax(max);
  1.9175 +      return display(nimg);
  1.9176 +    }
  1.9177 +
  1.9178 +    CImgDisplay& assign(const CImgDisplay &win) {
  1.9179 +      if (!win) return assign();
  1.9180 +      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
  1.9181 +      cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
  1.9182 +      return paint();
  1.9183 +    }
  1.9184 +
  1.9185 +    template<typename T>
  1.9186 +    CImgDisplay& display(const CImg<T>& img) {
  1.9187 +      if (is_empty()) assign(img.width,img.height);
  1.9188 +      return render(img).paint();
  1.9189 +    }
  1.9190 +
  1.9191 +    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
  1.9192 +      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
  1.9193 +      if (is_empty()) return assign(nwidth,nheight);
  1.9194 +      const unsigned int
  1.9195 +        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
  1.9196 +        tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
  1.9197 +        dimx = tmpdimx?tmpdimx:1,
  1.9198 +        dimy = tmpdimy?tmpdimy:1;
  1.9199 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9200 +
  1.9201 +      if ((window_width!=dimx || window_height!=dimy) &&
  1.9202 +          !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
  1.9203 +        throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
  1.9204 +
  1.9205 +      if (width!=dimx || height!=dimy) {
  1.9206 +        unsigned int *ndata = new unsigned int[dimx*dimy];
  1.9207 +        if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
  1.9208 +        else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
  1.9209 +        unsigned int const* old_data = data;
  1.9210 +        data = ndata;
  1.9211 +        delete[] old_data;
  1.9212 +        _CbReinitGraphics();
  1.9213 +      }
  1.9214 +      window_width = width = dimx; window_height = height = dimy;
  1.9215 +      is_resized = false;
  1.9216 +      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
  1.9217 +      if (redraw) return paint();
  1.9218 +      return *this;
  1.9219 +    }
  1.9220 +
  1.9221 +    CImgDisplay& move(const int posx, const int posy) {
  1.9222 +      if (is_empty()) return *this;
  1.9223 +      if (!is_fullscreen) {
  1.9224 +        // If the operation succeeds, window_x and window_y are updated by the event thread
  1.9225 +        cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9226 +        // Send the query
  1.9227 +        if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
  1.9228 +          throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
  1.9229 +      }
  1.9230 +      return show();
  1.9231 +    }
  1.9232 +
  1.9233 +    CImgDisplay& set_mouse(const int posx, const int posy) {
  1.9234 +      if (!is_closed && posx>=0 && posy>=0) {
  1.9235 +        // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
  1.9236 +        cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9237 +        // Send the query
  1.9238 +        if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
  1.9239 +          throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
  1.9240 +      }
  1.9241 +      return *this;
  1.9242 +    }
  1.9243 +
  1.9244 +    CImgDisplay& hide_mouse() {
  1.9245 +      if (is_empty()) return *this;
  1.9246 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9247 +      // Send the query
  1.9248 +      if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
  1.9249 +        throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
  1.9250 +      return *this;
  1.9251 +    }
  1.9252 +
  1.9253 +    CImgDisplay& show_mouse() {
  1.9254 +      if (is_empty()) return *this;
  1.9255 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9256 +      // Send the query
  1.9257 +      if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
  1.9258 +        throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
  1.9259 +      return *this;
  1.9260 +    }
  1.9261 +
  1.9262 +    static void wait_all() {
  1.9263 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9264 +      MPWaitOnSemaphore(c.wait_event,kDurationForever);
  1.9265 +    }
  1.9266 +
  1.9267 +    CImgDisplay& show() {
  1.9268 +      if (is_empty()) return *this;
  1.9269 +      if (is_closed) {
  1.9270 +        cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9271 +        if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
  1.9272 +          throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
  1.9273 +      }
  1.9274 +      return paint();
  1.9275 +    }
  1.9276 +
  1.9277 +    CImgDisplay& close() {
  1.9278 +      if (is_empty()) return *this;
  1.9279 +      if (!is_closed && !is_fullscreen) {
  1.9280 +        cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9281 +        // If the operation succeeds, window_x and window_y are updated on the event thread
  1.9282 +        if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
  1.9283 +          throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
  1.9284 +      }
  1.9285 +      return *this;
  1.9286 +    }
  1.9287 +
  1.9288 +    CImgDisplay& set_title(const char *format, ...) {
  1.9289 +      if (is_empty()) return *this;
  1.9290 +      char tmp[1024] = {0};
  1.9291 +      va_list ap;
  1.9292 +      va_start(ap, format);
  1.9293 +      cimg_std::vsprintf(tmp,format,ap);
  1.9294 +      va_end(ap);
  1.9295 +      if (title) delete[] title;
  1.9296 +      const int s = cimg::strlen(tmp)+1;
  1.9297 +      title = new char[s];
  1.9298 +      cimg_std::memcpy(title,tmp,s*sizeof(char));
  1.9299 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9300 +      if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
  1.9301 +        throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
  1.9302 +      return *this;
  1.9303 +    }
  1.9304 +
  1.9305 +    CImgDisplay& paint() {
  1.9306 +      if (!is_closed) {
  1.9307 +        MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
  1.9308 +        CGrafPtr portPtr = GetWindowPort(carbonWindow);
  1.9309 +        CGContextRef currentContext = 0;
  1.9310 +        QDBeginCGContext(portPtr,&currentContext);
  1.9311 +        CGContextSetRGBFillColor(currentContext,255,255,255,255);
  1.9312 +        CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
  1.9313 +        CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
  1.9314 +        CGContextFlush(currentContext);
  1.9315 +        QDEndCGContext(portPtr, &currentContext);
  1.9316 +        MPExitCriticalRegion(paintCriticalRegion);
  1.9317 +      }
  1.9318 +      return *this;
  1.9319 +    }
  1.9320 +
  1.9321 +    template<typename T>
  1.9322 +    CImgDisplay& render(const CImg<T>& img) {
  1.9323 +      if (is_empty()) return *this;
  1.9324 +      if (!img)
  1.9325 +        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
  1.9326 +                                    img.width,img.height,img.depth,img.dim,img.data);
  1.9327 +      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
  1.9328 +      const T
  1.9329 +        *data1 = img.data,
  1.9330 +        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
  1.9331 +        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
  1.9332 +      MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
  1.9333 +      unsigned int
  1.9334 +        *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
  1.9335 +        *ptrd = ndata;
  1.9336 +      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
  1.9337 +        min = max = 0;
  1.9338 +        for (unsigned int xy = img.width*img.height; xy>0; --xy)
  1.9339 +          *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
  1.9340 +      } else {
  1.9341 +        if (normalization==3) {
  1.9342 +          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
  1.9343 +          else {
  1.9344 +            min = (float)cimg::type<T>::min();
  1.9345 +            max = (float)cimg::type<T>::max();
  1.9346 +          }
  1.9347 +        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
  1.9348 +        const float delta = max-min, mm = delta?delta:1.0f;
  1.9349 +        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.9350 +          const unsigned char
  1.9351 +            R = (unsigned char)(255*(*(data1++)-min)/mm),
  1.9352 +            G = (unsigned char)(255*(*(data2++)-min)/mm),
  1.9353 +            B = (unsigned char)(255*(*(data3++)-min)/mm);
  1.9354 +          *(ptrd++) = (R<<16) | (G<<8) | (B);
  1.9355 +        }
  1.9356 +      }
  1.9357 +      if (ndata!=data) {
  1.9358 +        _render_resize(ndata,img.width,img.height,data,width,height);
  1.9359 +        delete[] ndata;
  1.9360 +      }
  1.9361 +      MPExitCriticalRegion(paintCriticalRegion);
  1.9362 +      return *this;
  1.9363 +    }
  1.9364 +
  1.9365 +    template<typename T>
  1.9366 +    const CImgDisplay& snapshot(CImg<T>& img) const {
  1.9367 +      if (is_empty()) img.assign();
  1.9368 +      else {
  1.9369 +        img.assign(width,height,1,3);
  1.9370 +        T
  1.9371 +          *data1 = img.ptr(0,0,0,0),
  1.9372 +          *data2 = img.ptr(0,0,0,1),
  1.9373 +          *data3 = img.ptr(0,0,0,2);
  1.9374 +        unsigned int *ptrs = data;
  1.9375 +        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
  1.9376 +          const unsigned int val = *(ptrs++);
  1.9377 +          *(data1++) = (unsigned char)(val>>16);
  1.9378 +          *(data2++) = (unsigned char)((val>>8)&0xFF);
  1.9379 +          *(data3++) = (unsigned char)(val&0xFF);
  1.9380 +        }
  1.9381 +      }
  1.9382 +      return *this;
  1.9383 +    }
  1.9384 +
  1.9385 +    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
  1.9386 +      if (is_empty()) return *this;
  1.9387 +      if (redraw) {
  1.9388 +        const unsigned int bufsize = width*height*4;
  1.9389 +        void *odata = cimg_std::malloc(bufsize);
  1.9390 +        cimg_std::memcpy(odata,data,bufsize);
  1.9391 +        assign(width,height,title,normalization,!is_fullscreen,false);
  1.9392 +        cimg_std::memcpy(data,odata,bufsize);
  1.9393 +        cimg_std::free(odata);
  1.9394 +        return paint();
  1.9395 +      }
  1.9396 +      return assign(width,height,title,normalization,!is_fullscreen,false);
  1.9397 +    }
  1.9398 +
  1.9399 +    static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
  1.9400 +      OSStatus result = eventNotHandledErr;
  1.9401 +      CImgDisplay* disp = (CImgDisplay*) userData;
  1.9402 +      (void)myHandler; // Avoid "unused parameter"
  1.9403 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9404 +      // Gets the associated display
  1.9405 +      if (disp) {
  1.9406 +        // Window events are always handled
  1.9407 +        if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
  1.9408 +        case kEventWindowClose :
  1.9409 +          disp->mouse_x = disp->mouse_y = -1;
  1.9410 +          disp->window_x = disp->window_y = 0;
  1.9411 +          if (disp->button) {
  1.9412 +            cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.9413 +            disp->button = 0;
  1.9414 +          }
  1.9415 +          if (disp->key) {
  1.9416 +            cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  1.9417 +            disp->key = 0;
  1.9418 +          }
  1.9419 +          if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  1.9420 +          disp->is_closed = true;
  1.9421 +          HideWindow(disp->carbonWindow);
  1.9422 +          disp->is_event = true;
  1.9423 +          MPSignalSemaphore(c.wait_event);
  1.9424 +          result = noErr;
  1.9425 +          break;
  1.9426 +          // There is a lot of case where we have to redraw our window
  1.9427 +        case kEventWindowBoundsChanging :
  1.9428 +        case kEventWindowResizeStarted :
  1.9429 +        case kEventWindowCollapsed : //Not sure it's really needed :-)
  1.9430 +          break;
  1.9431 +        case kEventWindowZoomed :
  1.9432 +        case kEventWindowExpanded :
  1.9433 +        case kEventWindowResizeCompleted : {
  1.9434 +          MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
  1.9435 +          // Now we retrieve the new size of the window
  1.9436 +          Rect newContentRect;
  1.9437 +          GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
  1.9438 +          const unsigned int
  1.9439 +            nw = (unsigned int)(newContentRect.right - newContentRect.left),
  1.9440 +            nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
  1.9441 +
  1.9442 +          // Then we update CImg internal settings
  1.9443 +          if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
  1.9444 +            disp->window_width = nw;
  1.9445 +            disp->window_height = nh;
  1.9446 +            disp->mouse_x = disp->mouse_y = -1;
  1.9447 +            disp->is_resized = true;
  1.9448 +          }
  1.9449 +          disp->is_event = true;
  1.9450 +          MPExitCriticalRegion(disp->paintCriticalRegion);
  1.9451 +          disp->paint(); // Coords changed, must update the screen
  1.9452 +          MPSignalSemaphore(c.wait_event);
  1.9453 +          result = noErr;
  1.9454 +        } break;
  1.9455 +        case kEventWindowDragStarted :
  1.9456 +        case kEventWindowDragCompleted : {
  1.9457 +          MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
  1.9458 +          // Now we retrieve the new size of the window
  1.9459 +          Rect newContentRect ;
  1.9460 +          GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
  1.9461 +          const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
  1.9462 +          // Then we update CImg internal settings
  1.9463 +          if (nx!=disp->window_x || ny!=disp->window_y) {
  1.9464 +            disp->window_x = nx;
  1.9465 +            disp->window_y = ny;
  1.9466 +            disp->is_moved = true;
  1.9467 +          }
  1.9468 +          disp->is_event = true;
  1.9469 +          MPExitCriticalRegion(disp->paintCriticalRegion);
  1.9470 +          disp->paint(); // Coords changed, must update the screen
  1.9471 +          MPSignalSemaphore(c.wait_event);
  1.9472 +          result = noErr;
  1.9473 +        } break;
  1.9474 +          case kEventWindowPaint :
  1.9475 +          disp->paint();
  1.9476 +          break;
  1.9477 +          }
  1.9478 +
  1.9479 +        switch (GetEventClass(theEvent)) {
  1.9480 +        case kEventClassKeyboard : {
  1.9481 +          if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
  1.9482 +            // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
  1.9483 +            UInt32 newModifiers;
  1.9484 +            if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
  1.9485 +              int newKeyCode = -1;
  1.9486 +              UInt32 changed = disp->lastKeyModifiers^newModifiers;
  1.9487 +              // Find what changed here
  1.9488 +              if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
  1.9489 +              if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
  1.9490 +
  1.9491 +              // On the Mac, the "option" key = the ALT key
  1.9492 +              if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
  1.9493 +              if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
  1.9494 +              if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
  1.9495 +              if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
  1.9496 +              if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
  1.9497 +              if (newKeyCode != -1) { // Simulate keystroke
  1.9498 +                if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  1.9499 +                disp->key = (int)newKeyCode;
  1.9500 +              }
  1.9501 +              disp->lastKeyModifiers = newModifiers; // Save current state
  1.9502 +            }
  1.9503 +            disp->is_event = true;
  1.9504 +            MPSignalSemaphore(c.wait_event);
  1.9505 +          }
  1.9506 +          if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
  1.9507 +            char keyCode;
  1.9508 +            if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
  1.9509 +              disp->update_iskey((unsigned int)keyCode,true);
  1.9510 +              if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
  1.9511 +              disp->key = (unsigned int)keyCode;
  1.9512 +              if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
  1.9513 +            }
  1.9514 +            disp->is_event = true;
  1.9515 +            MPSignalSemaphore(c.wait_event);
  1.9516 +          }
  1.9517 +        } break;
  1.9518 +
  1.9519 +        case kEventClassMouse :
  1.9520 +          switch (GetEventKind(theEvent)) {
  1.9521 +          case kEventMouseDragged :
  1.9522 +            //  When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
  1.9523 +            //  but a kEventMouseDragged one. So we merge them here.
  1.9524 +          case kEventMouseMoved :
  1.9525 +            HIPoint point;
  1.9526 +            if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
  1.9527 +              if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
  1.9528 +                disp->mouse_x = (int)point.x;
  1.9529 +                disp->mouse_y = (int)point.y;
  1.9530 +                if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
  1.9531 +                  disp->mouse_x = disp->mouse_y = -1;
  1.9532 +              } else disp->mouse_x = disp->mouse_y = -1;
  1.9533 +            }
  1.9534 +            disp->is_event = true;
  1.9535 +            MPSignalSemaphore(c.wait_event);
  1.9536 +            break;
  1.9537 +          case kEventMouseDown :
  1.9538 +            UInt16 btn;
  1.9539 +            if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
  1.9540 +              cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.9541 +              if (btn==kEventMouseButtonPrimary) disp->button|=1U;
  1.9542 +              // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
  1.9543 +              // to emulate a right click by using the Control key
  1.9544 +              if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
  1.9545 +                cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
  1.9546 +              if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
  1.9547 +              if (btn==kEventMouseButtonTertiary) disp->button|=4U;
  1.9548 +            }
  1.9549 +            disp->is_event = true;
  1.9550 +            MPSignalSemaphore(c.wait_event);
  1.9551 +            break;
  1.9552 +          case kEventMouseWheelMoved :
  1.9553 +            EventMouseWheelAxis wheelax;
  1.9554 +            SInt32 delta;
  1.9555 +            if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
  1.9556 +              if (wheelax==kEventMouseWheelAxisY) {
  1.9557 +                if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
  1.9558 +                  if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
  1.9559 +                disp->is_event = true;
  1.9560 +                MPSignalSemaphore(c.wait_event);
  1.9561 +              }
  1.9562 +            break;
  1.9563 +          }
  1.9564 +        }
  1.9565 +
  1.9566 +        switch (GetEventClass(theEvent)) {
  1.9567 +        case kEventClassKeyboard :
  1.9568 +          if (GetEventKind(theEvent)==kEventRawKeyUp) {
  1.9569 +            UInt32 keyCode;
  1.9570 +            if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
  1.9571 +              disp->update_iskey((unsigned int)keyCode,false);
  1.9572 +              if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
  1.9573 +              if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
  1.9574 +              disp->released_key = (int)keyCode;
  1.9575 +            }
  1.9576 +            disp->is_event = true;
  1.9577 +            MPSignalSemaphore(c.wait_event);
  1.9578 +          }
  1.9579 +          break;
  1.9580 +
  1.9581 +        case kEventClassMouse :
  1.9582 +          switch (GetEventKind(theEvent)) {
  1.9583 +          case kEventMouseUp :
  1.9584 +            UInt16 btn;
  1.9585 +            if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
  1.9586 +              cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
  1.9587 +              if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
  1.9588 +              // See note in kEventMouseDown handler.
  1.9589 +              if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
  1.9590 +                cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
  1.9591 +              if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
  1.9592 +              if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
  1.9593 +            }
  1.9594 +            disp->is_event = true;
  1.9595 +            MPSignalSemaphore(c.wait_event);
  1.9596 +            break;
  1.9597 +          }
  1.9598 +        }
  1.9599 +      }
  1.9600 +      return (result);
  1.9601 +    }
  1.9602 +
  1.9603 +    static void* _events_thread(void* args) {
  1.9604 +      (void)args;      // Make the compiler happy
  1.9605 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9606 +      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
  1.9607 +      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
  1.9608 +      MPSignalSemaphore(c.sync_event);  // Notify the caller that all goes fine
  1.9609 +      EventRef theEvent;
  1.9610 +      EventTargetRef theTarget;
  1.9611 +      OSStatus err;
  1.9612 +      CbSerializedQuery* query;
  1.9613 +      theTarget = GetEventDispatcherTarget();
  1.9614 +
  1.9615 +      // Enter in the main loop
  1.9616 +      while (true) {
  1.9617 +        pthread_testcancel(); /* Check if cancelation happens */
  1.9618 +        err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
  1.9619 +        if (err==noErr) { // Received a carbon event, so process it !
  1.9620 +          SendEventToEventTarget (theEvent, theTarget);
  1.9621 +          ReleaseEvent(theEvent);
  1.9622 +        } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
  1.9623 +          OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
  1.9624 +          if (r!=noErr) continue; //nothing in the queue or an error.., bye
  1.9625 +          // If we're here, we've something to do now.
  1.9626 +          if (query) {
  1.9627 +            switch (query->kind) {
  1.9628 +            case COM_SETMOUSEPOS : { // change the cursor position
  1.9629 +              query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
  1.9630 +                == kCGErrorSuccess;
  1.9631 +              if (query->success) {
  1.9632 +                query->sender->mouse_x = query->x;
  1.9633 +                query->sender->mouse_y = query->y;
  1.9634 +              } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
  1.9635 +            } break;
  1.9636 +            case COM_SETTITLE : { // change the title bar caption
  1.9637 +              CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
  1.9638 +              query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
  1.9639 +              if (!query->success)
  1.9640 +                cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
  1.9641 +              CFRelease(windowTitle);
  1.9642 +            } break;
  1.9643 +            case COM_RESIZEWINDOW : { // Resize a window
  1.9644 +              SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
  1.9645 +              // If the window has been resized successfully, update display informations
  1.9646 +              query->sender->window_width = query->x;
  1.9647 +              query->sender->window_height = query->y;
  1.9648 +              query->success = true;
  1.9649 +            } break;
  1.9650 +            case COM_MOVEWINDOW : { // Move a window
  1.9651 +              MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
  1.9652 +              query->sender->window_x = query->x;
  1.9653 +              query->sender->window_y = query->y;
  1.9654 +              query->sender->is_moved = false;
  1.9655 +              query->success = true;
  1.9656 +            } break;
  1.9657 +            case COM_SHOWMOUSE : { // Show the mouse
  1.9658 +              query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
  1.9659 +              if (!query->success)
  1.9660 +                cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
  1.9661 +            } break;
  1.9662 +            case COM_HIDEMOUSE : { // Hide the mouse
  1.9663 +              query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
  1.9664 +              if (!query->success)
  1.9665 +                cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
  1.9666 +            } break;
  1.9667 +            case COM_SHOWWINDOW : { // We've to show a window
  1.9668 +              ShowWindow(query->sender->carbonWindow);
  1.9669 +              query->success = true;
  1.9670 +              query->sender->is_closed = false;
  1.9671 +            } break;
  1.9672 +            case COM_HIDEWINDOW : { // We've to show a window
  1.9673 +              HideWindow(query->sender->carbonWindow);
  1.9674 +              query->sender->is_closed = true;
  1.9675 +              query->sender->window_x = query->sender->window_y = 0;
  1.9676 +              query->success = true;
  1.9677 +            } break;
  1.9678 +            case COM_RELEASEWINDOW : { // We have to release a given window handle
  1.9679 +              query->success = true;
  1.9680 +              CFRelease(query->sender->carbonWindow);
  1.9681 +            } break;
  1.9682 +            case COM_CREATEWINDOW : { // We have to create a window
  1.9683 +              query->success = true;
  1.9684 +              WindowAttributes  windowAttrs;
  1.9685 +              Rect              contentRect;
  1.9686 +              if (query->createFullScreenWindow) {
  1.9687 +                // To simulate a "true" full screen, we remove menus and close boxes
  1.9688 +                windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
  1.9689 +                // Define a full screen bound rect
  1.9690 +                SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
  1.9691 +              } else { // Set the window size
  1.9692 +                SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
  1.9693 +                // Use default attributes
  1.9694 +                windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
  1.9695 +              }
  1.9696 +              // Update window position
  1.9697 +              if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
  1.9698 +              else {
  1.9699 +                query->sender->window_x = contentRect.left;
  1.9700 +                query->sender->window_y = contentRect.top;
  1.9701 +              }
  1.9702 +              // Update window flags
  1.9703 +              query->sender->window_width = query->sender->width;
  1.9704 +              query->sender->window_height = query->sender->height;
  1.9705 +              query->sender->flush();
  1.9706 +              // Create the window
  1.9707 +              if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
  1.9708 +                query->success = false;
  1.9709 +                cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
  1.9710 +              }
  1.9711 +              // Send it to the foreground
  1.9712 +              if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
  1.9713 +              // Show it, if needed
  1.9714 +              if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
  1.9715 +
  1.9716 +              // Associate a valid event handler
  1.9717 +              EventTypeSpec eventList[] = {
  1.9718 +                { kEventClassWindow, kEventWindowClose },
  1.9719 +                { kEventClassWindow, kEventWindowResizeStarted },
  1.9720 +                { kEventClassWindow, kEventWindowResizeCompleted },
  1.9721 +                { kEventClassWindow, kEventWindowDragStarted},
  1.9722 +                { kEventClassWindow, kEventWindowDragCompleted },
  1.9723 +                { kEventClassWindow, kEventWindowPaint },
  1.9724 +                { kEventClassWindow, kEventWindowBoundsChanging },
  1.9725 +                { kEventClassWindow, kEventWindowCollapsed },
  1.9726 +                { kEventClassWindow, kEventWindowExpanded },
  1.9727 +                { kEventClassWindow, kEventWindowZoomed },
  1.9728 +                { kEventClassKeyboard, kEventRawKeyDown },
  1.9729 +                { kEventClassKeyboard, kEventRawKeyUp },
  1.9730 +                { kEventClassKeyboard, kEventRawKeyRepeat },
  1.9731 +                { kEventClassKeyboard, kEventRawKeyModifiersChanged },
  1.9732 +                { kEventClassMouse, kEventMouseMoved },
  1.9733 +                { kEventClassMouse, kEventMouseDown },
  1.9734 +                { kEventClassMouse, kEventMouseUp },
  1.9735 +                { kEventClassMouse, kEventMouseDragged }
  1.9736 +              };
  1.9737 +
  1.9738 +              // Set up the handler
  1.9739 +              if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
  1.9740 +                                            eventList,(void*)query->sender,0)!=noErr) {
  1.9741 +                query->success = false;
  1.9742 +                cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
  1.9743 +              }
  1.9744 +
  1.9745 +              // Paint
  1.9746 +              query->sender->paint();
  1.9747 +            } break;
  1.9748 +            default :
  1.9749 +              cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
  1.9750 +            }
  1.9751 +            // Signal that the message has been processed
  1.9752 +            MPSignalSemaphore(c.sync_event);
  1.9753 +          }
  1.9754 +        }
  1.9755 +      }
  1.9756 +      // If we are here, the application is now finished
  1.9757 +      pthread_exit(0);
  1.9758 +    }
  1.9759 +
  1.9760 +    CImgDisplay& assign() {
  1.9761 +      if (is_empty()) return *this;
  1.9762 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9763 +      // Destroy the window associated to the display
  1.9764 +      _CbFreeAttachedWindow(c);
  1.9765 +      // Don't destroy the background thread here.
  1.9766 +      // If you check whether _CbFreeAttachedWindow() returned true,
  1.9767 +      //   - saying that there were no window left on screen - and
  1.9768 +      //   you destroy the background thread here, ReceiveNextEvent won't
  1.9769 +      //   work anymore if you create a new window after. So the
  1.9770 +      //  background thread must be killed (pthread_cancel() + pthread_join())
  1.9771 +      //   only on the application shutdown.
  1.9772 +
  1.9773 +      // Finalize graphics
  1.9774 +      _CbFinalizeGraphics();
  1.9775 +
  1.9776 +      // Do some cleanup
  1.9777 +      if (data) delete[] data;
  1.9778 +      if (title) delete[] title;
  1.9779 +      width = height = normalization = window_width = window_height = 0;
  1.9780 +      window_x = window_y = 0;
  1.9781 +      is_fullscreen = false;
  1.9782 +      is_closed = true;
  1.9783 +      min = max = 0;
  1.9784 +      title = 0;
  1.9785 +      flush();
  1.9786 +      if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
  1.9787 +        throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
  1.9788 +      return *this;
  1.9789 +    }
  1.9790 +
  1.9791 +    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
  1.9792 +                         const unsigned int normalization_type=3,
  1.9793 +                         const bool fullscreen_flag=false, const bool closed_flag=false) {
  1.9794 +      cimg::CarbonInfo& c = cimg::CarbonAttr();
  1.9795 +
  1.9796 +      // Allocate space for window title
  1.9797 +      const int s = cimg::strlen(ptitle)+1;
  1.9798 +      char *tmp_title = s?new char[s]:0;
  1.9799 +      if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
  1.9800 +
  1.9801 +      // Destroy previous window if existing
  1.9802 +      if (!is_empty()) assign();
  1.9803 +
  1.9804 +      // Set display variables
  1.9805 +      width = cimg::min(dimw,(unsigned int)screen_dimx());
  1.9806 +      height = cimg::min(dimh,(unsigned int)screen_dimy());
  1.9807 +      normalization = normalization_type<4?normalization_type:3;
  1.9808 +      is_fullscreen = fullscreen_flag;
  1.9809 +      is_closed = closed_flag;
  1.9810 +      lastKeyModifiers = 0;
  1.9811 +      title = tmp_title;
  1.9812 +      flush();
  1.9813 +
  1.9814 +      // Create the paint CR
  1.9815 +      if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
  1.9816 +        throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
  1.9817 +
  1.9818 +      // Create the thread if it's not already created
  1.9819 +      if (c.event_thread==0) {
  1.9820 +        // Background thread does not exists, so create it !
  1.9821 +        if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
  1.9822 +          throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
  1.9823 +        // Wait for thread initialization
  1.9824 +        MPWaitOnSemaphore(c.sync_event, kDurationForever);
  1.9825 +      }
  1.9826 +
  1.9827 +      // Init disp. graphics
  1.9828 +      data = new unsigned int[width*height];
  1.9829 +      _CbInitializeGraphics();
  1.9830 +
  1.9831 +      // Now ask the thread to create the window
  1.9832 +      _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
  1.9833 +      return *this;
  1.9834 +    }
  1.9835 +
  1.9836 +#endif
  1.9837 +
  1.9838 +  };
  1.9839 +
  1.9840 +  /*
  1.9841 +   #--------------------------------------
  1.9842 +   #
  1.9843 +   #
  1.9844 +   #
  1.9845 +   # Definition of the CImg<T> structure
  1.9846 +   #
  1.9847 +   #
  1.9848 +   #
  1.9849 +   #--------------------------------------
  1.9850 +   */
  1.9851 +
  1.9852 +  //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
  1.9853 +  /**
  1.9854 +     This is the main class of the %CImg Library. It declares and constructs
  1.9855 +     an image, allows access to its pixel values, and is able to perform various image operations.
  1.9856 +
  1.9857 +     \par Image representation
  1.9858 +
  1.9859 +     A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
  1.9860 +     each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
  1.9861 +     and number of channels.
  1.9862 +     Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
  1.9863 +     is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
  1.9864 +     If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
  1.9865 +
  1.9866 +     Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
  1.9867 +     as well as images with less dimensions (1D scalar signal, 2D color images, ...).
  1.9868 +     Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
  1.9869 +
  1.9870 +     Concerning the pixel value type \c T :
  1.9871 +     fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
  1.9872 +     unsigned long, long, float, double, ... </tt>.
  1.9873 +     Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
  1.9874 +     while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
  1.9875 +     images that have floating-point pixel values. The default value for the template T is \c float.
  1.9876 +     Using your own template types may be possible. However, you will certainly have to define the complete set
  1.9877 +     of arithmetic and logical operators for your class.
  1.9878 +
  1.9879 +     \par Image structure
  1.9880 +
  1.9881 +     The \ref CImg<\c T> structure contains \a six fields :
  1.9882 +     - \ref width defines the number of \a columns of the image (size along the X-axis).
  1.9883 +     - \ref height defines the number of \a rows of the image (size along the Y-axis).
  1.9884 +     - \ref depth defines the number of \a slices of the image (size along the Z-axis).
  1.9885 +     - \ref dim defines the number of \a channels of the image (size along the V-axis).
  1.9886 +     - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
  1.9887 +     - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
  1.9888 +       another image.
  1.9889 +
  1.9890 +     You can access these fields publicly although it is recommended to use the dedicated functions
  1.9891 +     dimx(), dimy(), dimz(), dimv() and ptr() to do so.
  1.9892 +     Image dimensions are not limited to a specific range (as long as you got enough available memory).
  1.9893 +     A value of \e 1 usually means that the corresponding dimension is \a flat.
  1.9894 +     If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
  1.9895 +     Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
  1.9896 +     (a CImgInstanceException will be thrown instead).
  1.9897 +     Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).
  1.9898 +
  1.9899 +     \par Image declaration and construction
  1.9900 +
  1.9901 +     Declaring an image can be done by using one of the several available constructors.
  1.9902 +     Here is a list of the most used :
  1.9903 +
  1.9904 +     - Construct images from arbitrary dimensions :
  1.9905 +         - <tt>CImg<char> img;</tt> declares an empty image.
  1.9906 +         - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
  1.9907 +         \c unsigned \c char pixel values.
  1.9908 +         - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
  1.9909 +         - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
  1.9910 +         (colors are stored as an image with three channels).
  1.9911 +         - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
  1.9912 +         (with \c double pixel values).
  1.9913 +         - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
  1.9914 +         (with \c float pixels, which is the default value of the template parameter \c T).
  1.9915 +         - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to
  1.9916 +         do it, or use the specific constructor taking 5 parameters like this :
  1.9917 +         <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.
  1.9918 +
  1.9919 +     - Construct images from filenames :
  1.9920 +         - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
  1.9921 +         - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
  1.9922 +         - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
  1.9923 +         to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
  1.9924 +
  1.9925 +     - Construct images from C-style arrays :
  1.9926 +         - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
  1.9927 +         \c data_buffer (of size 256x256=65536).
  1.9928 +         - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
  1.9929 +         from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
  1.9930 +         - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
  1.9931 +         from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).
  1.9932 +
  1.9933 +         The complete list of constructors can be found <a href="#constructors">here</a>.
  1.9934 +
  1.9935 +     \par Most useful functions
  1.9936 +
  1.9937 +     The \ref CImg<\c T> class contains a lot of functions that operates on images.
  1.9938 +     Some of the most useful are :
  1.9939 +
  1.9940 +     - operator()(), operator[]() : allows to access or write pixel values.
  1.9941 +     - display() : displays the image in a new window.
  1.9942 +  **/
  1.9943 +  template<typename T>
  1.9944 +  struct CImg {
  1.9945 +
  1.9946 +    //! Variable representing the width of the instance image (i.e. dimensions along the X-axis).
  1.9947 +    /**
  1.9948 +       \remark
  1.9949 +       - Prefer using the function CImg<T>::dimx() to get information about the width of an image.
  1.9950 +       - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably
  1.9951 +       result in a library crash.
  1.9952 +       - Empty images have \c width defined to \c 0.
  1.9953 +    **/
  1.9954 +    unsigned int width;
  1.9955 +
  1.9956 +    //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis).
  1.9957 +    /**
  1.9958 +       \remark
  1.9959 +       - Prefer using the function CImg<T>::dimy() to get information about the height of an image.
  1.9960 +       - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably
  1.9961 +       result in a library crash.
  1.9962 +       - 1D signals have \c height defined to \c 1.
  1.9963 +       - Empty images have \c height defined to \c 0.
  1.9964 +    **/
  1.9965 +    unsigned int height;
  1.9966 +
  1.9967 +    //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
  1.9968 +    /**
  1.9969 +       \remark
  1.9970 +       - Prefer using the function CImg<T>::dimz() to get information about the depth of an image.
  1.9971 +       - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably
  1.9972 +       result in a library crash.
  1.9973 +       - Classical 2D images have \c depth defined to \c 1.
  1.9974 +       - Empty images have \c depth defined to \c 0.
  1.9975 +    **/
  1.9976 +    unsigned int depth;
  1.9977 +
  1.9978 +    //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis).
  1.9979 +    /**
  1.9980 +       \remark
  1.9981 +       - Prefer using the function CImg<T>::dimv() to get information about the depth of an image.
  1.9982 +       - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably
  1.9983 +       result in a library crash.
  1.9984 +       - Scalar-valued images (one value per pixel) have \c dim defined to \c 1.
  1.9985 +       - Empty images have \c depth defined to \c 0.
  1.9986 +    **/
  1.9987 +    unsigned int dim;
  1.9988 +
  1.9989 +    //! Variable telling if pixel buffer of the instance image is shared with another one.
  1.9990 +    bool is_shared;
  1.9991 +
  1.9992 +    //! Pointer to the first pixel of the pixel buffer.
  1.9993 +    T *data;
  1.9994 +
  1.9995 +    //! Iterator type for CImg<T>.
  1.9996 +    /**
  1.9997 +       \remark
  1.9998 +       - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer).
  1.9999 +       - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
 1.10000 +    **/
 1.10001 +    typedef T* iterator;
 1.10002 +
 1.10003 +    //! Const iterator type for CImg<T>.
 1.10004 +    /**
 1.10005 +       \remark
 1.10006 +       - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer).
 1.10007 +       - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
 1.10008 +    **/
 1.10009 +    typedef const T* const_iterator;
 1.10010 +
 1.10011 +    //! Get value type
 1.10012 +    typedef T value_type;
 1.10013 +
 1.10014 +    // Define common T-dependant types.
 1.10015 +    typedef typename cimg::superset<T,bool>::type Tbool;
 1.10016 +    typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 1.10017 +    typedef typename cimg::superset<T,char>::type Tchar;
 1.10018 +    typedef typename cimg::superset<T,unsigned short>::type Tushort;
 1.10019 +    typedef typename cimg::superset<T,short>::type Tshort;
 1.10020 +    typedef typename cimg::superset<T,unsigned int>::type Tuint;
 1.10021 +    typedef typename cimg::superset<T,int>::type Tint;
 1.10022 +    typedef typename cimg::superset<T,unsigned long>::type Tulong;
 1.10023 +    typedef typename cimg::superset<T,long>::type Tlong;
 1.10024 +    typedef typename cimg::superset<T,float>::type Tfloat;
 1.10025 +    typedef typename cimg::superset<T,double>::type Tdouble;
 1.10026 +    typedef typename cimg::last<T,bool>::type boolT;
 1.10027 +    typedef typename cimg::last<T,unsigned char>::type ucharT;
 1.10028 +    typedef typename cimg::last<T,char>::type charT;
 1.10029 +    typedef typename cimg::last<T,unsigned short>::type ushortT;
 1.10030 +    typedef typename cimg::last<T,short>::type shortT;
 1.10031 +    typedef typename cimg::last<T,unsigned int>::type uintT;
 1.10032 +    typedef typename cimg::last<T,int>::type intT;
 1.10033 +    typedef typename cimg::last<T,unsigned long>::type ulongT;
 1.10034 +    typedef typename cimg::last<T,long>::type longT;
 1.10035 +    typedef typename cimg::last<T,float>::type floatT;
 1.10036 +    typedef typename cimg::last<T,double>::type doubleT;
 1.10037 +
 1.10038 +    //@}
 1.10039 +    //---------------------------
 1.10040 +    //
 1.10041 +    //! \name Plugins
 1.10042 +    //@{
 1.10043 +    //---------------------------
 1.10044 +#ifdef cimg_plugin
 1.10045 +#include cimg_plugin
 1.10046 +#endif
 1.10047 +#ifdef cimg_plugin1
 1.10048 +#include cimg_plugin1
 1.10049 +#endif
 1.10050 +#ifdef cimg_plugin2
 1.10051 +#include cimg_plugin2
 1.10052 +#endif
 1.10053 +#ifdef cimg_plugin3
 1.10054 +#include cimg_plugin3
 1.10055 +#endif
 1.10056 +#ifdef cimg_plugin4
 1.10057 +#include cimg_plugin4
 1.10058 +#endif
 1.10059 +#ifdef cimg_plugin5
 1.10060 +#include cimg_plugin5
 1.10061 +#endif
 1.10062 +#ifdef cimg_plugin6
 1.10063 +#include cimg_plugin6
 1.10064 +#endif
 1.10065 +#ifdef cimg_plugin7
 1.10066 +#include cimg_plugin7
 1.10067 +#endif
 1.10068 +#ifdef cimg_plugin8
 1.10069 +#include cimg_plugin8
 1.10070 +#endif
 1.10071 +#ifndef cimg_plugin_greycstoration
 1.10072 +#define cimg_plugin_greycstoration_count
 1.10073 +#endif
 1.10074 +#ifndef cimg_plugin_greycstoration_lock
 1.10075 +#define cimg_plugin_greycstoration_lock
 1.10076 +#endif
 1.10077 +#ifndef cimg_plugin_greycstoration_unlock
 1.10078 +#define cimg_plugin_greycstoration_unlock
 1.10079 +#endif
 1.10080 +
 1.10081 +    //@}
 1.10082 +
 1.10083 +    //--------------------------------------
 1.10084 +    //
 1.10085 +    //! \name Constructors-Destructor-Copy
 1.10086 +    //@{
 1.10087 +    //--------------------------------------
 1.10088 +
 1.10089 +    //! Destructor.
 1.10090 +    /**
 1.10091 +       The destructor destroys the instance image.
 1.10092 +       \remark
 1.10093 +       - Destructing an empty or shared image does nothing.
 1.10094 +       - Otherwise, all memory used to store the pixel data of the instance image is freed.
 1.10095 +       - When destroying a non-shared image, be sure that every shared instances of the same image are
 1.10096 +       also destroyed to avoid further access to desallocated memory buffers.
 1.10097 +    **/
 1.10098 +    ~CImg() {
 1.10099 +      if (data && !is_shared) delete[] data;
 1.10100 +    }
 1.10101 +
 1.10102 +    //! Default constructor.
 1.10103 +    /**
 1.10104 +       The default constructor creates an empty instance image.
 1.10105 +       \remark
 1.10106 +       - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
 1.10107 +       set to 0 as well as its pointer to the pixel buffer \ref data.
 1.10108 +       - An empty image is non-shared.
 1.10109 +    **/
 1.10110 +    CImg():
 1.10111 +      width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
 1.10112 +
 1.10113 +    //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
 1.10114 +    /**
 1.10115 +       This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
 1.10116 +       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 1.10117 +       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 1.10118 +       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 1.10119 +       \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
 1.10120 +       \remark
 1.10121 +       - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
 1.10122 +       and all has its dimensions set to 0. No memory for pixel data is then allocated.
 1.10123 +       - This constructor creates only non-shared images.
 1.10124 +       - Image pixels allocated by this constructor are \b not \b initialized.
 1.10125 +       Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
 1.10126 +       to get an image of desired size with pixels set to a particular value.
 1.10127 +    **/
 1.10128 +    explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
 1.10129 +      is_shared(false) {
 1.10130 +      const unsigned long siz = dx*dy*dz*dv;
 1.10131 +      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
 1.10132 +      else { width = height = depth = dim = 0; data = 0; }
 1.10133 +    }
 1.10134 +
 1.10135 +    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
 1.10136 +    /**
 1.10137 +       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
 1.10138 +       values of the created instance image to \p val.
 1.10139 +       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 1.10140 +       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 1.10141 +       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 1.10142 +       \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 1.10143 +       \param val Default value for image pixels.
 1.10144 +       \remark
 1.10145 +       - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
 1.10146 +    **/
 1.10147 +    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
 1.10148 +      is_shared(false) {
 1.10149 +      const unsigned long siz = dx*dy*dz*dv;
 1.10150 +      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
 1.10151 +      else { width = height = depth = dim = 0; data = 0; }
 1.10152 +    }
 1.10153 +
 1.10154 +    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
 1.10155 +    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 1.10156 +         const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10157 +#define _CImg_stdarg(img,a0,a1,N,t) { \
 1.10158 +        unsigned int _siz = (unsigned int)N; \
 1.10159 +        if (_siz--) { \
 1.10160 +          va_list ap; \
 1.10161 +          va_start(ap,a1); \
 1.10162 +          T *ptrd = (img).data; \
 1.10163 +          *(ptrd++) = (T)a0; \
 1.10164 +          if (_siz--) { \
 1.10165 +            *(ptrd++) = (T)a1; \
 1.10166 +            for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
 1.10167 +          } \
 1.10168 +          va_end(ap); \
 1.10169 +        }}
 1.10170 +      assign(dx,dy,dz,dv);
 1.10171 +      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 1.10172 +    }
 1.10173 +
 1.10174 +    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
 1.10175 +    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 1.10176 +         const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10177 +      assign(dx,dy,dz,dv);
 1.10178 +      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 1.10179 +    }
 1.10180 +
 1.10181 +    //! Construct an image with given size and with specified values given in a string.
 1.10182 +    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 1.10183 +         const char *const values, const bool repeat_pattern):is_shared(false) {
 1.10184 +      const unsigned long siz = dx*dy*dz*dv;
 1.10185 +      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
 1.10186 +      else { width = height = depth = dim = 0; data = 0; }
 1.10187 +    }
 1.10188 +
 1.10189 +    //! Construct an image from a raw memory buffer.
 1.10190 +    /**
 1.10191 +       This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
 1.10192 +       copying data values from the input raw pixel buffer \p data_buffer.
 1.10193 +    **/
 1.10194 +    template<typename t>
 1.10195 +    CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 1.10196 +         const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
 1.10197 +      if (shared)
 1.10198 +        throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
 1.10199 +                                    "(different pixel types).",
 1.10200 +                                    pixel_type(),CImg<t>::pixel_type());
 1.10201 +      const unsigned long siz = dx*dy*dz*dv;
 1.10202 +      if (data_buffer && siz) {
 1.10203 +        width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
 1.10204 +        const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 1.10205 +      } else { width = height = depth = dim = 0; data = 0; }
 1.10206 +    }
 1.10207 +
 1.10208 +#ifndef cimg_use_visualcpp6
 1.10209 +    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 1.10210 +         const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
 1.10211 +#else
 1.10212 +    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 1.10213 +         const unsigned int dz, const unsigned int dv, const bool shared)
 1.10214 +#endif
 1.10215 +    {
 1.10216 +      const unsigned long siz = dx*dy*dz*dv;
 1.10217 +      if (data_buffer && siz) {
 1.10218 +        width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
 1.10219 +        if (is_shared) data = const_cast<T*>(data_buffer);
 1.10220 +        else { data = new T[siz]; cimg_std::memcpy(data,data_buffer,siz*sizeof(T)); }
 1.10221 +      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 1.10222 +    }
 1.10223 +
 1.10224 +   //! Default copy constructor.
 1.10225 +    /**
 1.10226 +       The default copy constructor creates a new instance image having same dimensions
 1.10227 +       (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
 1.10228 +       \param img The input image to copy.
 1.10229 +       \remark
 1.10230 +       - If the input image \p img is non-shared or have a different template type \p t != \p T,
 1.10231 +       the default copy constructor allocates a new pixel buffer and copy the pixel data
 1.10232 +       of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different
 1.10233 +       and the resulting instance image is non-shared.
 1.10234 +       - If the input image \p img is shared and has the same template type \p t == \p T,
 1.10235 +       the default copy constructor does not allocate a new pixel buffer and the resulting instance image
 1.10236 +       shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies
 1.10237 +       the created instance image.
 1.10238 +       - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
 1.10239 +       type \p t to type \p T.
 1.10240 +       - Copying an image having the same template type \p t == \p T is significantly faster.
 1.10241 +    **/
 1.10242 +    template<typename t>
 1.10243 +    CImg(const CImg<t>& img):is_shared(false) {
 1.10244 +      const unsigned int siz = img.size();
 1.10245 +      if (img.data && siz) {
 1.10246 +        width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
 1.10247 +        const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 1.10248 +      } else { width = height = depth = dim = 0; data = 0; }
 1.10249 +    }
 1.10250 +
 1.10251 +    CImg(const CImg<T>& img) {
 1.10252 +      const unsigned int siz = img.size();
 1.10253 +      if (img.data && siz) {
 1.10254 +        width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
 1.10255 +        if (is_shared) data = const_cast<T*>(img.data);
 1.10256 +        else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
 1.10257 +      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 1.10258 +    }
 1.10259 +
 1.10260 +   //! Advanced copy constructor.
 1.10261 +    /**
 1.10262 +       The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
 1.10263 +       \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
 1.10264 +       But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter
 1.10265 +       \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false).
 1.10266 +       \param img The input image to copy.
 1.10267 +       \param shared Boolean flag that decides if the copy is shared on non-shared.
 1.10268 +       \remark
 1.10269 +       - 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.
 1.10270 +       - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
 1.10271 +       - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
 1.10272 +       image is the same as the one used by the input image \p img.
 1.10273 +    **/
 1.10274 +    template<typename t>
 1.10275 +    CImg(const CImg<t>& img, const bool shared):is_shared(false) {
 1.10276 +      if (shared)
 1.10277 +        throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
 1.10278 +                                    "(different pixel types).",
 1.10279 +                                    pixel_type(),CImg<t>::pixel_type());
 1.10280 +      const unsigned int siz = img.size();
 1.10281 +      if (img.data && siz) {
 1.10282 +        width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
 1.10283 +        const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 1.10284 +      } else { width = height = depth = dim = 0; data = 0; }
 1.10285 +    }
 1.10286 +
 1.10287 +    CImg(const CImg<T>& img, const bool shared) {
 1.10288 +      const unsigned int siz = img.size();
 1.10289 +      if (img.data && siz) {
 1.10290 +        width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
 1.10291 +        if (is_shared) data = const_cast<T*>(img.data);
 1.10292 +        else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
 1.10293 +      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 1.10294 +    }
 1.10295 +
 1.10296 +    //! Construct an image using dimensions of another image
 1.10297 +    template<typename t>
 1.10298 +    CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10299 +      assign(img,dimensions);
 1.10300 +    }
 1.10301 +
 1.10302 +    //! Construct an image using dimensions of another image, and fill it with a default value
 1.10303 +    template<typename t>
 1.10304 +    CImg(const CImg<t>& img, const char *const dimensions, const T val):
 1.10305 +      width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10306 +      assign(img,dimensions).fill(val);
 1.10307 +    }
 1.10308 +
 1.10309 +   //! Construct an image from an image file.
 1.10310 +    /**
 1.10311 +       This constructor creates an instance image by reading it from a file.
 1.10312 +       \param filename Filename of the image file.
 1.10313 +       \remark
 1.10314 +       - The image format is deduced from the filename only by looking for the filename extension i.e. without
 1.10315 +       analyzing the file itself.
 1.10316 +       - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
 1.10317 +       More informations on this topic can be found in cimg_files_io.
 1.10318 +       - If the filename is not found, a CImgIOException is thrown by this constructor.
 1.10319 +    **/
 1.10320 +    CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10321 +      assign(filename);
 1.10322 +    }
 1.10323 +
 1.10324 +    //! Construct an image from the content of a CImgDisplay instance.
 1.10325 +    CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 1.10326 +      disp.snapshot(*this);
 1.10327 +    }
 1.10328 +
 1.10329 +    //! In-place version of the default constructor/destructor.
 1.10330 +    /**
 1.10331 +       This function replaces the instance image by an empty image.
 1.10332 +       \remark
 1.10333 +       - Memory used by the previous content of the instance image is freed if necessary.
 1.10334 +       - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
 1.10335 +       - This function is useful to free memory used by an image that is not of use, but which
 1.10336 +       has been created in the current code scope (i.e. not destroyed yet).
 1.10337 +    **/
 1.10338 +    CImg<T>& assign() {
 1.10339 +      if (data && !is_shared) delete[] data;
 1.10340 +      width = height = depth = dim = 0; is_shared = false; data = 0;
 1.10341 +      return *this;
 1.10342 +    }
 1.10343 +
 1.10344 +    //! In-place version of the default constructor.
 1.10345 +    /**
 1.10346 +       This function is strictly equivalent to \ref assign() and has been
 1.10347 +       introduced for having a STL-compliant function name.
 1.10348 +    **/
 1.10349 +    CImg<T>& clear() {
 1.10350 +      return assign();
 1.10351 +    }
 1.10352 +
 1.10353 +    //! In-place version of the previous constructor.
 1.10354 +    /**
 1.10355 +       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.
 1.10356 +       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 1.10357 +       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 1.10358 +       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 1.10359 +       \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 1.10360 +       - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty
 1.10361 +       and all has its dimensions set to 0. No memory for pixel data is then allocated.
 1.10362 +       - Memory buffer used to store previous pixel values is freed if necessary.
 1.10363 +       - If the instance image is shared, this constructor actually does nothing more than verifying
 1.10364 +       that new and old image dimensions fit.
 1.10365 +       - Image pixels allocated by this function are \b not \b initialized.
 1.10366 +       Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
 1.10367 +       to assign an image of desired size with pixels set to a particular value.
 1.10368 +    **/
 1.10369 +    CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
 1.10370 +      const unsigned long siz = dx*dy*dz*dv;
 1.10371 +      if (!siz) return assign();
 1.10372 +      const unsigned long curr_siz = size();
 1.10373 +      if (siz!=curr_siz) {
 1.10374 +        if (is_shared)
 1.10375 +          throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
 1.10376 +                                      pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
 1.10377 +        else { if (data) delete[] data; data = new T[siz]; }
 1.10378 +      }
 1.10379 +      width = dx; height = dy; depth = dz; dim = dv;
 1.10380 +      return *this;
 1.10381 +    }
 1.10382 +
 1.10383 +    //! In-place version of the previous constructor.
 1.10384 +    /**
 1.10385 +       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
 1.10386 +       and sets all pixel values of the instance image to \p val.
 1.10387 +       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 1.10388 +       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 1.10389 +       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 1.10390 +       \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 1.10391 +       \param val Default value for image pixels.
 1.10392 +       \remark
 1.10393 +       - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
 1.10394 +    **/
 1.10395 +    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
 1.10396 +      return assign(dx,dy,dz,dv).fill(val);
 1.10397 +    }
 1.10398 +
 1.10399 +    //! In-place version of the previous constructor.
 1.10400 +    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 1.10401 +                    const int val0, const int val1, ...) {
 1.10402 +      assign(dx,dy,dz,dv);
 1.10403 +      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 1.10404 +      return *this;
 1.10405 +    }
 1.10406 +
 1.10407 +    //! In-place version of the previous constructor.
 1.10408 +    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 1.10409 +                    const double val0, const double val1, ...) {
 1.10410 +      assign(dx,dy,dz,dv);
 1.10411 +      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 1.10412 +      return *this;
 1.10413 +    }
 1.10414 +
 1.10415 +    //! In-place version of the previous constructor.
 1.10416 +    template<typename t>
 1.10417 +    CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 1.10418 +                    const unsigned int dz=1, const unsigned int dv=1) {
 1.10419 +      const unsigned long siz = dx*dy*dz*dv;
 1.10420 +      if (!data_buffer || !siz) return assign();
 1.10421 +      assign(dx,dy,dz,dv);
 1.10422 +      const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 1.10423 +      return *this;
 1.10424 +    }
 1.10425 +
 1.10426 +#ifndef cimg_use_visualcpp6
 1.10427 +    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 1.10428 +                    const unsigned int dz=1, const unsigned int dv=1)
 1.10429 +#else
 1.10430 +    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 1.10431 +                    const unsigned int dz, const unsigned int dv)
 1.10432 +#endif
 1.10433 +    {
 1.10434 +      const unsigned long siz = dx*dy*dz*dv;
 1.10435 +      if (!data_buffer || !siz) return assign();
 1.10436 +      const unsigned long curr_siz = size();
 1.10437 +      if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
 1.10438 +      if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
 1.10439 +        assign(dx,dy,dz,dv);
 1.10440 +        if (is_shared) cimg_std::memmove(data,data_buffer,siz*sizeof(T));
 1.10441 +        else cimg_std::memcpy(data,data_buffer,siz*sizeof(T));
 1.10442 +      } else {
 1.10443 +        T *new_data = new T[siz];
 1.10444 +        cimg_std::memcpy(new_data,data_buffer,siz*sizeof(T));
 1.10445 +        delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
 1.10446 +      }
 1.10447 +      return *this;
 1.10448 +    }
 1.10449 +
 1.10450 +    //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
 1.10451 +    template<typename t>
 1.10452 +    CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
 1.10453 +                    const unsigned int dz, const unsigned int dv, const bool shared) {
 1.10454 +      if (shared)
 1.10455 +        throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
 1.10456 +                                    "(different pixel types).",
 1.10457 +                                    pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
 1.10458 +      return assign(data_buffer,dx,dy,dz,dv);
 1.10459 +    }
 1.10460 +
 1.10461 +    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 1.10462 +                    const unsigned int dz, const unsigned int dv, const bool shared) {
 1.10463 +      const unsigned long siz = dx*dy*dz*dv;
 1.10464 +      if (!data_buffer || !siz) return assign();
 1.10465 +      if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
 1.10466 +      else {
 1.10467 +        if (!is_shared) {
 1.10468 +          if (data_buffer+siz<data || data_buffer>=data+size()) assign();
 1.10469 +          else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
 1.10470 +                          pixel_type());
 1.10471 +        }
 1.10472 +        width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
 1.10473 +        data = const_cast<T*>(data_buffer);
 1.10474 +      }
 1.10475 +      return *this;
 1.10476 +    }
 1.10477 +
 1.10478 +    //! In-place version of the default copy constructor.
 1.10479 +    /**
 1.10480 +       This function assigns a copy of the input image \p img to the current instance image.
 1.10481 +       \param img The input image to copy.
 1.10482 +       \remark
 1.10483 +       - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
 1.10484 +       becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
 1.10485 +       - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
 1.10486 +       of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
 1.10487 +    **/
 1.10488 +    template<typename t>
 1.10489 +    CImg<T>& assign(const CImg<t>& img) {
 1.10490 +      return assign(img.data,img.width,img.height,img.depth,img.dim);
 1.10491 +    }
 1.10492 +
 1.10493 +    //! In-place version of the advanced constructor.
 1.10494 +    /**
 1.10495 +       This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
 1.10496 +       current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
 1.10497 +       or non-shared (if the input parameter \p shared is set to \c false).
 1.10498 +       \param img The input image to copy.
 1.10499 +       \param shared Boolean flag that decides if the copy is shared or non-shared.
 1.10500 +       \remark
 1.10501 +       - 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.
 1.10502 +       - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
 1.10503 +       - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
 1.10504 +       image is the same as the one used by the input image \p img.
 1.10505 +    **/
 1.10506 +    template<typename t>
 1.10507 +    CImg<T>& assign(const CImg<t>& img, const bool shared) {
 1.10508 +      return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
 1.10509 +    }
 1.10510 +
 1.10511 +    //! In-place version of the previous constructor.
 1.10512 +    template<typename t>
 1.10513 +    CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
 1.10514 +      if (dimensions) {
 1.10515 +        unsigned int siz[4] = { 0,1,1,1 };
 1.10516 +        const char *s = dimensions;
 1.10517 +        char tmp[256] = { 0 }, c = 0;
 1.10518 +        int val = 0;
 1.10519 +        for (unsigned int k=0; k<4; ++k) {
 1.10520 +          const int err = cimg_std::sscanf(s,"%[-0-9]%c",tmp,&c);
 1.10521 +          if (err>=1) {
 1.10522 +            const int err = cimg_std::sscanf(s,"%d",&val);
 1.10523 +            if (err==1) {
 1.10524 +              int val2 = val<0?-val:(c=='%'?val:-1);
 1.10525 +              if (val2>=0) {
 1.10526 +                val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
 1.10527 +                if (c!='%' && !val) val = 1;
 1.10528 +              }
 1.10529 +              siz[k] = val;
 1.10530 +            }
 1.10531 +            s+=cimg::strlen(tmp);
 1.10532 +            if (c=='%') ++s;
 1.10533 +          }
 1.10534 +          if (!err) {
 1.10535 +            if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
 1.10536 +            else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
 1.10537 +            else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
 1.10538 +            else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
 1.10539 +            else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
 1.10540 +            else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
 1.10541 +            else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
 1.10542 +            else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
 1.10543 +            else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
 1.10544 +            else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
 1.10545 +            else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
 1.10546 +            else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
 1.10547 +            else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
 1.10548 +            else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
 1.10549 +            else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
 1.10550 +            else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
 1.10551 +            else { ++s; --k; }
 1.10552 +          }
 1.10553 +        }
 1.10554 +        return assign(siz[0],siz[1],siz[2],siz[3]);
 1.10555 +      }
 1.10556 +      return assign();
 1.10557 +    }
 1.10558 +
 1.10559 +    //! In-place version of the previous constructor.
 1.10560 +    template<typename t>
 1.10561 +    CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
 1.10562 +      return assign(img,dimensions).fill(val);
 1.10563 +    }
 1.10564 +
 1.10565 +    //! In-place version of the previous constructor.
 1.10566 +    /**
 1.10567 +       This function replaces the instance image by the one that have been read from the given file.
 1.10568 +       \param filename Filename of the image file.
 1.10569 +       - The image format is deduced from the filename only by looking for the filename extension i.e. without
 1.10570 +       analyzing the file itself.
 1.10571 +       - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
 1.10572 +       More informations on this topic can be found in cimg_files_io.
 1.10573 +       - If the filename is not found, a CImgIOException is thrown by this constructor.
 1.10574 +    **/
 1.10575 +    CImg<T>& assign(const char *const filename) {
 1.10576 +      return load(filename);
 1.10577 +    }
 1.10578 +
 1.10579 +    //! In-place version of the previous constructor.
 1.10580 +    CImg<T>& assign(const CImgDisplay &disp) {
 1.10581 +      disp.snapshot(*this);
 1.10582 +      return *this;
 1.10583 +    }
 1.10584 +
 1.10585 +    //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
 1.10586 +    /**
 1.10587 +       The instance image is always empty after a call to this function.
 1.10588 +    **/
 1.10589 +    template<typename t>
 1.10590 +    CImg<t>& transfer_to(CImg<t>& img) {
 1.10591 +      img.assign(*this);
 1.10592 +      assign();
 1.10593 +      return img;
 1.10594 +    }
 1.10595 +
 1.10596 +    CImg<T>& transfer_to(CImg<T>& img) {
 1.10597 +      if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
 1.10598 +      return img;
 1.10599 +    }
 1.10600 +
 1.10601 +    //! Swap all fields of two images. Use with care !
 1.10602 +    CImg<T>& swap(CImg<T>& img) {
 1.10603 +      cimg::swap(width,img.width);
 1.10604 +      cimg::swap(height,img.height);
 1.10605 +      cimg::swap(depth,img.depth);
 1.10606 +      cimg::swap(dim,img.dim);
 1.10607 +      cimg::swap(data,img.data);
 1.10608 +      cimg::swap(is_shared,img.is_shared);
 1.10609 +      return img;
 1.10610 +    }
 1.10611 +
 1.10612 +    //@}
 1.10613 +    //-------------------------------------
 1.10614 +    //
 1.10615 +    //! \name Image Informations
 1.10616 +    //@{
 1.10617 +    //-------------------------------------
 1.10618 +
 1.10619 +    //! Return the type of the pixel values.
 1.10620 +    /**
 1.10621 +       \return a string describing the type of the image pixels (template parameter \p T).
 1.10622 +       - The string returned may contains spaces (<tt>"unsigned char"</tt>).
 1.10623 +       - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
 1.10624 +    **/
 1.10625 +    static const char* pixel_type() {
 1.10626 +      return cimg::type<T>::string();
 1.10627 +    }
 1.10628 +
 1.10629 +    //! Return the total number of pixel values in an image.
 1.10630 +    /**
 1.10631 +       - Equivalent to : dimx() * dimy() * dimz() * dimv().
 1.10632 +
 1.10633 +       \par example:
 1.10634 +       \code
 1.10635 +       CImg<> img(100,100,1,3);
 1.10636 +       if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
 1.10637 +       \endcode
 1.10638 +    **/
 1.10639 +    unsigned long size() const {
 1.10640 +      return width*height*depth*dim;
 1.10641 +    }
 1.10642 +
 1.10643 +    //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
 1.10644 +    int dimx() const {
 1.10645 +      return (int)width;
 1.10646 +    }
 1.10647 +
 1.10648 +    //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
 1.10649 +    int dimy() const {
 1.10650 +      return (int)height;
 1.10651 +    }
 1.10652 +
 1.10653 +    //! Return the number of slices of the instance image (size along the Z-axis).
 1.10654 +    int dimz() const {
 1.10655 +      return (int)depth;
 1.10656 +    }
 1.10657 +
 1.10658 +    //! Return the number of vector channels of the instance image (size along the V-axis).
 1.10659 +    int dimv() const {
 1.10660 +      return (int)dim;
 1.10661 +    }
 1.10662 +
 1.10663 +    //! Return \c true if image (*this) has the specified width.
 1.10664 +    bool is_sameX(const unsigned int dx) const {
 1.10665 +      return (width==dx);
 1.10666 +    }
 1.10667 +
 1.10668 +    //! Return \c true if images \c (*this) and \c img have same width.
 1.10669 +    template<typename t>
 1.10670 +    bool is_sameX(const CImg<t>& img) const {
 1.10671 +      return is_sameX(img.width);
 1.10672 +    }
 1.10673 +
 1.10674 +    //! Return \c true if images \c (*this) and the display \c disp have same width.
 1.10675 +    bool is_sameX(const CImgDisplay& disp) const {
 1.10676 +      return is_sameX(disp.width);
 1.10677 +    }
 1.10678 +
 1.10679 +    //! Return \c true if image (*this) has the specified height.
 1.10680 +    bool is_sameY(const unsigned int dy) const {
 1.10681 +      return (height==dy);
 1.10682 +    }
 1.10683 +
 1.10684 +    //! Return \c true if images \c (*this) and \c img have same height.
 1.10685 +    template<typename t>
 1.10686 +    bool is_sameY(const CImg<t>& img) const {
 1.10687 +      return is_sameY(img.height);
 1.10688 +    }
 1.10689 +
 1.10690 +    //! Return \c true if images \c (*this) and the display \c disp have same height.
 1.10691 +    bool is_sameY(const CImgDisplay& disp) const {
 1.10692 +      return is_sameY(disp.height);
 1.10693 +    }
 1.10694 +
 1.10695 +    //! Return \c true if image (*this) has the specified depth.
 1.10696 +    bool is_sameZ(const unsigned int dz) const {
 1.10697 +      return (depth==dz);
 1.10698 +    }
 1.10699 +
 1.10700 +    //! Return \c true if images \c (*this) and \c img have same depth.
 1.10701 +    template<typename t>
 1.10702 +    bool is_sameZ(const CImg<t>& img) const {
 1.10703 +      return is_sameZ(img.depth);
 1.10704 +    }
 1.10705 +
 1.10706 +    //! Return \c true if image (*this) has the specified number of channels.
 1.10707 +    bool is_sameV(const unsigned int dv) const {
 1.10708 +      return (dim==dv);
 1.10709 +    }
 1.10710 +
 1.10711 +    //! Return \c true if images \c (*this) and \c img have same dim.
 1.10712 +    template<typename t>
 1.10713 +    bool is_sameV(const CImg<t>& img) const {
 1.10714 +      return is_sameV(img.dim);
 1.10715 +    }
 1.10716 +
 1.10717 +    //! Return \c true if image (*this) has the specified width and height.
 1.10718 +    bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
 1.10719 +      return (is_sameX(dx) && is_sameY(dy));
 1.10720 +    }
 1.10721 +
 1.10722 +    //! Return \c true if images have same width and same height.
 1.10723 +    template<typename t>
 1.10724 +    bool is_sameXY(const CImg<t>& img) const {
 1.10725 +      return (is_sameX(img) && is_sameY(img));
 1.10726 +    }
 1.10727 +
 1.10728 +    //! Return \c true if image \c (*this) and the display \c disp have same width and same height.
 1.10729 +    bool is_sameXY(const CImgDisplay& disp) const {
 1.10730 +      return (is_sameX(disp) && is_sameY(disp));
 1.10731 +    }
 1.10732 +
 1.10733 +    //! Return \c true if image (*this) has the specified width and depth.
 1.10734 +    bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
 1.10735 +      return (is_sameX(dx) && is_sameZ(dz));
 1.10736 +    }
 1.10737 +
 1.10738 +    //! Return \c true if images have same width and same depth.
 1.10739 +    template<typename t>
 1.10740 +    bool is_sameXZ(const CImg<t>& img) const {
 1.10741 +      return (is_sameX(img) && is_sameZ(img));
 1.10742 +    }
 1.10743 +
 1.10744 +    //! Return \c true if image (*this) has the specified width and number of channels.
 1.10745 +    bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
 1.10746 +      return (is_sameX(dx) && is_sameV(dv));
 1.10747 +    }
 1.10748 +
 1.10749 +    //! Return \c true if images have same width and same number of channels.
 1.10750 +    template<typename t>
 1.10751 +    bool is_sameXV(const CImg<t>& img) const {
 1.10752 +      return (is_sameX(img) && is_sameV(img));
 1.10753 +    }
 1.10754 +
 1.10755 +    //! Return \c true if image (*this) has the specified height and depth.
 1.10756 +    bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
 1.10757 +      return (is_sameY(dy) && is_sameZ(dz));
 1.10758 +    }
 1.10759 +
 1.10760 +    //! Return \c true if images have same height and same depth.
 1.10761 +    template<typename t>
 1.10762 +    bool is_sameYZ(const CImg<t>& img) const {
 1.10763 +      return (is_sameY(img) && is_sameZ(img));
 1.10764 +    }
 1.10765 +
 1.10766 +    //! Return \c true if image (*this) has the specified height and number of channels.
 1.10767 +    bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
 1.10768 +      return (is_sameY(dy) && is_sameV(dv));
 1.10769 +    }
 1.10770 +
 1.10771 +    //! Return \c true if images have same height and same number of channels.
 1.10772 +    template<typename t>
 1.10773 +    bool is_sameYV(const CImg<t>& img) const {
 1.10774 +      return (is_sameY(img) && is_sameV(img));
 1.10775 +    }
 1.10776 +
 1.10777 +    //! Return \c true if image (*this) has the specified depth and number of channels.
 1.10778 +    bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
 1.10779 +      return (is_sameZ(dz) && is_sameV(dv));
 1.10780 +    }
 1.10781 +
 1.10782 +    //! Return \c true if images have same depth and same number of channels.
 1.10783 +    template<typename t>
 1.10784 +    bool is_sameZV(const CImg<t>& img) const {
 1.10785 +      return (is_sameZ(img) && is_sameV(img));
 1.10786 +    }
 1.10787 +
 1.10788 +    //! Return \c true if image (*this) has the specified width, height and depth.
 1.10789 +    bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
 1.10790 +      return (is_sameXY(dx,dy) && is_sameZ(dz));
 1.10791 +    }
 1.10792 +
 1.10793 +    //! Return \c true if images have same width, same height and same depth.
 1.10794 +    template<typename t>
 1.10795 +    bool is_sameXYZ(const CImg<t>& img) const {
 1.10796 +      return (is_sameXY(img) && is_sameZ(img));
 1.10797 +    }
 1.10798 +
 1.10799 +    //! Return \c true if image (*this) has the specified width, height and depth.
 1.10800 +    bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
 1.10801 +      return (is_sameXY(dx,dy) && is_sameV(dv));
 1.10802 +    }
 1.10803 +
 1.10804 +    //! Return \c true if images have same width, same height and same number of channels.
 1.10805 +    template<typename t>
 1.10806 +    bool is_sameXYV(const CImg<t>& img) const {
 1.10807 +      return (is_sameXY(img) && is_sameV(img));
 1.10808 +    }
 1.10809 +
 1.10810 +    //! Return \c true if image (*this) has the specified width, height and number of channels.
 1.10811 +    bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
 1.10812 +      return (is_sameXZ(dx,dz) && is_sameV(dv));
 1.10813 +    }
 1.10814 +
 1.10815 +    //! Return \c true if images have same width, same depth and same number of channels.
 1.10816 +    template<typename t>
 1.10817 +    bool is_sameXZV(const CImg<t>& img) const {
 1.10818 +      return (is_sameXZ(img) && is_sameV(img));
 1.10819 +    }
 1.10820 +
 1.10821 +    //! Return \c true if image (*this) has the specified height, depth and number of channels.
 1.10822 +    bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 1.10823 +      return (is_sameYZ(dy,dz) && is_sameV(dv));
 1.10824 +    }
 1.10825 +
 1.10826 +    //! Return \c true if images have same heigth, same depth and same number of channels.
 1.10827 +    template<typename t>
 1.10828 +    bool is_sameYZV(const CImg<t>& img) const {
 1.10829 +      return (is_sameYZ(img) && is_sameV(img));
 1.10830 +    }
 1.10831 +
 1.10832 +    //! Return \c true if image (*this) has the specified width, height, depth and number of channels.
 1.10833 +    bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 1.10834 +      return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
 1.10835 +    }
 1.10836 +
 1.10837 +    //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
 1.10838 +    template<typename t>
 1.10839 +    bool is_sameXYZV(const CImg<t>& img) const {
 1.10840 +      return (is_sameXYZ(img) && is_sameV(img));
 1.10841 +    }
 1.10842 +
 1.10843 +    //! Return \c true if current image is empty.
 1.10844 +    bool is_empty() const {
 1.10845 +      return !(data && width && height && depth && dim);
 1.10846 +    }
 1.10847 +
 1.10848 +    //! Return \p true if image is not empty.
 1.10849 +    operator bool() const {
 1.10850 +      return !is_empty();
 1.10851 +    }
 1.10852 +
 1.10853 +    //! Return an iterator to the first image pixel
 1.10854 +    iterator begin() {
 1.10855 +      return data;
 1.10856 +    }
 1.10857 +
 1.10858 +    const_iterator begin() const {
 1.10859 +      return data;
 1.10860 +    }
 1.10861 +
 1.10862 +    //! Return reference to the first image pixel
 1.10863 +    const T& first() const {
 1.10864 +      return *data;
 1.10865 +    }
 1.10866 +
 1.10867 +    T& first() {
 1.10868 +       return *data;
 1.10869 +    }
 1.10870 +
 1.10871 +    //! Return an iterator pointing after the last image pixel
 1.10872 +    iterator end() {
 1.10873 +      return data + size();
 1.10874 +    }
 1.10875 +
 1.10876 +    const_iterator end() const {
 1.10877 +      return data + size();
 1.10878 +    }
 1.10879 +
 1.10880 +    //! Return a reference to the last image pixel
 1.10881 +    const T& last() const {
 1.10882 +       return data[size() - 1];
 1.10883 +    }
 1.10884 +
 1.10885 +    T& last() {
 1.10886 +       return data[size() - 1];
 1.10887 +    }
 1.10888 +
 1.10889 +    //! Return a pointer to the pixel buffer.
 1.10890 +    T* ptr() {
 1.10891 +      return data;
 1.10892 +    }
 1.10893 +
 1.10894 +    const T* ptr() const {
 1.10895 +      return data;
 1.10896 +    }
 1.10897 +
 1.10898 +    //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
 1.10899 +    /**
 1.10900 +       \param x X-coordinate of the pixel.
 1.10901 +       \param y Y-coordinate of the pixel.
 1.10902 +       \param z Z-coordinate of the pixel.
 1.10903 +       \param v V-coordinate of the pixel.
 1.10904 +
 1.10905 +       - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer.
 1.10906 +       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
 1.10907 +       given coordinates are outside the image range (but function performances decrease).
 1.10908 +
 1.10909 +       \par example:
 1.10910 +       \code
 1.10911 +       CImg<float> img(100,100,1,1,0);   // Define a 100x100 greyscale image with float-valued pixels.
 1.10912 +       float *ptr = ptr(10,10);          // Get a pointer to the pixel located at (10,10).
 1.10913 +       float val = *ptr;                 // Get the pixel value.
 1.10914 +       \endcode
 1.10915 +    **/
 1.10916 +#if cimg_debug>=3
 1.10917 +    T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 1.10918 +      const long off = offset(x,y,z,v);
 1.10919 +      if (off<0 || off>=(long)size()) {
 1.10920 +        cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
 1.10921 +                   "outside image range (%u,%u,%u,%u) (size=%lu)",
 1.10922 +                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
 1.10923 +        return data;
 1.10924 +      }
 1.10925 +      return data + off;
 1.10926 +    }
 1.10927 +
 1.10928 +    const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 1.10929 +      return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
 1.10930 +    }
 1.10931 +#else
 1.10932 +    T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 1.10933 +      return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 1.10934 +    }
 1.10935 +
 1.10936 +    const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 1.10937 +      return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 1.10938 +    }
 1.10939 +#endif
 1.10940 +
 1.10941 +    //! Return \c true if the memory buffers of the two images overlaps.
 1.10942 +    /**
 1.10943 +       May happen when using shared images.
 1.10944 +    **/
 1.10945 +    template<typename t>
 1.10946 +    bool is_overlapped(const CImg<t>& img) const {
 1.10947 +      const unsigned long csiz = size(), isiz = img.size();
 1.10948 +      return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
 1.10949 +    }
 1.10950 +
 1.10951 +    //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data.
 1.10952 +    /**
 1.10953 +       \param x X-coordinate of the pixel.
 1.10954 +       \param y Y-coordinate of the pixel.
 1.10955 +       \param z Z-coordinate of the pixel.
 1.10956 +       \param v V-coordinate of the pixel.
 1.10957 +
 1.10958 +       - No checking is done on the validity of the given coordinates.
 1.10959 +
 1.10960 +       \par Example:
 1.10961 +       \code
 1.10962 +       CImg<float> img(100,100,1,3,0);         // Define a 100x100 color image with float-valued black pixels.
 1.10963 +       long off = img.offset(10,10,0,2);       // Get the offset of the blue value of the pixel located at (10,10).
 1.10964 +       float val = img[off];                   // Get the blue value of the pixel.
 1.10965 +       \endcode
 1.10966 +    **/
 1.10967 +    long offset(const int x, const int y=0, const int z=0, const int v=0) const {
 1.10968 +      return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 1.10969 +    }
 1.10970 +
 1.10971 +    //! Fast access to pixel value for reading or writing.
 1.10972 +    /**
 1.10973 +       \param x X-coordinate of the pixel.
 1.10974 +       \param y Y-coordinate of the pixel.
 1.10975 +       \param z Z-coordinate of the pixel.
 1.10976 +       \param v V-coordinate of the pixel.
 1.10977 +
 1.10978 +       - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
 1.10979 +       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
 1.10980 +       (but function performances decrease).
 1.10981 +
 1.10982 +       \par example:
 1.10983 +       \code
 1.10984 +       CImg<float> img(100,100,1,3,0);                       // Define a 100x100 color image with float-valued black pixels.
 1.10985 +       const float valR = img(10,10,0,0);                    // Read the red component at coordinates (10,10).
 1.10986 +       const float valG = img(10,10,0,1);                    // Read the green component at coordinates (10,10)
 1.10987 +       const float valB = img(10,10,2);                      // Read the blue component at coordinates (10,10) (Z-coordinate omitted here).
 1.10988 +       const float avg = (valR + valG + valB)/3;             // Compute average pixel value.
 1.10989 +       img(10,10,0) = img(10,10,1) = img(10,10,2) = avg;     // Replace the pixel (10,10) by the average grey value.
 1.10990 +       \endcode
 1.10991 +    **/
 1.10992 +#if cimg_debug>=3
 1.10993 +    T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 1.10994 +      const long off = offset(x,y,z,v);
 1.10995 +      if (!data || off>=(long)size()) {
 1.10996 +        cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
 1.10997 +                   "outside the image range (%u,%u,%u,%u) (size=%lu)",
 1.10998 +                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
 1.10999 +        return *data;
 1.11000 +      }
 1.11001 +      else return data[off];
 1.11002 +    }
 1.11003 +
 1.11004 +    const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 1.11005 +      return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
 1.11006 +    }
 1.11007 +#else
 1.11008 +    T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 1.11009 +      return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 1.11010 +    }
 1.11011 +
 1.11012 +    const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 1.11013 +      return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 1.11014 +    }
 1.11015 +#endif
 1.11016 +
 1.11017 +    //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
 1.11018 +    /**
 1.11019 +       \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr().
 1.11020 +
 1.11021 +       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
 1.11022 +       (but function performances decrease).
 1.11023 +       - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
 1.11024 +       with operator()() (see example below).
 1.11025 +
 1.11026 +       \par example:
 1.11027 +       \code
 1.11028 +       CImg<float> vec(1,10);        // Define a vector of float values (10 lines, 1 row).
 1.11029 +       const float val1 = vec(0,4);  // Get the fifth element using operator()().
 1.11030 +       const float val2 = vec[4];    // Get the fifth element using operator[]. Here, val2==val1.
 1.11031 +       \endcode
 1.11032 +    **/
 1.11033 +#if cimg_debug>=3
 1.11034 +    T& operator[](const unsigned long off) {
 1.11035 +      if (!data || off>=size()) {
 1.11036 +        cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
 1.11037 +                   "outside the image range (%u,%u,%u,%u) (size=%lu)",
 1.11038 +                   pixel_type(),off,width,height,depth,dim,size());
 1.11039 +        return *data;
 1.11040 +      }
 1.11041 +      else return data[off];
 1.11042 +    }
 1.11043 +
 1.11044 +    const T& operator[](const unsigned long off) const {
 1.11045 +      return const_cast<CImg<T>*>(this)->operator[](off);
 1.11046 +    }
 1.11047 +#else
 1.11048 +    T& operator[](const unsigned long off) {
 1.11049 +      return data[off];
 1.11050 +    }
 1.11051 +
 1.11052 +    const T& operator[](const unsigned long off) const {
 1.11053 +      return data[off];
 1.11054 +    }
 1.11055 +#endif
 1.11056 +
 1.11057 +    //! Return a reference to the last image value
 1.11058 +    T& back() {
 1.11059 +      return operator()(size()-1);
 1.11060 +    }
 1.11061 +
 1.11062 +    const T& back() const {
 1.11063 +      return operator()(size()-1);
 1.11064 +    }
 1.11065 +
 1.11066 +    //! Return a reference to the first image value
 1.11067 +    T& front() {
 1.11068 +      return *data;
 1.11069 +    }
 1.11070 +
 1.11071 +    const T& front() const {
 1.11072 +      return *data;
 1.11073 +    }
 1.11074 +
 1.11075 +    //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
 1.11076 +    bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
 1.11077 +      return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
 1.11078 +    }
 1.11079 +
 1.11080 +    //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
 1.11081 +    template<typename t>
 1.11082 +    bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
 1.11083 +      const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
 1.11084 +      const T *const ppixel = &pixel;
 1.11085 +      if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 1.11086 +      unsigned long off = (unsigned long)(ppixel - data);
 1.11087 +      const unsigned long nv = off/whz;
 1.11088 +      off%=whz;
 1.11089 +      const unsigned long nz = off/wh;
 1.11090 +      off%=wh;
 1.11091 +      const unsigned long ny = off/width, nx = off%width;
 1.11092 +      x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
 1.11093 +      return true;
 1.11094 +    }
 1.11095 +
 1.11096 +    //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
 1.11097 +    template<typename t>
 1.11098 +    bool contains(const T& pixel, t& x, t& y, t& z) const {
 1.11099 +      const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
 1.11100 +      const T *const ppixel = &pixel;
 1.11101 +      if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 1.11102 +      unsigned long off = ((unsigned long)(ppixel - data))%whz;
 1.11103 +      const unsigned long nz = off/wh;
 1.11104 +      off%=wh;
 1.11105 +      const unsigned long ny = off/width, nx = off%width;
 1.11106 +      x = (t)nx; y = (t)ny; z = (t)nz;
 1.11107 +      return true;
 1.11108 +    }
 1.11109 +
 1.11110 +    //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y).
 1.11111 +    template<typename t>
 1.11112 +    bool contains(const T& pixel, t& x, t& y) const {
 1.11113 +      const unsigned long wh = width*height, siz = wh*depth*dim;
 1.11114 +      const T *const ppixel = &pixel;
 1.11115 +      if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 1.11116 +      unsigned long off = ((unsigned long)(ppixel - data))%wh;
 1.11117 +      const unsigned long ny = off/width, nx = off%width;
 1.11118 +      x = (t)nx; y = (t)ny;
 1.11119 +      return true;
 1.11120 +    }
 1.11121 +
 1.11122 +    //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x).
 1.11123 +    template<typename t>
 1.11124 +    bool contains(const T& pixel, t& x) const {
 1.11125 +      const T *const ppixel = &pixel;
 1.11126 +      if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
 1.11127 +      x = (t)(((unsigned long)(ppixel - data))%width);
 1.11128 +      return true;
 1.11129 +    }
 1.11130 +
 1.11131 +    //! Return \c true if specified referenced value is inside the image boundaries.
 1.11132 +    bool contains(const T& pixel) const {
 1.11133 +      const T *const ppixel = &pixel;
 1.11134 +      return !is_empty() && ppixel>=data && ppixel<data+size();
 1.11135 +    }
 1.11136 +
 1.11137 +    //! Read a pixel value with Dirichlet boundary conditions.
 1.11138 +    T& at(const int off, const T out_val) {
 1.11139 +      return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
 1.11140 +    }
 1.11141 +
 1.11142 +    T at(const int off, const T out_val) const {
 1.11143 +      return (off<0 || off>=(int)size())?out_val:(*this)[off];
 1.11144 +    }
 1.11145 +
 1.11146 +    //! Read a pixel value with Neumann boundary conditions.
 1.11147 +    T& at(const int off) {
 1.11148 +      if (!size())
 1.11149 +        throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
 1.11150 +                                    pixel_type());
 1.11151 +      return _at(off);
 1.11152 +    }
 1.11153 +
 1.11154 +    T at(const int off) const {
 1.11155 +      if (!size())
 1.11156 +        throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
 1.11157 +                                    pixel_type());
 1.11158 +      return _at(off);
 1.11159 +    }
 1.11160 +
 1.11161 +    T& _at(const int off) {
 1.11162 +      const unsigned int siz = (unsigned int)size();
 1.11163 +      return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
 1.11164 +    }
 1.11165 +
 1.11166 +    T _at(const int off) const {
 1.11167 +      const unsigned int siz = (unsigned int)size();
 1.11168 +      return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
 1.11169 +    }
 1.11170 +
 1.11171 +    //! Read a pixel value with Dirichlet boundary conditions.
 1.11172 +    T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
 1.11173 +      return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
 1.11174 +        (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 1.11175 +    }
 1.11176 +
 1.11177 +    T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
 1.11178 +      return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
 1.11179 +    }
 1.11180 +
 1.11181 +    //! Read a pixel value with Neumann boundary conditions.
 1.11182 +    T& atXYZV(const int x, const int y, const int z, const int v) {
 1.11183 +      if (is_empty())
 1.11184 +        throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
 1.11185 +                                    pixel_type());
 1.11186 +      return _atXYZV(x,y,z,v);
 1.11187 +    }
 1.11188 +
 1.11189 +    T atXYZV(const int x, const int y, const int z, const int v) const {
 1.11190 +      if (is_empty())
 1.11191 +        throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
 1.11192 +                                    pixel_type());
 1.11193 +      return _atXYZV(x,y,z,v);
 1.11194 +    }
 1.11195 +
 1.11196 +    T& _atXYZV(const int x, const int y, const int z, const int v) {
 1.11197 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 1.11198 +                     z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 1.11199 +    }
 1.11200 +
 1.11201 +    T _atXYZV(const int x, const int y, const int z, const int v) const {
 1.11202 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 1.11203 +                     z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 1.11204 +    }
 1.11205 +
 1.11206 +    //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
 1.11207 +    T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
 1.11208 +      return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
 1.11209 +        (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 1.11210 +    }
 1.11211 +
 1.11212 +    T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
 1.11213 +      return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
 1.11214 +    }
 1.11215 +
 1.11216 +    //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
 1.11217 +    T& atXYZ(const int x, const int y, const int z, const int v=0) {
 1.11218 +      if (is_empty())
 1.11219 +        throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
 1.11220 +                                    pixel_type());
 1.11221 +      return _atXYZ(x,y,z,v);
 1.11222 +    }
 1.11223 +
 1.11224 +    T atXYZ(const int x, const int y, const int z, const int v=0) const {
 1.11225 +      if (is_empty())
 1.11226 +        throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
 1.11227 +                                    pixel_type());
 1.11228 +      return _atXYZ(x,y,z,v);
 1.11229 +    }
 1.11230 +
 1.11231 +    T& _atXYZ(const int x, const int y, const int z, const int v=0) {
 1.11232 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
 1.11233 +                     z<0?0:(z>=dimz()?dimz()-1:z),v);
 1.11234 +    }
 1.11235 +
 1.11236 +    T _atXYZ(const int x, const int y, const int z, const int v=0) const {
 1.11237 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
 1.11238 +                     z<0?0:(z>=dimz()?dimz()-1:z),v);
 1.11239 +    }
 1.11240 +
 1.11241 +    //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
 1.11242 +    T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
 1.11243 +      return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 1.11244 +    }
 1.11245 +
 1.11246 +    T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
 1.11247 +      return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
 1.11248 +    }
 1.11249 +
 1.11250 +    //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
 1.11251 +    T& atXY(const int x, const int y, const int z=0, const int v=0) {
 1.11252 +      if (is_empty())
 1.11253 +        throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
 1.11254 +                                    pixel_type());
 1.11255 +      return _atXY(x,y,z,v);
 1.11256 +    }
 1.11257 +
 1.11258 +    T atXY(const int x, const int y, const int z=0, const int v=0) const {
 1.11259 +      if (is_empty())
 1.11260 +        throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
 1.11261 +                                    pixel_type());
 1.11262 +      return _atXY(x,y,z,v);
 1.11263 +    }
 1.11264 +
 1.11265 +    T& _atXY(const int x, const int y, const int z=0, const int v=0) {
 1.11266 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 1.11267 +    }
 1.11268 +
 1.11269 +    T _atXY(const int x, const int y, const int z=0, const int v=0) const {
 1.11270 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 1.11271 +    }
 1.11272 +
 1.11273 +    //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
 1.11274 +    T& atX(const int x, const int y, const int z, const int v, const T out_val) {
 1.11275 +      return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
 1.11276 +    }
 1.11277 +
 1.11278 +    T atX(const int x, const int y, const int z, const int v, const T out_val) const {
 1.11279 +      return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
 1.11280 +    }
 1.11281 +
 1.11282 +    //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
 1.11283 +    T& atX(const int x, const int y=0, const int z=0, const int v=0) {
 1.11284 +      if (is_empty())
 1.11285 +        throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
 1.11286 +                                    pixel_type());
 1.11287 +      return _atX(x,y,z,v);
 1.11288 +    }
 1.11289 +
 1.11290 +    T atX(const int x, const int y=0, const int z=0, const int v=0) const {
 1.11291 +      if (is_empty())
 1.11292 +        throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
 1.11293 +                                    pixel_type());
 1.11294 +      return _atX(x,y,z,v);
 1.11295 +    }
 1.11296 +
 1.11297 +    T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
 1.11298 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 1.11299 +    }
 1.11300 +
 1.11301 +    T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
 1.11302 +      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 1.11303 +    }
 1.11304 +
 1.11305 +    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
 1.11306 +    Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
 1.11307 +      const int
 1.11308 +        x = (int)fx-(fx>=0?0:1), nx = x+1,
 1.11309 +        y = (int)fy-(fy>=0?0:1), ny = y+1,
 1.11310 +        z = (int)fz-(fz>=0?0:1), nz = z+1,
 1.11311 +        v = (int)fv-(fv>=0?0:1), nv = v+1;
 1.11312 +      const float
 1.11313 +        dx = fx-x,
 1.11314 +        dy = fy-y,
 1.11315 +        dz = fz-z,
 1.11316 +        dv = fv-v;
 1.11317 +      const Tfloat
 1.11318 +        Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
 1.11319 +        Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
 1.11320 +        Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
 1.11321 +        Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
 1.11322 +        Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
 1.11323 +        Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
 1.11324 +        Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
 1.11325 +        Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
 1.11326 +      return Icccc +
 1.11327 +        dx*(Inccc-Icccc +
 1.11328 +            dy*(Icccc+Inncc-Icncc-Inccc +
 1.11329 +                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 1.11330 +                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 1.11331 +                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 1.11332 +            dz*(Icccc+Incnc-Iccnc-Inccc +
 1.11333 +                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 1.11334 +            dv*(Icccc+Inccn-Inccc-Icccn)) +
 1.11335 +        dy*(Icncc-Icccc +
 1.11336 +            dz*(Icccc+Icnnc-Iccnc-Icncc +
 1.11337 +                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 1.11338 +            dv*(Icccc+Icncn-Icncc-Icccn)) +
 1.11339 +        dz*(Iccnc-Icccc +
 1.11340 +            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 1.11341 +        dv*(Icccn-Icccc);
 1.11342 +    }
 1.11343 +
 1.11344 +    //! Read a pixel value using linear interpolation and Neumann boundary conditions.
 1.11345 +    Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 1.11346 +      if (is_empty())
 1.11347 +        throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
 1.11348 +                                    pixel_type());
 1.11349 +      return _linear_atXYZV(fx,fy,fz,fv);
 1.11350 +    }
 1.11351 +
 1.11352 +    Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 1.11353 +      const float
 1.11354 +        nfx = fx<0?0:(fx>width-1?width-1:fx),
 1.11355 +        nfy = fy<0?0:(fy>height-1?height-1:fy),
 1.11356 +        nfz = fz<0?0:(fz>depth-1?depth-1:fz),
 1.11357 +        nfv = fv<0?0:(fv>dim-1?dim-1:fv);
 1.11358 +      const unsigned int
 1.11359 +        x = (unsigned int)nfx,
 1.11360 +        y = (unsigned int)nfy,
 1.11361 +        z = (unsigned int)nfz,
 1.11362 +        v = (unsigned int)nfv;
 1.11363 +      const float
 1.11364 +        dx = nfx-x,
 1.11365 +        dy = nfy-y,
 1.11366 +        dz = nfz-z,
 1.11367 +        dv = nfv-v;
 1.11368 +      const unsigned int
 1.11369 +        nx = dx>0?x+1:x,
 1.11370 +        ny = dy>0?y+1:y,
 1.11371 +        nz = dz>0?z+1:z,
 1.11372 +        nv = dv>0?v+1:v;
 1.11373 +      const Tfloat
 1.11374 +        Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
 1.11375 +        Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
 1.11376 +        Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
 1.11377 +        Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
 1.11378 +        Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
 1.11379 +        Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
 1.11380 +        Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
 1.11381 +        Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
 1.11382 +      return Icccc +
 1.11383 +        dx*(Inccc-Icccc +
 1.11384 +            dy*(Icccc+Inncc-Icncc-Inccc +
 1.11385 +                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 1.11386 +                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 1.11387 +                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 1.11388 +            dz*(Icccc+Incnc-Iccnc-Inccc +
 1.11389 +                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 1.11390 +            dv*(Icccc+Inccn-Inccc-Icccn)) +
 1.11391 +        dy*(Icncc-Icccc +
 1.11392 +            dz*(Icccc+Icnnc-Iccnc-Icncc +
 1.11393 +                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 1.11394 +            dv*(Icccc+Icncn-Icncc-Icccn)) +
 1.11395 +        dz*(Iccnc-Icccc +
 1.11396 +            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 1.11397 +        dv*(Icccn-Icccc);
 1.11398 +    }
 1.11399 +
 1.11400 +    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
 1.11401 +    Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
 1.11402 +      const int
 1.11403 +        x = (int)fx-(fx>=0?0:1), nx = x+1,
 1.11404 +        y = (int)fy-(fy>=0?0:1), ny = y+1,
 1.11405 +        z = (int)fz-(fz>=0?0:1), nz = z+1;
 1.11406 +      const float
 1.11407 +        dx = fx-x,
 1.11408 +        dy = fy-y,
 1.11409 +        dz = fz-z;
 1.11410 +      const Tfloat
 1.11411 +        Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
 1.11412 +        Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
 1.11413 +        Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
 1.11414 +        Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
 1.11415 +      return Iccc +
 1.11416 +        dx*(Incc-Iccc +
 1.11417 +            dy*(Iccc+Innc-Icnc-Incc +
 1.11418 +                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 1.11419 +            dz*(Iccc+Incn-Iccn-Incc)) +
 1.11420 +        dy*(Icnc-Iccc +
 1.11421 +            dz*(Iccc+Icnn-Iccn-Icnc)) +
 1.11422 +        dz*(Iccn-Iccc);
 1.11423 +    }
 1.11424 +
 1.11425 +    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
 1.11426 +    Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
 1.11427 +      if (is_empty())
 1.11428 +        throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
 1.11429 +                                    pixel_type());
 1.11430 +      return _linear_atXYZ(fx,fy,fz,v);
 1.11431 +    }
 1.11432 +
 1.11433 +    Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
 1.11434 +      const float
 1.11435 +        nfx = fx<0?0:(fx>width-1?width-1:fx),
 1.11436 +        nfy = fy<0?0:(fy>height-1?height-1:fy),
 1.11437 +        nfz = fz<0?0:(fz>depth-1?depth-1:fz);
 1.11438 +      const unsigned int
 1.11439 +        x = (unsigned int)nfx,
 1.11440 +        y = (unsigned int)nfy,
 1.11441 +        z = (unsigned int)nfz;
 1.11442 +      const float
 1.11443 +        dx = nfx-x,
 1.11444 +        dy = nfy-y,
 1.11445 +        dz = nfz-z;
 1.11446 +      const unsigned int
 1.11447 +        nx = dx>0?x+1:x,
 1.11448 +        ny = dy>0?y+1:y,
 1.11449 +        nz = dz>0?z+1:z;
 1.11450 +      const Tfloat
 1.11451 +        Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
 1.11452 +        Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
 1.11453 +        Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
 1.11454 +        Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
 1.11455 +      return Iccc +
 1.11456 +        dx*(Incc-Iccc +
 1.11457 +            dy*(Iccc+Innc-Icnc-Incc +
 1.11458 +                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 1.11459 +            dz*(Iccc+Incn-Iccn-Incc)) +
 1.11460 +        dy*(Icnc-Iccc +
 1.11461 +            dz*(Iccc+Icnn-Iccn-Icnc)) +
 1.11462 +        dz*(Iccn-Iccc);
 1.11463 +    }
 1.11464 +
 1.11465 +    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
 1.11466 +    Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
 1.11467 +      const int
 1.11468 +        x = (int)fx-(fx>=0?0:1), nx = x+1,
 1.11469 +        y = (int)fy-(fy>=0?0:1), ny = y+1;
 1.11470 +      const float
 1.11471 +        dx = fx-x,
 1.11472 +        dy = fy-y;
 1.11473 +      const Tfloat
 1.11474 +        Icc = (Tfloat)atXY(x,y,z,v,out_val),  Inc = (Tfloat)atXY(nx,y,z,v,out_val),
 1.11475 +        Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
 1.11476 +      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 1.11477 +    }
 1.11478 +
 1.11479 +    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
 1.11480 +    Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 1.11481 +      if (is_empty())
 1.11482 +        throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
 1.11483 +                                    pixel_type());
 1.11484 +      return _linear_atXY(fx,fy,z,v);
 1.11485 +    }
 1.11486 +
 1.11487 +    Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 1.11488 +      const float
 1.11489 +        nfx = fx<0?0:(fx>width-1?width-1:fx),
 1.11490 +        nfy = fy<0?0:(fy>height-1?height-1:fy);
 1.11491 +      const unsigned int
 1.11492 +        x = (unsigned int)nfx,
 1.11493 +        y = (unsigned int)nfy;
 1.11494 +      const float
 1.11495 +        dx = nfx-x,
 1.11496 +        dy = nfy-y;
 1.11497 +      const unsigned int
 1.11498 +        nx = dx>0?x+1:x,
 1.11499 +        ny = dy>0?y+1:y;
 1.11500 +      const Tfloat
 1.11501 +        Icc = (Tfloat)(*this)(x,y,z,v),  Inc = (Tfloat)(*this)(nx,y,z,v),
 1.11502 +        Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
 1.11503 +      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 1.11504 +    }
 1.11505 +
 1.11506 +    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
 1.11507 +    Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
 1.11508 +      const int
 1.11509 +        x = (int)fx-(fx>=0?0:1), nx = x+1;
 1.11510 +      const float
 1.11511 +        dx = fx-x;
 1.11512 +      const Tfloat
 1.11513 +        Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
 1.11514 +      return Ic + dx*(In-Ic);
 1.11515 +    }
 1.11516 +
 1.11517 +    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
 1.11518 +    Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 1.11519 +      if (is_empty())
 1.11520 +        throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
 1.11521 +                                    pixel_type());
 1.11522 +      return _linear_atX(fx,y,z,v);
 1.11523 +    }
 1.11524 +
 1.11525 +    Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 1.11526 +      const float
 1.11527 +        nfx = fx<0?0:(fx>width-1?width-1:fx);
 1.11528 +      const unsigned int
 1.11529 +        x = (unsigned int)nfx;
 1.11530 +      const float
 1.11531 +        dx = nfx-x;
 1.11532 +      const unsigned int
 1.11533 +        nx = dx>0?x+1:x;
 1.11534 +      const Tfloat
 1.11535 +        Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
 1.11536 +      return Ic + dx*(In-Ic);
 1.11537 +    }
 1.11538 +
 1.11539 +    //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
 1.11540 +    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
 1.11541 +      const int
 1.11542 +        x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
 1.11543 +        y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
 1.11544 +      const float
 1.11545 +        dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
 1.11546 +        dy = fy-y;
 1.11547 +      const Tfloat
 1.11548 +        Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
 1.11549 +        Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
 1.11550 +        Ipc = (Tfloat)atXY(px,y,z,v,out_val),  Icc = (Tfloat)atXY(x,y,z,v,out_val),
 1.11551 +        Inc = (Tfloat)atXY(nx,y,z,v,out_val),  Iac = (Tfloat)atXY(ax,y,z,v,out_val),
 1.11552 +        Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
 1.11553 +        Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
 1.11554 +        Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
 1.11555 +        Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
 1.11556 +        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)),
 1.11557 +        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)),
 1.11558 +        u0p = Icp - Ipp,
 1.11559 +        u1p = Iap - Inp,
 1.11560 +        ap = 2*(Icp-Inp) + u0p + u1p,
 1.11561 +        bp = 3*(Inp-Icp) - 2*u0p - u1p,
 1.11562 +        u0c = Icc - Ipc,
 1.11563 +        u1c = Iac - Inc,
 1.11564 +        ac = 2*(Icc-Inc) + u0c + u1c,
 1.11565 +        bc = 3*(Inc-Icc) - 2*u0c - u1c,
 1.11566 +        u0n = Icn - Ipn,
 1.11567 +        u1n = Ian - Inn,
 1.11568 +        an = 2*(Icn-Inn) + u0n + u1n,
 1.11569 +        bn = 3*(Inn-Icn) - 2*u0n - u1n,
 1.11570 +        u0a = Ica - Ipa,
 1.11571 +        u1a = Iaa - Ina,
 1.11572 +        aa = 2*(Ica-Ina) + u0a + u1a,
 1.11573 +        ba = 3*(Ina-Ica) - 2*u0a - u1a,
 1.11574 +        valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 1.11575 +        valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 1.11576 +        valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 1.11577 +        vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 1.11578 +        u0 = valc - valp,
 1.11579 +        u1 = vala - valn,
 1.11580 +        a = 2*(valc-valn) + u0 + u1,
 1.11581 +        b = 3*(valn-valc) - 2*u0 - u1,
 1.11582 +        val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 1.11583 +      return val<valm?valm:(val>valM?valM:val);
 1.11584 +    }
 1.11585 +
 1.11586 +    //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
 1.11587 +    Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 1.11588 +      if (is_empty())
 1.11589 +        throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
 1.11590 +                                    pixel_type());
 1.11591 +      return _cubic_atXY(fx,fy,z,v);
 1.11592 +    }
 1.11593 +
 1.11594 +    Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
 1.11595 +      const float
 1.11596 +        nfx = fx<0?0:(fx>width-1?width-1:fx),
 1.11597 +        nfy = fy<0?0:(fy>height-1?height-1:fy);
 1.11598 +      const int
 1.11599 +        x = (int)nfx,
 1.11600 +        y = (int)nfy;
 1.11601 +      const float
 1.11602 +        dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
 1.11603 +        dy = nfy-y;
 1.11604 +      const int
 1.11605 +        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
 1.11606 +        py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
 1.11607 +      const Tfloat
 1.11608 +        Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
 1.11609 +        Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
 1.11610 +        Ipc = (Tfloat)(*this)(px,y,z,v),  Icc = (Tfloat)(*this)(x,y,z,v),
 1.11611 +        Inc = (Tfloat)(*this)(nx,y,z,v),  Iac = (Tfloat)(*this)(ax,y,z,v),
 1.11612 +        Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
 1.11613 +        Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
 1.11614 +        Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
 1.11615 +        Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
 1.11616 +        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)),
 1.11617 +        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)),
 1.11618 +        u0p = Icp - Ipp,
 1.11619 +        u1p = Iap - Inp,
 1.11620 +        ap = 2*(Icp-Inp) + u0p + u1p,
 1.11621 +        bp = 3*(Inp-Icp) - 2*u0p - u1p,
 1.11622 +        u0c = Icc - Ipc,
 1.11623 +        u1c = Iac - Inc,
 1.11624 +        ac = 2*(Icc-Inc) + u0c + u1c,
 1.11625 +        bc = 3*(Inc-Icc) - 2*u0c - u1c,
 1.11626 +        u0n = Icn - Ipn,
 1.11627 +        u1n = Ian - Inn,
 1.11628 +        an = 2*(Icn-Inn) + u0n + u1n,
 1.11629 +        bn = 3*(Inn-Icn) - 2*u0n - u1n,
 1.11630 +        u0a = Ica - Ipa,
 1.11631 +        u1a = Iaa - Ina,
 1.11632 +        aa = 2*(Ica-Ina) + u0a + u1a,
 1.11633 +        ba = 3*(Ina-Ica) - 2*u0a - u1a,
 1.11634 +        valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 1.11635 +        valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 1.11636 +        valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 1.11637 +        vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 1.11638 +        u0 = valc - valp,
 1.11639 +        u1 = vala - valn,
 1.11640 +        a = 2*(valc-valn) + u0 + u1,
 1.11641 +        b = 3*(valn-valc) - 2*u0 - u1,
 1.11642 +        val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 1.11643 +      return val<valm?valm:(val>valM?valM:val);
 1.11644 +    }
 1.11645 +
 1.11646 +    //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
 1.11647 +    Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
 1.11648 +      const int
 1.11649 +        x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
 1.11650 +      const float
 1.11651 +        dx = fx-x;
 1.11652 +      const Tfloat
 1.11653 +        Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
 1.11654 +        In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
 1.11655 +        valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 1.11656 +        u0 = Ic - Ip,
 1.11657 +        u1 = Ia - In,
 1.11658 +        a = 2*(Ic-In) + u0 + u1,
 1.11659 +        b = 3*(In-Ic) - 2*u0 - u1,
 1.11660 +        val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 1.11661 +      return val<valm?valm:(val>valM?valM:val);
 1.11662 +    }
 1.11663 +
 1.11664 +    //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
 1.11665 +    Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 1.11666 +      if (is_empty())
 1.11667 +        throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
 1.11668 +                                    pixel_type());
 1.11669 +      return _cubic_atX(fx,y,z,v);
 1.11670 +    }
 1.11671 +
 1.11672 +    Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
 1.11673 +      const float
 1.11674 +        nfx = fx<0?0:(fx>width-1?width-1:fx);
 1.11675 +      const int
 1.11676 +        x = (int)nfx;
 1.11677 +      const float
 1.11678 +        dx = nfx-x;
 1.11679 +      const int
 1.11680 +        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
 1.11681 +      const Tfloat
 1.11682 +        Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
 1.11683 +        In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
 1.11684 +        valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 1.11685 +        u0 = Ic - Ip,
 1.11686 +        u1 = Ia - In,
 1.11687 +        a = 2*(Ic-In) + u0 + u1,
 1.11688 +        b = 3*(In-Ic) - 2*u0 - u1,
 1.11689 +        val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 1.11690 +      return val<valm?valm:(val>valM?valM:val);
 1.11691 +    }
 1.11692 +
 1.11693 +    //! Set a pixel value, with 3D float coordinates, using linear interpolation.
 1.11694 +    CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
 1.11695 +                           const bool add=false) {
 1.11696 +      const int
 1.11697 +        x = (int)fx-(fx>=0?0:1), nx = x+1,
 1.11698 +        y = (int)fy-(fy>=0?0:1), ny = y+1,
 1.11699 +        z = (int)fz-(fz>=0?0:1), nz = z+1;
 1.11700 +      const float
 1.11701 +        dx = fx-x,
 1.11702 +        dy = fy-y,
 1.11703 +        dz = fz-z;
 1.11704 +      if (v>=0 && v<dimv()) {
 1.11705 +        if (z>=0 && z<dimz()) {
 1.11706 +          if (y>=0 && y<dimy()) {
 1.11707 +            if (x>=0 && x<dimx()) {
 1.11708 +              const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
 1.11709 +              (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
 1.11710 +            }
 1.11711 +            if (nx>=0 && nx<dimx()) {
 1.11712 +              const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
 1.11713 +              (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
 1.11714 +            }
 1.11715 +          }
 1.11716 +          if (ny>=0 && ny<dimy()) {
 1.11717 +            if (x>=0 && x<dimx()) {
 1.11718 +              const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
 1.11719 +              (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
 1.11720 +            }
 1.11721 +            if (nx>=0 && nx<dimx()) {
 1.11722 +              const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
 1.11723 +              (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
 1.11724 +            }
 1.11725 +          }
 1.11726 +        }
 1.11727 +        if (nz>=0 && nz<dimz()) {
 1.11728 +          if (y>=0 && y<dimy()) {
 1.11729 +            if (x>=0 && x<dimx()) {
 1.11730 +              const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
 1.11731 +              (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
 1.11732 +            }
 1.11733 +            if (nx>=0 && nx<dimx()) {
 1.11734 +              const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
 1.11735 +              (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
 1.11736 +            }
 1.11737 +          }
 1.11738 +          if (ny>=0 && ny<dimy()) {
 1.11739 +            if (x>=0 && x<dimx()) {
 1.11740 +              const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
 1.11741 +              (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
 1.11742 +            }
 1.11743 +            if (nx>=0 && nx<dimx()) {
 1.11744 +              const float w1 = dx*dy, w2 = add?1:(1-w1);
 1.11745 +              (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
 1.11746 +            }
 1.11747 +          }
 1.11748 +        }
 1.11749 +      }
 1.11750 +      return *this;
 1.11751 +    }
 1.11752 +
 1.11753 +    //! Set a pixel value, with 2D float coordinates, using linear interpolation.
 1.11754 +    CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
 1.11755 +                          const bool add=false) {
 1.11756 +      const int
 1.11757 +        x = (int)fx-(fx>=0?0:1), nx = x+1,
 1.11758 +        y = (int)fy-(fy>=0?0:1), ny = y+1;
 1.11759 +      const float
 1.11760 +        dx = fx-x,
 1.11761 +        dy = fy-y;
 1.11762 +      if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
 1.11763 +        if (y>=0 && y<dimy()) {
 1.11764 +          if (x>=0 && x<dimx()) {
 1.11765 +            const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
 1.11766 +            (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
 1.11767 +          }
 1.11768 +          if (nx>=0 && nx<dimx()) {
 1.11769 +            const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
 1.11770 +            (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
 1.11771 +          }
 1.11772 +        }
 1.11773 +        if (ny>=0 && ny<dimy()) {
 1.11774 +          if (x>=0 && x<dimx()) {
 1.11775 +            const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
 1.11776 +            (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
 1.11777 +          }
 1.11778 +          if (nx>=0 && nx<dimx()) {
 1.11779 +            const float w1 = dx*dy, w2 = add?1:(1-w1);
 1.11780 +            (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
 1.11781 +          }
 1.11782 +        }
 1.11783 +      }
 1.11784 +      return *this;
 1.11785 +    }
 1.11786 +
 1.11787 +    //! Return a reference to the minimum pixel value of the instance image
 1.11788 +    const T& min() const {
 1.11789 +      if (is_empty())
 1.11790 +        throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
 1.11791 +                                    pixel_type());
 1.11792 +      const T *ptrmin = data;
 1.11793 +      T min_value = *ptrmin;
 1.11794 +      cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 1.11795 +      return *ptrmin;
 1.11796 +    }
 1.11797 +
 1.11798 +    //! Return a reference to the minimum pixel value of the instance image
 1.11799 +    T& min() {
 1.11800 +      if (is_empty())
 1.11801 +        throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
 1.11802 +                                    pixel_type());
 1.11803 +      T *ptrmin = data;
 1.11804 +      T min_value = *ptrmin;
 1.11805 +      cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 1.11806 +      return *ptrmin;
 1.11807 +    }
 1.11808 +
 1.11809 +    //! Return a reference to the maximum pixel value of the instance image
 1.11810 +    const T& max() const {
 1.11811 +      if (is_empty())
 1.11812 +        throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
 1.11813 +                                    pixel_type());
 1.11814 +      const T *ptrmax = data;
 1.11815 +      T max_value = *ptrmax;
 1.11816 +      cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 1.11817 +      return *ptrmax;
 1.11818 +    }
 1.11819 +
 1.11820 +    //! Return a reference to the maximum pixel value of the instance image
 1.11821 +    T& max() {
 1.11822 +      if (is_empty())
 1.11823 +        throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
 1.11824 +                                    pixel_type());
 1.11825 +      T *ptrmax = data;
 1.11826 +      T max_value = *ptrmax;
 1.11827 +      cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 1.11828 +      return *ptrmax;
 1.11829 +    }
 1.11830 +
 1.11831 +    //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 1.11832 +    template<typename t>
 1.11833 +    const T& minmax(t& max_val) const {
 1.11834 +      if (is_empty())
 1.11835 +        throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
 1.11836 +                                    pixel_type());
 1.11837 +      const T *ptrmin = data;
 1.11838 +      T min_value = *ptrmin, max_value = min_value;
 1.11839 +      cimg_for(*this,ptr,T) {
 1.11840 +        const T val = *ptr;
 1.11841 +        if (val<min_value) { min_value = val; ptrmin = ptr; }
 1.11842 +        if (val>max_value) max_value = val;
 1.11843 +      }
 1.11844 +      max_val = (t)max_value;
 1.11845 +      return *ptrmin;
 1.11846 +    }
 1.11847 +
 1.11848 +    //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 1.11849 +    template<typename t>
 1.11850 +    T& minmax(t& max_val) {
 1.11851 +      if (is_empty())
 1.11852 +        throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
 1.11853 +                                    pixel_type());
 1.11854 +      T *ptrmin = data;
 1.11855 +      T min_value = *ptrmin, max_value = min_value;
 1.11856 +      cimg_for(*this,ptr,T) {
 1.11857 +        const T val = *ptr;
 1.11858 +        if (val<min_value) { min_value = val; ptrmin = ptr; }
 1.11859 +        if (val>max_value) max_value = val;
 1.11860 +      }
 1.11861 +      max_val = (t)max_value;
 1.11862 +      return *ptrmin;
 1.11863 +    }
 1.11864 +
 1.11865 +    //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 1.11866 +    template<typename t>
 1.11867 +    const T& maxmin(t& min_val) const {
 1.11868 +      if (is_empty())
 1.11869 +        throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
 1.11870 +                                    pixel_type());
 1.11871 +      const T *ptrmax = data;
 1.11872 +      T max_value = *ptrmax, min_value = max_value;
 1.11873 +      cimg_for(*this,ptr,T) {
 1.11874 +        const T val = *ptr;
 1.11875 +        if (val>max_value) { max_value = val; ptrmax = ptr; }
 1.11876 +        if (val<min_value) min_value = val;
 1.11877 +      }
 1.11878 +      min_val = (t)min_value;
 1.11879 +      return *ptrmax;
 1.11880 +    }
 1.11881 +
 1.11882 +    //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 1.11883 +    template<typename t>
 1.11884 +    T& maxmin(t& min_val) {
 1.11885 +      if (is_empty())
 1.11886 +        throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
 1.11887 +                                    pixel_type());
 1.11888 +      T *ptrmax = data;
 1.11889 +      T max_value = *ptrmax, min_value = max_value;
 1.11890 +      cimg_for(*this,ptr,T) {
 1.11891 +        const T val = *ptr;
 1.11892 +        if (val>max_value) { max_value = val; ptrmax = ptr; }
 1.11893 +        if (val<min_value) min_value = val;
 1.11894 +      }
 1.11895 +      min_val = (t)min_value;
 1.11896 +      return *ptrmax;
 1.11897 +    }
 1.11898 +
 1.11899 +    //! Return the sum of all the pixel values in an image.
 1.11900 +    Tfloat sum() const {
 1.11901 +      if (is_empty())
 1.11902 +        throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.11903 +                                                  pixel_type(),width,height,depth,dim,data);
 1.11904 +      Tfloat res = 0;
 1.11905 +      cimg_for(*this,ptr,T) res+=*ptr;
 1.11906 +      return res;
 1.11907 +    }
 1.11908 +
 1.11909 +    //! Return the mean pixel value of the instance image.
 1.11910 +    Tfloat mean() const {
 1.11911 +      if (is_empty())
 1.11912 +        throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",
 1.11913 +                                    pixel_type());
 1.11914 +      Tfloat val = 0;
 1.11915 +      cimg_for(*this,ptr,T) val+=*ptr;
 1.11916 +      return val/size();
 1.11917 +    }
 1.11918 +
 1.11919 +    //! Return the variance of the image.
 1.11920 +    /**
 1.11921 +       @param variance_method Determines how to calculate the variance
 1.11922 +       <table border="0">
 1.11923 +       <tr><td>0</td>
 1.11924 +       <td>Second moment:
 1.11925 +       @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
 1.11926 +       = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
 1.11927 +       with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
 1.11928 +       <tr><td>1</td>
 1.11929 +       <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
 1.11930 +       <tr><td>2</td>
 1.11931 +       <td>Least median of squares</td></tr>
 1.11932 +       <tr><td>3</td>
 1.11933 +       <td>Least trimmed of squares</td></tr>
 1.11934 +       </table>
 1.11935 +    */
 1.11936 +    Tfloat variance(const unsigned int variance_method=1) const {
 1.11937 +      Tfloat foo;
 1.11938 +      return variancemean(variance_method,foo);
 1.11939 +    }
 1.11940 +
 1.11941 +    //! Return the variance and the mean of the image.
 1.11942 +    template<typename t>
 1.11943 +    Tfloat variancemean(const unsigned int variance_method, t& mean) const {
 1.11944 +      if (is_empty())
 1.11945 +        throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",
 1.11946 +                                    pixel_type());
 1.11947 +      Tfloat variance = 0, average = 0;
 1.11948 +      const unsigned int siz = size();
 1.11949 +      switch (variance_method) {
 1.11950 +      case 3 : { // Least trimmed of Squares
 1.11951 +        CImg<Tfloat> buf(*this);
 1.11952 +        const unsigned int siz2 = siz>>1;
 1.11953 +        { cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }}
 1.11954 +        buf.sort();
 1.11955 +        Tfloat a = 0;
 1.11956 +        const Tfloat *ptrs = buf.ptr();
 1.11957 +        for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
 1.11958 +        const Tfloat sig = (Tfloat)(2.6477*cimg_std::sqrt(a/siz2));
 1.11959 +        variance = sig*sig;
 1.11960 +      } break;
 1.11961 +      case 2 : { // Least Median of Squares (MAD)
 1.11962 +        CImg<Tfloat> buf(*this);
 1.11963 +        buf.sort();
 1.11964 +        const unsigned int siz2 = siz>>1;
 1.11965 +        const Tfloat med_i = buf[siz2];
 1.11966 +        cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
 1.11967 +        buf.sort();
 1.11968 +        const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
 1.11969 +        variance = sig*sig;
 1.11970 +      } break;
 1.11971 +      case 1 : { // Least mean square (robust definition)
 1.11972 +        Tfloat S = 0, S2 = 0;
 1.11973 +        cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
 1.11974 +        variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
 1.11975 +        average = S;
 1.11976 +      } break;
 1.11977 +      case 0 :{ // Least mean square (standard definition)
 1.11978 +        Tfloat S = 0, S2 = 0;
 1.11979 +        cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
 1.11980 +        variance = (S2 - S*S/siz)/siz;
 1.11981 +        average = S;
 1.11982 +      } break;
 1.11983 +      default :
 1.11984 +        throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
 1.11985 +                                    pixel_type(),variance_method);
 1.11986 +      }
 1.11987 +      mean = (t)(average/siz);
 1.11988 +      return variance>0?variance:0;
 1.11989 +    }
 1.11990 +
 1.11991 +    //! Return the kth smallest element of the image.
 1.11992 +    // (Adapted from the numerical recipies for CImg)
 1.11993 +    T kth_smallest(const unsigned int k) const {
 1.11994 +      if (is_empty())
 1.11995 +        throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.11996 +                                    pixel_type(),width,height,depth,dim,data);
 1.11997 +      CImg<T> arr(*this);
 1.11998 +      unsigned long l = 0, ir = size()-1;
 1.11999 +      for (;;) {
 1.12000 +        if (ir<=l+1) {
 1.12001 +          if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
 1.12002 +          return arr[k];
 1.12003 +        } else {
 1.12004 +          const unsigned long mid = (l+ir)>>1;
 1.12005 +          cimg::swap(arr[mid],arr[l+1]);
 1.12006 +          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
 1.12007 +          if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
 1.12008 +          if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
 1.12009 +          unsigned long i = l+1, j = ir;
 1.12010 +          const T pivot = arr[l+1];
 1.12011 +          for (;;) {
 1.12012 +            do ++i; while (arr[i]<pivot);
 1.12013 +            do --j; while (arr[j]>pivot);
 1.12014 +            if (j<i) break;
 1.12015 +            cimg::swap(arr[i],arr[j]);
 1.12016 +          }
 1.12017 +          arr[l+1] = arr[j];
 1.12018 +          arr[j] = pivot;
 1.12019 +          if (j>=k) ir=j-1;
 1.12020 +          if (j<=k) l=i;
 1.12021 +        }
 1.12022 +      }
 1.12023 +      return 0;
 1.12024 +    }
 1.12025 +
 1.12026 +    //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
 1.12027 +    CImg<T>& stats(const unsigned int variance_method=1) {
 1.12028 +      return get_stats(variance_method).transfer_to(*this);
 1.12029 +    }
 1.12030 +
 1.12031 +    CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
 1.12032 +      if (is_empty()) return CImg<Tfloat>();
 1.12033 +      const unsigned long siz = size();
 1.12034 +      const T *const odata = data;
 1.12035 +      const T *pm = odata, *pM = odata;
 1.12036 +      Tfloat S = 0, S2 = 0;
 1.12037 +      T m = *pm, M = m;
 1.12038 +      cimg_for(*this,ptr,T) {
 1.12039 +        const T val = *ptr;
 1.12040 +        const Tfloat fval = (Tfloat)val;
 1.12041 +        if (val<m) { m = val; pm = ptr; }
 1.12042 +        if (val>M) { M = val; pM = ptr; }
 1.12043 +        S+=fval;
 1.12044 +        S2+=fval*fval;
 1.12045 +      }
 1.12046 +      const Tfloat
 1.12047 +        mean_value = S/siz,
 1.12048 +        _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
 1.12049 +        (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
 1.12050 +         variance(variance_method)),
 1.12051 +        variance_value = _variance_value>0?_variance_value:0;
 1.12052 +      int
 1.12053 +        xm = 0, ym = 0, zm = 0, vm = 0,
 1.12054 +        xM = 0, yM = 0, zM = 0, vM = 0;
 1.12055 +      contains(*pm,xm,ym,zm,vm);
 1.12056 +      contains(*pM,xM,yM,zM,vM);
 1.12057 +      return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
 1.12058 +                                     (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
 1.12059 +                                     (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
 1.12060 +    }
 1.12061 +
 1.12062 +    //! Return the median value of the image.
 1.12063 +    T median() const {
 1.12064 +      const unsigned int s = size();
 1.12065 +      const T res = kth_smallest(s>>1);
 1.12066 +      return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
 1.12067 +    }
 1.12068 +
 1.12069 +    //! Compute the MSE (Mean-Squared Error) between two images.
 1.12070 +    template<typename t>
 1.12071 +    Tfloat MSE(const CImg<t>& img) const {
 1.12072 +      if (img.size()!=size())
 1.12073 +        throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
 1.12074 +                                    pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
 1.12075 +
 1.12076 +      Tfloat vMSE = 0;
 1.12077 +      const t* ptr2 = img.end();
 1.12078 +      cimg_for(*this,ptr1,T) {
 1.12079 +        const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
 1.12080 +        vMSE += diff*diff;
 1.12081 +      }
 1.12082 +      vMSE/=img.size();
 1.12083 +      return vMSE;
 1.12084 +    }
 1.12085 +
 1.12086 +    //! Compute the PSNR between two images.
 1.12087 +    template<typename t>
 1.12088 +    Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
 1.12089 +      const Tfloat vMSE = (Tfloat)cimg_std::sqrt(MSE(img));
 1.12090 +      return (vMSE!=0)?(Tfloat)(20*cimg_std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
 1.12091 +    }
 1.12092 +
 1.12093 +    //! Return the trace of the image, viewed as a matrix.
 1.12094 +    Tfloat trace() const {
 1.12095 +      if (is_empty())
 1.12096 +        throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
 1.12097 +                                    pixel_type(),width,height,depth,dim,data);
 1.12098 +      Tfloat res = 0;
 1.12099 +      cimg_forX(*this,k) res+=(*this)(k,k);
 1.12100 +      return res;
 1.12101 +    }
 1.12102 +
 1.12103 +    //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
 1.12104 +    template<typename t>
 1.12105 +    Tfloat dot(const CImg<t>& img) const {
 1.12106 +      if (is_empty())
 1.12107 +        throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
 1.12108 +                                    pixel_type(),width,height,depth,dim,data);
 1.12109 +      if (!img)
 1.12110 +        throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
 1.12111 +                                    pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
 1.12112 +      const unsigned long nb = cimg::min(size(),img.size());
 1.12113 +      Tfloat res = 0;
 1.12114 +      for (unsigned long off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
 1.12115 +      return res;
 1.12116 +    }
 1.12117 +
 1.12118 +    //! Return the determinant of the image, viewed as a matrix.
 1.12119 +    Tfloat det() const {
 1.12120 +      if (is_empty() || width!=height || depth!=1 || dim!=1)
 1.12121 +        throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
 1.12122 +                                    pixel_type(),width,height,depth,dim,data);
 1.12123 +      switch (width) {
 1.12124 +      case 1 : return (Tfloat)((*this)(0,0));
 1.12125 +      case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
 1.12126 +      case 3 : {
 1.12127 +        const Tfloat
 1.12128 +          a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
 1.12129 +          b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
 1.12130 +          c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
 1.12131 +        return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
 1.12132 +      }
 1.12133 +      default : {
 1.12134 +        CImg<Tfloat> lu(*this);
 1.12135 +        CImg<uintT> indx;
 1.12136 +        bool d;
 1.12137 +        lu._LU(indx,d);
 1.12138 +        Tfloat res = d?(Tfloat)1:(Tfloat)-1;
 1.12139 +        cimg_forX(lu,i) res*=lu(i,i);
 1.12140 +        return res;
 1.12141 +      }
 1.12142 +      }
 1.12143 +      return 0;
 1.12144 +    }
 1.12145 +
 1.12146 +    //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
 1.12147 +    Tfloat norm(const int norm_type=2) const {
 1.12148 +      if (is_empty())
 1.12149 +        throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
 1.12150 +                                    pixel_type(),width,height,depth,dim,data);
 1.12151 +      Tfloat res = 0;
 1.12152 +      switch (norm_type) {
 1.12153 +      case -1 : {
 1.12154 +        cimg_foroff(*this,off) {
 1.12155 +          const Tfloat tmp = cimg::abs((Tfloat)data[off]);
 1.12156 +          if (tmp>res) res = tmp;
 1.12157 +        }
 1.12158 +        return res;
 1.12159 +      } break;
 1.12160 +      case 1 : {
 1.12161 +        cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
 1.12162 +        return res;
 1.12163 +      } break;
 1.12164 +      case 2 : return (Tfloat)cimg_std::sqrt(dot(*this)); break;
 1.12165 +      default :
 1.12166 +        throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
 1.12167 +                                    pixel_type(),norm_type);
 1.12168 +      }
 1.12169 +      return 0;
 1.12170 +    }
 1.12171 +
 1.12172 +    //! Return a C-string containing the values of the instance image.
 1.12173 +    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
 1.12174 +      if (is_empty()) return CImg<charT>(1,1,1,1,0);
 1.12175 +      const unsigned int siz = (unsigned int)size();
 1.12176 +      CImgList<charT> items;
 1.12177 +      char item[256] = { 0 };
 1.12178 +      const T *ptrs = ptr();
 1.12179 +      for (unsigned int off = 0; off<siz-1; ++off) {
 1.12180 +        cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
 1.12181 +        const int l = cimg::strlen(item);
 1.12182 +        items.insert(CImg<charT>(item,l+1));
 1.12183 +        items[items.size-1](l) = separator;
 1.12184 +      }
 1.12185 +      cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
 1.12186 +      items.insert(CImg<charT>(item,cimg::strlen(item)+1));
 1.12187 +      CImg<ucharT> res = items.get_append('x');
 1.12188 +      if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
 1.12189 +      return res;
 1.12190 +    }
 1.12191 +
 1.12192 +    //! Display informations about the image on the standard error output.
 1.12193 +    /**
 1.12194 +       \param title Name for the considered image (optional).
 1.12195 +       \param display_stats Compute and display image statistics (optional).
 1.12196 +    **/
 1.12197 +    const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
 1.12198 +      int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
 1.12199 +      static CImg<doubleT> st;
 1.12200 +      if (!is_empty() && display_stats) {
 1.12201 +        st = get_stats();
 1.12202 +        xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
 1.12203 +        xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
 1.12204 +      }
 1.12205 +      const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
 1.12206 +      const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
 1.12207 +      char ntitle[64] = { 0 };
 1.12208 +      if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 1.12209 +      cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
 1.12210 +                   title?title:ntitle,(void*)this,width,height,depth,dim,
 1.12211 +                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 1.12212 +                   mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 1.12213 +                   pixel_type(),(void*)data,is_shared?"shared":"not shared");
 1.12214 +      if (!is_empty()) cimg_foroff(*this,off) {
 1.12215 +        cimg_std::fprintf(cimg_stdout,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
 1.12216 +        if (off!=siz1) cimg_std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
 1.12217 +        if (off==7 && siz>16) { off = siz1-8; if (off!=7) cimg_std::fprintf(cimg_stdout,"... "); }
 1.12218 +      }
 1.12219 +      if (!is_empty() && display_stats)
 1.12220 +        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",
 1.12221 +                     st[0],st[1],st[2],cimg_std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
 1.12222 +      else cimg_std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
 1.12223 +      return *this;
 1.12224 +    }
 1.12225 +
 1.12226 +    //@}
 1.12227 +    //------------------------------------------
 1.12228 +    //
 1.12229 +    //! \name Arithmetic and Boolean Operators
 1.12230 +    //@{
 1.12231 +    //------------------------------------------
 1.12232 +
 1.12233 +    //! Assignment operator.
 1.12234 +    /**
 1.12235 +       This operator assigns a copy of the input image \p img to the current instance image.
 1.12236 +       \param img The input image to copy.
 1.12237 +       \remark
 1.12238 +       - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
 1.12239 +    **/
 1.12240 +    template<typename t>
 1.12241 +    CImg<T>& operator=(const CImg<t>& img) {
 1.12242 +      return assign(img);
 1.12243 +    }
 1.12244 +
 1.12245 +    CImg<T>& operator=(const CImg<T>& img) {
 1.12246 +      return assign(img);
 1.12247 +    }
 1.12248 +
 1.12249 +    //! Assign values of a C-array to the instance image.
 1.12250 +    /**
 1.12251 +       \param buf Pointer to a C-style array having a size of (at least) <tt>this->size()</tt>.
 1.12252 +
 1.12253 +       - Replace pixel values by the content of the array \c buf.
 1.12254 +       - Warning : the value types in the array and in the image must be the same.
 1.12255 +
 1.12256 +       \par example:
 1.12257 +       \code
 1.12258 +       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.
 1.12259 +       CImg<float> matrice(4,4);                                        // Define a 4x4 greyscale image.
 1.12260 +       matrice = tab;                                                   // Fill the image by the values in tab.
 1.12261 +       \endcode
 1.12262 +    **/
 1.12263 +    CImg<T>& operator=(const T *buf) {
 1.12264 +      return assign(buf,width,height,depth,dim);
 1.12265 +    }
 1.12266 +
 1.12267 +    //! Assign a value to each image pixel of the instance image.
 1.12268 +    CImg<T>& operator=(const T val) {
 1.12269 +      return fill(val);
 1.12270 +    }
 1.12271 +
 1.12272 +    //! Operator+
 1.12273 +    /**
 1.12274 +       \remark
 1.12275 +       - This operator can be used to get a non-shared copy of an image.
 1.12276 +    **/
 1.12277 +    CImg<T> operator+() const {
 1.12278 +      return CImg<T>(*this,false);
 1.12279 +    }
 1.12280 +
 1.12281 +    //! Operator+=;
 1.12282 +#ifdef cimg_use_visualcpp6
 1.12283 +    CImg<T>& operator+=(const T val)
 1.12284 +#else
 1.12285 +    template<typename t>
 1.12286 +    CImg<T>& operator+=(const t val)
 1.12287 +#endif
 1.12288 +    {
 1.12289 +      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
 1.12290 +      return *this;
 1.12291 +    }
 1.12292 +
 1.12293 +    //! Operator+=
 1.12294 +    template<typename t>
 1.12295 +    CImg<T>& operator+=(const CImg<t>& img) {
 1.12296 +      if (is_overlapped(img)) return *this+=+img;
 1.12297 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12298 +      t *ptrs = img.data + smin;
 1.12299 +      for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
 1.12300 +      return *this;
 1.12301 +    }
 1.12302 +
 1.12303 +    //! Operator++ (prefix)
 1.12304 +    CImg<T>& operator++() {
 1.12305 +      cimg_for(*this,ptr,T) ++(*ptr);
 1.12306 +      return *this;
 1.12307 +    }
 1.12308 +
 1.12309 +    //! Operator++ (postfix)
 1.12310 +    CImg<T> operator++(int) {
 1.12311 +      const CImg<T> copy(*this,false);
 1.12312 +      ++*this;
 1.12313 +      return copy;
 1.12314 +    }
 1.12315 +
 1.12316 +    //! Operator-.
 1.12317 +    CImg<T> operator-() const {
 1.12318 +      return CImg<T>(width,height,depth,dim,0)-=*this;
 1.12319 +    }
 1.12320 +
 1.12321 +    //! Operator-=.
 1.12322 +#ifdef cimg_use_visualcpp6
 1.12323 +    CImg<T>& operator-=(const T val)
 1.12324 +#else
 1.12325 +    template<typename t>
 1.12326 +    CImg<T>& operator-=(const t val)
 1.12327 +#endif
 1.12328 +    {
 1.12329 +      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
 1.12330 +      return *this;
 1.12331 +    }
 1.12332 +
 1.12333 +    //! Operator-=.
 1.12334 +    template<typename t>
 1.12335 +    CImg<T>& operator-=(const CImg<t>& img) {
 1.12336 +      if (is_overlapped(img)) return *this-=+img;
 1.12337 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12338 +      t *ptrs = img.data+smin;
 1.12339 +      for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
 1.12340 +      return *this;
 1.12341 +    }
 1.12342 +
 1.12343 +    //! Operator-- (prefix).
 1.12344 +    CImg<T>& operator--() {
 1.12345 +      cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
 1.12346 +      return *this;
 1.12347 +    }
 1.12348 +
 1.12349 +    //! Operator-- (postfix).
 1.12350 +    CImg<T> operator--(int) {
 1.12351 +      CImg<T> copy(*this,false);
 1.12352 +      --*this;
 1.12353 +      return copy;
 1.12354 +    }
 1.12355 +
 1.12356 +    //! Operator*=.
 1.12357 +#ifdef cimg_use_visualcpp6
 1.12358 +    CImg<T>& operator*=(const double val)
 1.12359 +#else
 1.12360 +    template<typename t>
 1.12361 +    CImg<T>& operator*=(const t val)
 1.12362 +#endif
 1.12363 +    {
 1.12364 +      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
 1.12365 +      return *this;
 1.12366 +    }
 1.12367 +
 1.12368 +    //! Operator*=.
 1.12369 +    template<typename t>
 1.12370 +    CImg<T>& operator*=(const CImg<t>& img) {
 1.12371 +      return ((*this)*img).transfer_to(*this);
 1.12372 +    }
 1.12373 +
 1.12374 +    //! Operator/=.
 1.12375 +#ifdef cimg_use_visualcpp6
 1.12376 +    CImg<T>& operator/=(const double val)
 1.12377 +#else
 1.12378 +    template<typename t>
 1.12379 +    CImg<T>& operator/=(const t val)
 1.12380 +#endif
 1.12381 +    {
 1.12382 +      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
 1.12383 +      return *this;
 1.12384 +    }
 1.12385 +
 1.12386 +    //! Operator/=.
 1.12387 +    template<typename t>
 1.12388 +    CImg<T>& operator/=(const CImg<t>& img) {
 1.12389 +      return assign(*this*img.get_invert());
 1.12390 +    }
 1.12391 +
 1.12392 +    //! Modulo.
 1.12393 +    template<typename t>
 1.12394 +    CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
 1.12395 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12396 +      return CImg<Tt>(*this,false)%=img;
 1.12397 +    }
 1.12398 +
 1.12399 +    //! Modulo.
 1.12400 +    CImg<T> operator%(const T val) const {
 1.12401 +      return (+*this)%=val;
 1.12402 +    }
 1.12403 +
 1.12404 +    //! In-place modulo.
 1.12405 +    CImg<T>& operator%=(const T val) {
 1.12406 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
 1.12407 +      return *this;
 1.12408 +    }
 1.12409 +
 1.12410 +    //! In-place modulo.
 1.12411 +    template<typename t>
 1.12412 +    CImg<T>& operator%=(const CImg<t>& img) {
 1.12413 +      if (is_overlapped(img)) return *this%=+img;
 1.12414 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12415 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12416 +      const t *ptrs = img.data + smin;
 1.12417 +      for (T *ptrd = data + smin; ptrd>data; ) {
 1.12418 +        T& val = *(--ptrd);
 1.12419 +        val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
 1.12420 +      }
 1.12421 +      return *this;
 1.12422 +    }
 1.12423 +
 1.12424 +    //! Bitwise AND.
 1.12425 +    template<typename t>
 1.12426 +    CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
 1.12427 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12428 +      return CImg<Tt>(*this,false)&=img;
 1.12429 +    }
 1.12430 +
 1.12431 +    //! Bitwise AND.
 1.12432 +    CImg<T> operator&(const T val) const {
 1.12433 +      return (+*this)&=val;
 1.12434 +    }
 1.12435 +
 1.12436 +    //! In-place bitwise AND.
 1.12437 +    template<typename t>
 1.12438 +    CImg<T>& operator&=(const CImg<t>& img) {
 1.12439 +      if (is_overlapped(img)) return *this&=+img;
 1.12440 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12441 +      const t *ptrs = img.data + smin;
 1.12442 +      for (T *ptrd = data + smin; ptrd>data; ) {
 1.12443 +        T& val = *(--ptrd);
 1.12444 +        val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
 1.12445 +      }
 1.12446 +      return *this;
 1.12447 +    }
 1.12448 +
 1.12449 +    //! In-place bitwise AND.
 1.12450 +    CImg<T>& operator&=(const T val) {
 1.12451 +      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
 1.12452 +      return *this;
 1.12453 +    }
 1.12454 +
 1.12455 +    //! Bitwise OR.
 1.12456 +    template<typename t>
 1.12457 +    CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
 1.12458 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12459 +      return CImg<Tt>(*this,false)|=img;
 1.12460 +    }
 1.12461 +
 1.12462 +    //! Bitwise OR.
 1.12463 +    CImg<T> operator|(const T val) const {
 1.12464 +      return (+*this)|=val;
 1.12465 +    }
 1.12466 +
 1.12467 +    //! In-place bitwise OR.
 1.12468 +    template<typename t>
 1.12469 +    CImg<T>& operator|=(const CImg<t>& img) {
 1.12470 +      if (is_overlapped(img)) return *this|=+img;
 1.12471 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12472 +      const t *ptrs = img.data + smin;
 1.12473 +      for (T *ptrd = data + smin; ptrd>data; ) {
 1.12474 +        T& val = *(--ptrd);
 1.12475 +        val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
 1.12476 +      }
 1.12477 +      return *this;
 1.12478 +    }
 1.12479 +
 1.12480 +    //! In-place bitwise OR.
 1.12481 +    CImg<T>& operator|=(const T val) {
 1.12482 +      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
 1.12483 +      return *this;
 1.12484 +    }
 1.12485 +
 1.12486 +    //! Bitwise XOR.
 1.12487 +    template<typename t>
 1.12488 +    CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
 1.12489 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12490 +      return CImg<Tt>(*this,false)^=img;
 1.12491 +    }
 1.12492 +
 1.12493 +    //! Bitwise XOR.
 1.12494 +    CImg<T> operator^(const T val) const {
 1.12495 +      return (+*this)^=val;
 1.12496 +    }
 1.12497 +
 1.12498 +    //! In-place bitwise XOR.
 1.12499 +    template<typename t>
 1.12500 +    CImg<T>& operator^=(const CImg<t>& img) {
 1.12501 +      if (is_overlapped(img)) return *this^=+img;
 1.12502 +      const unsigned int smin = cimg::min(size(),img.size());
 1.12503 +      const t *ptrs = img.data + smin;
 1.12504 +      for (T *ptrd = data+smin; ptrd>data; ) {
 1.12505 +        T& val = *(--ptrd);
 1.12506 +        val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
 1.12507 +      }
 1.12508 +      return *this;
 1.12509 +    }
 1.12510 +
 1.12511 +    //! In-place bitwise XOR.
 1.12512 +    CImg<T>& operator^=(const T val) {
 1.12513 +      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
 1.12514 +      return *this;
 1.12515 +    }
 1.12516 +
 1.12517 +    //! Bitwise NOT.
 1.12518 +    CImg<T> operator~() const {
 1.12519 +      CImg<T> res(width,height,depth,dim);
 1.12520 +      const T *ptrs = end();
 1.12521 +      cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
 1.12522 +      return res;
 1.12523 +    }
 1.12524 +
 1.12525 +    //! Bitwise left shift.
 1.12526 +    CImg<T>& operator<<=(const int n) {
 1.12527 +      cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
 1.12528 +      return *this;
 1.12529 +    }
 1.12530 +
 1.12531 +    //! Bitwise left shift.
 1.12532 +    CImg<T> operator<<(const int n) const {
 1.12533 +      return (+*this)<<=n;
 1.12534 +    }
 1.12535 +
 1.12536 +    //! Bitwise right shift.
 1.12537 +    CImg<T>& operator>>=(const int n) {
 1.12538 +      cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
 1.12539 +      return *this;
 1.12540 +    }
 1.12541 +
 1.12542 +    //! Bitwise right shift.
 1.12543 +    CImg<T> operator>>(const int n) const {
 1.12544 +      return (+*this)>>=n;
 1.12545 +    }
 1.12546 +
 1.12547 +    //! Boolean equality.
 1.12548 +    template<typename t>
 1.12549 +    bool operator==(const CImg<t>& img) const {
 1.12550 +      const unsigned int siz = size();
 1.12551 +      bool vequal = true;
 1.12552 +      if (siz!=img.size()) return false;
 1.12553 +      t *ptrs = img.data + siz;
 1.12554 +      for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
 1.12555 +      return vequal;
 1.12556 +    }
 1.12557 +
 1.12558 +    //! Boolean difference.
 1.12559 +    template<typename t>
 1.12560 +    bool operator!=(const CImg<t>& img) const {
 1.12561 +      return !((*this)==img);
 1.12562 +    }
 1.12563 +
 1.12564 +    //! Return a list of two images { *this, img }.
 1.12565 +    template<typename t>
 1.12566 +    CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
 1.12567 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12568 +      return CImgList<Tt>(*this,img);
 1.12569 +    }
 1.12570 +
 1.12571 +    //! Return a copy of \p list, where image *this has been inserted at first position.
 1.12572 +    template<typename t>
 1.12573 +    CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
 1.12574 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12575 +      return CImgList<Tt>(list).insert(*this,0);
 1.12576 +    }
 1.12577 +
 1.12578 +    //! Return a list of two images { *this, img }.
 1.12579 +    template<typename t>
 1.12580 +    CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
 1.12581 +      return (*this)<<img;
 1.12582 +    }
 1.12583 +
 1.12584 +    //! Insert an image into the begining of an image list.
 1.12585 +    template<typename t>
 1.12586 +    CImgList<t>& operator>>(const CImgList<t>& list) const {
 1.12587 +      return list.insert(*this,0);
 1.12588 +    }
 1.12589 +
 1.12590 +    //! Display an image into a CImgDisplay.
 1.12591 +    const CImg<T>& operator>>(CImgDisplay& disp) const {
 1.12592 +      return display(disp);
 1.12593 +    }
 1.12594 +
 1.12595 +    //@}
 1.12596 +    //---------------------------------------
 1.12597 +    //
 1.12598 +    //! \name Usual Mathematics Functions
 1.12599 +    //@{
 1.12600 +    //---------------------------------------
 1.12601 +
 1.12602 +    //! Apply a R->R function on all pixel values.
 1.12603 +    template<typename t>
 1.12604 +    CImg<T>& apply(t& func) {
 1.12605 +      cimg_for(*this,ptr,T) *ptr = func(*ptr);
 1.12606 +      return *this;
 1.12607 +    }
 1.12608 +
 1.12609 +    template<typename t>
 1.12610 +    CImg<T> get_apply(t& func) const {
 1.12611 +      return (+*this).apply(func);
 1.12612 +    }
 1.12613 +
 1.12614 +    //! Pointwise multiplication between two images.
 1.12615 +    template<typename t>
 1.12616 +    CImg<T>& mul(const CImg<t>& img) {
 1.12617 +      if (is_overlapped(img)) return mul(+img);
 1.12618 +      t *ptrs = img.data;
 1.12619 +      T *ptrf = data + cimg::min(size(),img.size());
 1.12620 +      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
 1.12621 +      return *this;
 1.12622 +    }
 1.12623 +
 1.12624 +    template<typename t>
 1.12625 +    CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
 1.12626 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12627 +      return CImg<Tt>(*this,false).mul(img);
 1.12628 +    }
 1.12629 +
 1.12630 +    //! Pointwise division between two images.
 1.12631 +    template<typename t>
 1.12632 +    CImg<T>& div(const CImg<t>& img) {
 1.12633 +      if (is_overlapped(img)) return div(+img);
 1.12634 +      t *ptrs = img.data;
 1.12635 +      T *ptrf = data + cimg::min(size(),img.size());
 1.12636 +      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
 1.12637 +      return *this;
 1.12638 +    }
 1.12639 +
 1.12640 +    template<typename t>
 1.12641 +    CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
 1.12642 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12643 +      return CImg<Tt>(*this,false).div(img);
 1.12644 +    }
 1.12645 +
 1.12646 +    //! Pointwise max operator between two images.
 1.12647 +    template<typename t>
 1.12648 +    CImg<T>& max(const CImg<t>& img) {
 1.12649 +      if (is_overlapped(img)) return max(+img);
 1.12650 +      t *ptrs = img.data;
 1.12651 +      T *ptrf = data + cimg::min(size(),img.size());
 1.12652 +      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
 1.12653 +      return *this;
 1.12654 +    }
 1.12655 +
 1.12656 +    template<typename t>
 1.12657 +    CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
 1.12658 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12659 +      return CImg<Tt>(*this,false).max(img);
 1.12660 +    }
 1.12661 +
 1.12662 +    //! Pointwise max operator between an image and a value.
 1.12663 +    CImg<T>& max(const T val) {
 1.12664 +      cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
 1.12665 +      return *this;
 1.12666 +    }
 1.12667 +
 1.12668 +    CImg<T> get_max(const T val) const {
 1.12669 +      return (+*this).max(val);
 1.12670 +    }
 1.12671 +
 1.12672 +    //! Pointwise min operator between two images.
 1.12673 +    template<typename t>
 1.12674 +    CImg<T>& min(const CImg<t>& img) {
 1.12675 +      if (is_overlapped(img)) return min(+img);
 1.12676 +      t *ptrs = img.data;
 1.12677 +      T *ptrf = data + cimg::min(size(),img.size());
 1.12678 +      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
 1.12679 +      return *this;
 1.12680 +    }
 1.12681 +
 1.12682 +    template<typename t>
 1.12683 +    CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
 1.12684 +      typedef typename cimg::superset<T,t>::type Tt;
 1.12685 +      return CImg<Tt>(*this,false).min(img);
 1.12686 +    }
 1.12687 +
 1.12688 +    //! Pointwise min operator between an image and a value.
 1.12689 +    CImg<T>& min(const T val) {
 1.12690 +      cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
 1.12691 +      return *this;
 1.12692 +    }
 1.12693 +
 1.12694 +    CImg<T> get_min(const T val) const {
 1.12695 +      return (+*this).min(val);
 1.12696 +    }
 1.12697 +
 1.12698 +    //! Compute the square value of each pixel.
 1.12699 +    CImg<T>& sqr() {
 1.12700 +      cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
 1.12701 +      return *this;
 1.12702 +    }
 1.12703 +
 1.12704 +    CImg<Tfloat> get_sqr() const {
 1.12705 +      return CImg<Tfloat>(*this,false).sqr();
 1.12706 +    }
 1.12707 +
 1.12708 +    //! Compute the square root of each pixel value.
 1.12709 +    CImg<T>& sqrt() {
 1.12710 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sqrt((double)(*ptr));
 1.12711 +      return *this;
 1.12712 +    }
 1.12713 +
 1.12714 +    CImg<Tfloat> get_sqrt() const {
 1.12715 +      return CImg<Tfloat>(*this,false).sqrt();
 1.12716 +    }
 1.12717 +
 1.12718 +    //! Compute the exponential of each pixel value.
 1.12719 +    CImg<T>& exp() {
 1.12720 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::exp((double)(*ptr));
 1.12721 +      return *this;
 1.12722 +    }
 1.12723 +
 1.12724 +    CImg<Tfloat> get_exp() const {
 1.12725 +      return CImg<Tfloat>(*this,false).exp();
 1.12726 +    }
 1.12727 +
 1.12728 +    //! Compute the log of each each pixel value.
 1.12729 +    CImg<T>& log() {
 1.12730 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log((double)(*ptr));
 1.12731 +      return *this;
 1.12732 +    }
 1.12733 +
 1.12734 +    CImg<Tfloat> get_log() const {
 1.12735 +      return CImg<Tfloat>(*this,false).log();
 1.12736 +    }
 1.12737 +
 1.12738 +    //! Compute the log10 of each each pixel value.
 1.12739 +    CImg<T>& log10() {
 1.12740 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log10((double)(*ptr));
 1.12741 +      return *this;
 1.12742 +    }
 1.12743 +
 1.12744 +    CImg<Tfloat> get_log10() const {
 1.12745 +      return CImg<Tfloat>(*this,false).log10();
 1.12746 +    }
 1.12747 +
 1.12748 +    //! Compute the power by p of each pixel value.
 1.12749 +    CImg<T>& pow(const double p) {
 1.12750 +      if (p==0) return fill(1);
 1.12751 +      if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)cimg_std::sqrt((double)val); } return *this; }
 1.12752 +      if (p==1) return *this;
 1.12753 +      if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
 1.12754 +      if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
 1.12755 +      if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
 1.12756 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::pow((double)(*ptr),p);
 1.12757 +      return *this;
 1.12758 +    }
 1.12759 +
 1.12760 +    CImg<Tfloat> get_pow(const double p) const {
 1.12761 +      return CImg<Tfloat>(*this,false).pow(p);
 1.12762 +    }
 1.12763 +
 1.12764 +    //! Compute the power of each pixel value.
 1.12765 +    template<typename t>
 1.12766 +    CImg<T>& pow(const CImg<t>& img) {
 1.12767 +      if (is_overlapped(img)) return pow(+img);
 1.12768 +      t *ptrs = img.data;
 1.12769 +      T *ptrf = data + cimg::min(size(),img.size());
 1.12770 +      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)cimg_std::pow((double)*ptrd,(double)(*(ptrs++)));
 1.12771 +      return *this;
 1.12772 +    }
 1.12773 +
 1.12774 +    template<typename t>
 1.12775 +    CImg<Tfloat> get_pow(const CImg<t>& img) const {
 1.12776 +      return CImg<Tfloat>(*this,false).pow(img);
 1.12777 +    }
 1.12778 +
 1.12779 +    //! Compute the absolute value of each pixel value.
 1.12780 +    CImg<T>& abs() {
 1.12781 +      cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
 1.12782 +      return *this;
 1.12783 +    }
 1.12784 +
 1.12785 +    CImg<Tfloat> get_abs() const {
 1.12786 +      return CImg<Tfloat>(*this,false).abs();
 1.12787 +    }
 1.12788 +
 1.12789 +    //! Compute the cosinus of each pixel value.
 1.12790 +    CImg<T>& cos() {
 1.12791 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::cos((double)(*ptr));
 1.12792 +      return *this;
 1.12793 +    }
 1.12794 +
 1.12795 +    CImg<Tfloat> get_cos() const {
 1.12796 +      return CImg<Tfloat>(*this,false).cos();
 1.12797 +    }
 1.12798 +
 1.12799 +    //! Compute the sinus of each pixel value.
 1.12800 +    CImg<T>& sin() {
 1.12801 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sin((double)(*ptr));
 1.12802 +      return *this;
 1.12803 +    }
 1.12804 +
 1.12805 +    CImg<Tfloat> get_sin() const {
 1.12806 +      return CImg<Tfloat>(*this,false).sin();
 1.12807 +    }
 1.12808 +
 1.12809 +    //! Compute the tangent of each pixel.
 1.12810 +    CImg<T>& tan() {
 1.12811 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::tan((double)(*ptr));
 1.12812 +      return *this;
 1.12813 +    }
 1.12814 +
 1.12815 +    CImg<Tfloat> get_tan() const {
 1.12816 +      return CImg<Tfloat>(*this,false).tan();
 1.12817 +    }
 1.12818 +
 1.12819 +    //! Compute the arc-cosine of each pixel value.
 1.12820 +    CImg<T>& acos() {
 1.12821 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::acos((double)(*ptr));
 1.12822 +      return *this;
 1.12823 +    }
 1.12824 +
 1.12825 +    CImg<Tfloat> get_acos() const {
 1.12826 +      return CImg<Tfloat>(*this,false).acos();
 1.12827 +    }
 1.12828 +
 1.12829 +    //! Compute the arc-sinus of each pixel value.
 1.12830 +    CImg<T>& asin() {
 1.12831 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::asin((double)(*ptr));
 1.12832 +      return *this;
 1.12833 +    }
 1.12834 +
 1.12835 +    CImg<Tfloat> get_asin() const {
 1.12836 +      return CImg<Tfloat>(*this,false).asin();
 1.12837 +    }
 1.12838 +
 1.12839 +    //! Compute the arc-tangent of each pixel.
 1.12840 +    CImg<T>& atan() {
 1.12841 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::atan((double)(*ptr));
 1.12842 +      return *this;
 1.12843 +    }
 1.12844 +
 1.12845 +    CImg<Tfloat> get_atan() const {
 1.12846 +      return CImg<Tfloat>(*this,false).atan();
 1.12847 +    }
 1.12848 +
 1.12849 +    //! Compute image with rounded pixel values.
 1.12850 +    /**
 1.12851 +       \param x Rounding precision.
 1.12852 +       \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
 1.12853 +    **/
 1.12854 +    CImg<T>& round(const float x, const int rounding_type=0) {
 1.12855 +      cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
 1.12856 +      return *this;
 1.12857 +    }
 1.12858 +
 1.12859 +    CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
 1.12860 +      return (+*this).round(x,rounding_type);
 1.12861 +    }
 1.12862 +
 1.12863 +    //! Fill the instance image with random values between specified range.
 1.12864 +    CImg<T>& rand(const T val_min, const T val_max) {
 1.12865 +      const float delta = (float)val_max - (float)val_min;
 1.12866 +      cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
 1.12867 +      return *this;
 1.12868 +    }
 1.12869 +
 1.12870 +    CImg<T> get_rand(const T val_min, const T val_max) const {
 1.12871 +      return (+*this).rand(val_min,val_max);
 1.12872 +    }
 1.12873 +
 1.12874 +    //@}
 1.12875 +    //-----------------------------------
 1.12876 +    //
 1.12877 +    //! \name Usual Image Transformations
 1.12878 +    //@{
 1.12879 +    //-----------------------------------
 1.12880 +
 1.12881 +    //! Fill an image by a value \p val.
 1.12882 +    /**
 1.12883 +       \param val = fill value
 1.12884 +       \note All pixel values of the instance image will be initialized by \p val.
 1.12885 +    **/
 1.12886 +    CImg<T>& fill(const T val) {
 1.12887 +      if (is_empty()) return *this;
 1.12888 +      if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
 1.12889 +      else cimg_std::memset(data,(int)val,size()*sizeof(T));
 1.12890 +      return *this;
 1.12891 +    }
 1.12892 +
 1.12893 +    CImg<T> get_fill(const T val) const {
 1.12894 +      return CImg<T>(width,height,depth,dim).fill(val);
 1.12895 +    }
 1.12896 +
 1.12897 +    //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
 1.12898 +    CImg<T>& fill(const T val0, const T val1) {
 1.12899 +      if (is_empty()) return *this;
 1.12900 +      T *ptr, *ptr_end = end()-1;
 1.12901 +      for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
 1.12902 +      if (ptr!=ptr_end+1) *(ptr++) = val0;
 1.12903 +      return *this;
 1.12904 +    }
 1.12905 +
 1.12906 +    CImg<T> get_fill(const T val0, const T val1) const {
 1.12907 +      return CImg<T>(width,height,depth,dim).fill(val0,val1);
 1.12908 +    }
 1.12909 +
 1.12910 +    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
 1.12911 +    CImg<T>& fill(const T val0, const T val1, const T val2) {
 1.12912 +      if (is_empty()) return *this;
 1.12913 +      T *ptr, *ptr_end = end()-2;
 1.12914 +      for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
 1.12915 +      ptr_end+=2;
 1.12916 +      switch (ptr_end-ptr) {
 1.12917 +      case 2 : *(--ptr_end) = val1;
 1.12918 +      case 1 : *(--ptr_end) = val0;
 1.12919 +      }
 1.12920 +      return *this;
 1.12921 +    }
 1.12922 +
 1.12923 +    CImg<T> get_fill(const T val0, const T val1, const T val2) const {
 1.12924 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
 1.12925 +    }
 1.12926 +
 1.12927 +    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
 1.12928 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
 1.12929 +      if (is_empty()) return *this;
 1.12930 +      T *ptr, *ptr_end = end()-3;
 1.12931 +      for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
 1.12932 +      ptr_end+=3;
 1.12933 +      switch (ptr_end-ptr) {
 1.12934 +      case 3 : *(--ptr_end) = val2;
 1.12935 +      case 2 : *(--ptr_end) = val1;
 1.12936 +      case 1 : *(--ptr_end) = val0;
 1.12937 +      }
 1.12938 +      return *this;
 1.12939 +    }
 1.12940 +
 1.12941 +    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
 1.12942 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
 1.12943 +    }
 1.12944 +
 1.12945 +    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
 1.12946 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
 1.12947 +      if (is_empty()) return *this;
 1.12948 +      T *ptr, *ptr_end = end()-4;
 1.12949 +      for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
 1.12950 +      ptr_end+=4;
 1.12951 +      switch (ptr_end-ptr) {
 1.12952 +      case 4 : *(--ptr_end) = val3;
 1.12953 +      case 3 : *(--ptr_end) = val2;
 1.12954 +      case 2 : *(--ptr_end) = val1;
 1.12955 +      case 1 : *(--ptr_end) = val0;
 1.12956 +      }
 1.12957 +      return *this;
 1.12958 +    }
 1.12959 +
 1.12960 +    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
 1.12961 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
 1.12962 +    }
 1.12963 +
 1.12964 +    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
 1.12965 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
 1.12966 +      if (is_empty()) return *this;
 1.12967 +      T *ptr, *ptr_end = end()-5;
 1.12968 +      for (ptr = data; ptr<ptr_end; ) {
 1.12969 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.12970 +      }
 1.12971 +      ptr_end+=5;
 1.12972 +      switch (ptr_end-ptr) {
 1.12973 +      case 5 : *(--ptr_end) = val4;
 1.12974 +      case 4 : *(--ptr_end) = val3;
 1.12975 +      case 3 : *(--ptr_end) = val2;
 1.12976 +      case 2 : *(--ptr_end) = val1;
 1.12977 +      case 1 : *(--ptr_end) = val0;
 1.12978 +      }
 1.12979 +      return *this;
 1.12980 +    }
 1.12981 +
 1.12982 +    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
 1.12983 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
 1.12984 +    }
 1.12985 +
 1.12986 +    //! Fill sequentially pixel values.
 1.12987 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
 1.12988 +      if (is_empty()) return *this;
 1.12989 +      T *ptr, *ptr_end = end()-6;
 1.12990 +      for (ptr = data; ptr<ptr_end; ) {
 1.12991 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
 1.12992 +      }
 1.12993 +      ptr_end+=6;
 1.12994 +      switch (ptr_end-ptr) {
 1.12995 +      case 6 : *(--ptr_end) = val5;
 1.12996 +      case 5 : *(--ptr_end) = val4;
 1.12997 +      case 4 : *(--ptr_end) = val3;
 1.12998 +      case 3 : *(--ptr_end) = val2;
 1.12999 +      case 2 : *(--ptr_end) = val1;
 1.13000 +      case 1 : *(--ptr_end) = val0;
 1.13001 +      }
 1.13002 +      return *this;
 1.13003 +    }
 1.13004 +
 1.13005 +    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 {
 1.13006 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
 1.13007 +    }
 1.13008 +
 1.13009 +    //! Fill sequentially pixel values.
 1.13010 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13011 +                  const T val7) {
 1.13012 +      if (is_empty()) return *this;
 1.13013 +      T *ptr, *ptr_end = end()-7;
 1.13014 +      for (ptr = data; ptr<ptr_end; ) {
 1.13015 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
 1.13016 +        *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
 1.13017 +      }
 1.13018 +      ptr_end+=7;
 1.13019 +      switch (ptr_end-ptr) {
 1.13020 +      case 7 : *(--ptr_end) = val6;
 1.13021 +      case 6 : *(--ptr_end) = val5;
 1.13022 +      case 5 : *(--ptr_end) = val4;
 1.13023 +      case 4 : *(--ptr_end) = val3;
 1.13024 +      case 3 : *(--ptr_end) = val2;
 1.13025 +      case 2 : *(--ptr_end) = val1;
 1.13026 +      case 1 : *(--ptr_end) = val0;
 1.13027 +      }
 1.13028 +      return *this;
 1.13029 +    }
 1.13030 +
 1.13031 +    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,
 1.13032 +                     const T val7) const {
 1.13033 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
 1.13034 +    }
 1.13035 +
 1.13036 +    //! Fill sequentially pixel values.
 1.13037 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13038 +                  const T val7, const T val8) {
 1.13039 +      if (is_empty()) return *this;
 1.13040 +      T *ptr, *ptr_end = end()-8;
 1.13041 +      for (ptr = data; ptr<ptr_end; ) {
 1.13042 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
 1.13043 +        *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13044 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
 1.13045 +      }
 1.13046 +      ptr_end+=8;
 1.13047 +      switch (ptr_end-ptr) {
 1.13048 +      case 8 : *(--ptr_end) = val7;
 1.13049 +      case 7 : *(--ptr_end) = val6;
 1.13050 +      case 6 : *(--ptr_end) = val5;
 1.13051 +      case 5 : *(--ptr_end) = val4;
 1.13052 +      case 4 : *(--ptr_end) = val3;
 1.13053 +      case 3 : *(--ptr_end) = val2;
 1.13054 +      case 2 : *(--ptr_end) = val1;
 1.13055 +      case 1 : *(--ptr_end) = val0;
 1.13056 +      }
 1.13057 +      return *this;
 1.13058 +    }
 1.13059 +
 1.13060 +    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,
 1.13061 +                     const T val7, const T val8) const {
 1.13062 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
 1.13063 +    }
 1.13064 +
 1.13065 +    //! Fill sequentially pixel values.
 1.13066 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13067 +                  const T val7, const T val8, const T val9) {
 1.13068 +      if (is_empty()) return *this;
 1.13069 +      T *ptr, *ptr_end = end()-9;
 1.13070 +      for (ptr = data; ptr<ptr_end; ) {
 1.13071 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
 1.13072 +        *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
 1.13073 +      }
 1.13074 +      ptr_end+=9;
 1.13075 +      switch (ptr_end-ptr) {
 1.13076 +      case 9 : *(--ptr_end) = val8;
 1.13077 +      case 8 : *(--ptr_end) = val7;
 1.13078 +      case 7 : *(--ptr_end) = val6;
 1.13079 +      case 6 : *(--ptr_end) = val5;
 1.13080 +      case 5 : *(--ptr_end) = val4;
 1.13081 +      case 4 : *(--ptr_end) = val3;
 1.13082 +      case 3 : *(--ptr_end) = val2;
 1.13083 +      case 2 : *(--ptr_end) = val1;
 1.13084 +      case 1 : *(--ptr_end) = val0;
 1.13085 +      }
 1.13086 +      return *this;
 1.13087 +    }
 1.13088 +
 1.13089 +    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,
 1.13090 +                     const T val7, const T val8, const T val9) const {
 1.13091 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
 1.13092 +    }
 1.13093 +
 1.13094 +    //! Fill sequentially pixel values.
 1.13095 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13096 +                  const T val7, const T val8, const T val9, const T val10) {
 1.13097 +      if (is_empty()) return *this;
 1.13098 +      T *ptr, *ptr_end = end()-10;
 1.13099 +      for (ptr = data; ptr<ptr_end; ) {
 1.13100 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
 1.13101 +        *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
 1.13102 +        *(ptr++) = val10;
 1.13103 +      }
 1.13104 +      ptr_end+=10;
 1.13105 +      switch (ptr_end-ptr) {
 1.13106 +      case 10 : *(--ptr_end) = val9;
 1.13107 +      case 9 : *(--ptr_end) = val8;
 1.13108 +      case 8 : *(--ptr_end) = val7;
 1.13109 +      case 7 : *(--ptr_end) = val6;
 1.13110 +      case 6 : *(--ptr_end) = val5;
 1.13111 +      case 5 : *(--ptr_end) = val4;
 1.13112 +      case 4 : *(--ptr_end) = val3;
 1.13113 +      case 3 : *(--ptr_end) = val2;
 1.13114 +      case 2 : *(--ptr_end) = val1;
 1.13115 +      case 1 : *(--ptr_end) = val0;
 1.13116 +      }
 1.13117 +      return *this;
 1.13118 +    }
 1.13119 +
 1.13120 +    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,
 1.13121 +                     const T val7, const T val8, const T val9, const T val10) const {
 1.13122 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
 1.13123 +    }
 1.13124 +
 1.13125 +    //! Fill sequentially pixel values.
 1.13126 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13127 +                  const T val7, const T val8, const T val9, const T val10, const T val11) {
 1.13128 +      if (is_empty()) return *this;
 1.13129 +      T *ptr, *ptr_end = end()-11;
 1.13130 +      for (ptr = data; ptr<ptr_end; ) {
 1.13131 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13132 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 1.13133 +      }
 1.13134 +      ptr_end+=11;
 1.13135 +      switch (ptr_end-ptr) {
 1.13136 +      case 11 : *(--ptr_end) = val10;
 1.13137 +      case 10 : *(--ptr_end) = val9;
 1.13138 +      case 9 : *(--ptr_end) = val8;
 1.13139 +      case 8 : *(--ptr_end) = val7;
 1.13140 +      case 7 : *(--ptr_end) = val6;
 1.13141 +      case 6 : *(--ptr_end) = val5;
 1.13142 +      case 5 : *(--ptr_end) = val4;
 1.13143 +      case 4 : *(--ptr_end) = val3;
 1.13144 +      case 3 : *(--ptr_end) = val2;
 1.13145 +      case 2 : *(--ptr_end) = val1;
 1.13146 +      case 1 : *(--ptr_end) = val0;
 1.13147 +      }
 1.13148 +      return *this;
 1.13149 +    }
 1.13150 +
 1.13151 +    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,
 1.13152 +                     const T val7, const T val8, const T val9, const T val10, const T val11) const {
 1.13153 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
 1.13154 +    }
 1.13155 +
 1.13156 +    //! Fill sequentially pixel values.
 1.13157 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13158 +                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
 1.13159 +      if (is_empty()) return *this;
 1.13160 +      T *ptr, *ptr_end = end()-12;
 1.13161 +      for (ptr = data; ptr<ptr_end; ) {
 1.13162 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13163 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 1.13164 +        *(ptr++) = val12;
 1.13165 +      }
 1.13166 +      ptr_end+=12;
 1.13167 +      switch (ptr_end-ptr) {
 1.13168 +      case 12 : *(--ptr_end) = val11;
 1.13169 +      case 11 : *(--ptr_end) = val10;
 1.13170 +      case 10 : *(--ptr_end) = val9;
 1.13171 +      case 9 : *(--ptr_end) = val8;
 1.13172 +      case 8 : *(--ptr_end) = val7;
 1.13173 +      case 7 : *(--ptr_end) = val6;
 1.13174 +      case 6 : *(--ptr_end) = val5;
 1.13175 +      case 5 : *(--ptr_end) = val4;
 1.13176 +      case 4 : *(--ptr_end) = val3;
 1.13177 +      case 3 : *(--ptr_end) = val2;
 1.13178 +      case 2 : *(--ptr_end) = val1;
 1.13179 +      case 1 : *(--ptr_end) = val0;
 1.13180 +      }
 1.13181 +      return *this;
 1.13182 +    }
 1.13183 +
 1.13184 +    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,
 1.13185 +                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
 1.13186 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
 1.13187 +    }
 1.13188 +
 1.13189 +    //! Fill sequentially pixel values.
 1.13190 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13191 +                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13192 +                  const T val13) {
 1.13193 +      if (is_empty()) return *this;
 1.13194 +      T *ptr, *ptr_end = end()-13;
 1.13195 +      for (ptr = data; ptr<ptr_end; ) {
 1.13196 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13197 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 1.13198 +        *(ptr++) = val12; *(ptr++) = val13;
 1.13199 +      }
 1.13200 +      ptr_end+=13;
 1.13201 +      switch (ptr_end-ptr) {
 1.13202 +      case 13 : *(--ptr_end) = val12;
 1.13203 +      case 12 : *(--ptr_end) = val11;
 1.13204 +      case 11 : *(--ptr_end) = val10;
 1.13205 +      case 10 : *(--ptr_end) = val9;
 1.13206 +      case 9 : *(--ptr_end) = val8;
 1.13207 +      case 8 : *(--ptr_end) = val7;
 1.13208 +      case 7 : *(--ptr_end) = val6;
 1.13209 +      case 6 : *(--ptr_end) = val5;
 1.13210 +      case 5 : *(--ptr_end) = val4;
 1.13211 +      case 4 : *(--ptr_end) = val3;
 1.13212 +      case 3 : *(--ptr_end) = val2;
 1.13213 +      case 2 : *(--ptr_end) = val1;
 1.13214 +      case 1 : *(--ptr_end) = val0;
 1.13215 +      }
 1.13216 +      return *this;
 1.13217 +    }
 1.13218 +
 1.13219 +    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,
 1.13220 +                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13221 +                     const T val13) const {
 1.13222 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 1.13223 +                                                  val13);
 1.13224 +    }
 1.13225 +
 1.13226 +    //! Fill sequentially pixel values.
 1.13227 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13228 +                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13229 +                  const T val13, const T val14) {
 1.13230 +      if (is_empty()) return *this;
 1.13231 +      T *ptr, *ptr_end = end()-14;
 1.13232 +      for (ptr = data; ptr<ptr_end; ) {
 1.13233 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13234 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 1.13235 +        *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
 1.13236 +      }
 1.13237 +      ptr_end+=14;
 1.13238 +      switch (ptr_end-ptr) {
 1.13239 +      case 14 : *(--ptr_end) = val13;
 1.13240 +      case 13 : *(--ptr_end) = val12;
 1.13241 +      case 12 : *(--ptr_end) = val11;
 1.13242 +      case 11 : *(--ptr_end) = val10;
 1.13243 +      case 10 : *(--ptr_end) = val9;
 1.13244 +      case 9 : *(--ptr_end) = val8;
 1.13245 +      case 8 : *(--ptr_end) = val7;
 1.13246 +      case 7 : *(--ptr_end) = val6;
 1.13247 +      case 6 : *(--ptr_end) = val5;
 1.13248 +      case 5 : *(--ptr_end) = val4;
 1.13249 +      case 4 : *(--ptr_end) = val3;
 1.13250 +      case 3 : *(--ptr_end) = val2;
 1.13251 +      case 2 : *(--ptr_end) = val1;
 1.13252 +      case 1 : *(--ptr_end) = val0;
 1.13253 +      }
 1.13254 +      return *this;
 1.13255 +    }
 1.13256 +
 1.13257 +    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,
 1.13258 +                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13259 +                     const T val13, const T val14) const {
 1.13260 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 1.13261 +                                                  val13,val14);
 1.13262 +    }
 1.13263 +
 1.13264 +    //! Fill sequentially pixel values.
 1.13265 +    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 1.13266 +                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13267 +                  const T val13, const T val14, const T val15) {
 1.13268 +      if (is_empty()) return *this;
 1.13269 +      T *ptr, *ptr_end = end()-15;
 1.13270 +      for (ptr = data; ptr<ptr_end; ) {
 1.13271 +        *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
 1.13272 +        *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
 1.13273 +        *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
 1.13274 +      }
 1.13275 +      ptr_end+=15;
 1.13276 +      switch (ptr_end-ptr) {
 1.13277 +      case 15 : *(--ptr_end) = val14;
 1.13278 +      case 14 : *(--ptr_end) = val13;
 1.13279 +      case 13 : *(--ptr_end) = val12;
 1.13280 +      case 12 : *(--ptr_end) = val11;
 1.13281 +      case 11 : *(--ptr_end) = val10;
 1.13282 +      case 10 : *(--ptr_end) = val9;
 1.13283 +      case 9 : *(--ptr_end) = val8;
 1.13284 +      case 8 : *(--ptr_end) = val7;
 1.13285 +      case 7 : *(--ptr_end) = val6;
 1.13286 +      case 6 : *(--ptr_end) = val5;
 1.13287 +      case 5 : *(--ptr_end) = val4;
 1.13288 +      case 4 : *(--ptr_end) = val3;
 1.13289 +      case 3 : *(--ptr_end) = val2;
 1.13290 +      case 2 : *(--ptr_end) = val1;
 1.13291 +      case 1 : *(--ptr_end) = val0;
 1.13292 +      }
 1.13293 +      return *this;
 1.13294 +    }
 1.13295 +
 1.13296 +    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,
 1.13297 +                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 1.13298 +                     const T val13, const T val14, const T val15) const {
 1.13299 +      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
 1.13300 +                                                  val13,val14,val15);
 1.13301 +    }
 1.13302 +
 1.13303 +    //! Fill image values according to the values found in the specified string.
 1.13304 +    CImg<T>& fill(const char *const values, const bool repeat_pattern) {
 1.13305 +      if (is_empty() || !values) return *this;
 1.13306 +      T *ptrd = data, *ptr_end = data + size();
 1.13307 +      const char *nvalues = values;
 1.13308 +      const unsigned int siz = size();
 1.13309 +      char cval[64] = { 0 },  sep = 0;
 1.13310 +      int err = 0; double val = 0; unsigned int nb = 0;
 1.13311 +      while ((err=cimg_std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%c",cval,&sep))>0 &&
 1.13312 +             cimg_std::sscanf(cval,"%lf",&val)>0 && nb<siz) {
 1.13313 +        nvalues += cimg::strlen(cval);
 1.13314 +        *(ptrd++) = (T)val;
 1.13315 +        ++nb;
 1.13316 +        if (err!=2) break; else ++nvalues;
 1.13317 +      }
 1.13318 +      if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
 1.13319 +      return *this;
 1.13320 +    }
 1.13321 +
 1.13322 +    CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
 1.13323 +      return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
 1.13324 +    }
 1.13325 +
 1.13326 +    //! Fill image values according to the values found in the specified image.
 1.13327 +    template<typename t>
 1.13328 +    CImg<T>& fill(const CImg<t>& values, const bool repeat_pattern=true) {
 1.13329 +      if (is_empty() || !values) return *this;
 1.13330 +      T *ptrd = data, *ptrd_end = ptrd + size();
 1.13331 +      for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
 1.13332 +      if (repeat_pattern && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
 1.13333 +      return *this;
 1.13334 +    }
 1.13335 +
 1.13336 +    template<typename t>
 1.13337 +    CImg<T> get_fill(const CImg<t>& values, const bool repeat_pattern=true) const {
 1.13338 +      return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
 1.13339 +    }
 1.13340 +
 1.13341 +    //! Fill image values along the X-axis at the specified pixel position (y,z,v).
 1.13342 +    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
 1.13343 +#define _cimg_fill1(x,y,z,v,off,siz,t) { \
 1.13344 +    va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
 1.13345 +    for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
 1.13346 +    va_end(ap); }
 1.13347 +      if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
 1.13348 +      return *this;
 1.13349 +    }
 1.13350 +
 1.13351 +    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
 1.13352 +      if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
 1.13353 +      return *this;
 1.13354 +    }
 1.13355 +
 1.13356 +    //! Fill image values along the Y-axis at the specified pixel position (x,z,v).
 1.13357 +    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
 1.13358 +      if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
 1.13359 +      return *this;
 1.13360 +    }
 1.13361 +
 1.13362 +    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
 1.13363 +      if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
 1.13364 +      return *this;
 1.13365 +    }
 1.13366 +
 1.13367 +    //! Fill image values along the Z-axis at the specified pixel position (x,y,v).
 1.13368 +    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
 1.13369 +      const unsigned int wh = width*height;
 1.13370 +      if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
 1.13371 +      return *this;
 1.13372 +    }
 1.13373 +
 1.13374 +    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
 1.13375 +      const unsigned int wh = width*height;
 1.13376 +      if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
 1.13377 +      return *this;
 1.13378 +    }
 1.13379 +
 1.13380 +    //! Fill image values along the V-axis at the specified pixel position (x,y,z).
 1.13381 +    CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
 1.13382 +      const unsigned int whz = width*height*depth;
 1.13383 +      if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
 1.13384 +      return *this;
 1.13385 +    }
 1.13386 +
 1.13387 +    CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
 1.13388 +      const unsigned int whz = width*height*depth;
 1.13389 +      if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
 1.13390 +      return *this;
 1.13391 +    }
 1.13392 +
 1.13393 +    //! Linear normalization of the pixel values between \a a and \a b.
 1.13394 +    CImg<T>& normalize(const T a, const T b) {
 1.13395 +      if (is_empty()) return *this;
 1.13396 +      const T na = a<b?a:b, nb = a<b?b:a;
 1.13397 +      T m, M = maxmin(m);
 1.13398 +      const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
 1.13399 +      if (m==M) return fill(0);
 1.13400 +      if (m!=na || M!=nb) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(nb-na)+na);
 1.13401 +      return *this;
 1.13402 +    }
 1.13403 +
 1.13404 +    CImg<T> get_normalize(const T a, const T b) const {
 1.13405 +      return (+*this).normalize(a,b);
 1.13406 +    }
 1.13407 +
 1.13408 +    //! Cut pixel values between \a a and \a b.
 1.13409 +    CImg<T>& cut(const T a, const T b) {
 1.13410 +      if (is_empty()) return *this;
 1.13411 +      const T na = a<b?a:b, nb = a<b?b:a;
 1.13412 +      cimg_for(*this,ptr,T) *ptr = (*ptr<na)?na:((*ptr>nb)?nb:*ptr);
 1.13413 +      return *this;
 1.13414 +    }
 1.13415 +
 1.13416 +    CImg<T> get_cut(const T a, const T b) const {
 1.13417 +      return (+*this).cut(a,b);
 1.13418 +    }
 1.13419 +
 1.13420 +    //! Quantize pixel values into \n levels.
 1.13421 +    CImg<T>& quantize(const unsigned int n, const bool keep_range=true) {
 1.13422 +      if (is_empty()) return *this;
 1.13423 +      if (!n)
 1.13424 +        throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
 1.13425 +                                    pixel_type());
 1.13426 +      Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
 1.13427 +      if (range>0) {
 1.13428 +        if (keep_range) cimg_for(*this,ptr,T) {
 1.13429 +          const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 1.13430 +          *ptr = (T)(m + cimg::min(val,n-1)*range/n);
 1.13431 +        } else cimg_for(*this,ptr,T) {
 1.13432 +          const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 1.13433 +          *ptr = (T)cimg::min(val,n-1);
 1.13434 +        }
 1.13435 +      }
 1.13436 +      return *this;
 1.13437 +    }
 1.13438 +
 1.13439 +    CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
 1.13440 +      return (+*this).quantize(n,keep_range);
 1.13441 +    }
 1.13442 +
 1.13443 +    //! Threshold the image.
 1.13444 +    /**
 1.13445 +       \param value Threshold value.
 1.13446 +       \param soft Enable soft thresholding.
 1.13447 +       \param strict Tells if the threshold is strict.
 1.13448 +    **/
 1.13449 +    CImg<T>& threshold(const T value, const bool soft=false, const bool strict=false) {
 1.13450 +      if (is_empty()) return *this;
 1.13451 +      if (strict) {
 1.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; }
 1.13453 +        else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
 1.13454 +      } else {
 1.13455 +        if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-value?(T)(v+value):(T)0; }
 1.13456 +        else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
 1.13457 +      }
 1.13458 +      return *this;
 1.13459 +    }
 1.13460 +
 1.13461 +    CImg<T> get_threshold(const T value, const bool soft=false, const bool strict=false) const {
 1.13462 +      return (+*this).threshold(value,soft,strict);
 1.13463 +    }
 1.13464 +
 1.13465 +    //! Rotate an image.
 1.13466 +    /**
 1.13467 +       \param angle = rotation angle (in degrees).
 1.13468 +       \param cond = rotation type. can be :
 1.13469 +       - 0 = zero-value at borders
 1.13470 +       - 1 = nearest pixel.
 1.13471 +       - 2 = Fourier style.
 1.13472 +       \note Returned image will probably have a different size than the instance image *this.
 1.13473 +    **/
 1.13474 +    CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
 1.13475 +      return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
 1.13476 +    }
 1.13477 +
 1.13478 +    CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
 1.13479 +      if (is_empty()) return *this;
 1.13480 +      CImg<T> dest;
 1.13481 +      const float nangle = cimg::mod(angle,360.0f);
 1.13482 +      if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
 1.13483 +        const int wm1 = dimx()-1, hm1 = dimy()-1;
 1.13484 +        const int iangle = (int)nangle/90;
 1.13485 +        switch (iangle) {
 1.13486 +        case 1 : {
 1.13487 +          dest.assign(height,width,depth,dim);
 1.13488 +          cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
 1.13489 +        } break;
 1.13490 +        case 2 : {
 1.13491 +          dest.assign(width,height,depth,dim);
 1.13492 +          cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
 1.13493 +        } break;
 1.13494 +        case 3 : {
 1.13495 +          dest.assign(height,width,depth,dim);
 1.13496 +          cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
 1.13497 +        } break;
 1.13498 +        default :
 1.13499 +          return *this;
 1.13500 +        }
 1.13501 +      } else { // generic version
 1.13502 +        const float
 1.13503 +          rad = (float)(nangle*cimg::valuePI/180.0),
 1.13504 +          ca = (float)cimg_std::cos(rad),
 1.13505 +          sa = (float)cimg_std::sin(rad),
 1.13506 +          ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
 1.13507 +          vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
 1.13508 +          w2 = 0.5f*width, h2 = 0.5f*height,
 1.13509 +          dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
 1.13510 +        dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
 1.13511 +        switch (border_conditions) {
 1.13512 +        case 0 : {
 1.13513 +          switch (interpolation) {
 1.13514 +          case 2 : {
 1.13515 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13516 +              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);
 1.13517 +          } break;
 1.13518 +          case 1 : {
 1.13519 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13520 +              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);
 1.13521 +          } break;
 1.13522 +          default : {
 1.13523 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13524 +              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);
 1.13525 +          }
 1.13526 +          }
 1.13527 +        } break;
 1.13528 +        case 1 : {
 1.13529 +          switch (interpolation) {
 1.13530 +          case 2 :
 1.13531 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13532 +              dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
 1.13533 +            break;
 1.13534 +          case 1 :
 1.13535 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13536 +              dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
 1.13537 +            break;
 1.13538 +          default :
 1.13539 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13540 +              dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
 1.13541 +          }
 1.13542 +        } break;
 1.13543 +        case 2 : {
 1.13544 +          switch (interpolation) {
 1.13545 +          case 2 :
 1.13546 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13547 +              dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
 1.13548 +                                            cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
 1.13549 +            break;
 1.13550 +          case 1 :
 1.13551 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13552 +              dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
 1.13553 +                                             cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
 1.13554 +            break;
 1.13555 +          default :
 1.13556 +            cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
 1.13557 +              dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
 1.13558 +                                      cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
 1.13559 +          }
 1.13560 +        } break;
 1.13561 +        default :
 1.13562 +          throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid border conditions %d (should be 0,1 or 2).",
 1.13563 +                                      pixel_type(),border_conditions);
 1.13564 +        }
 1.13565 +      }
 1.13566 +      return dest;
 1.13567 +    }
 1.13568 +
 1.13569 +    //! Rotate an image around a center point (\c cx,\c cy).
 1.13570 +    /**
 1.13571 +       \param angle = rotation angle (in degrees).
 1.13572 +       \param cx = X-coordinate of the rotation center.
 1.13573 +       \param cy = Y-coordinate of the rotation center.
 1.13574 +       \param zoom = zoom.
 1.13575 +       \param cond = rotation type. can be :
 1.13576 +       - 0 = zero-value at borders
 1.13577 +       - 1 = repeat image at borders
 1.13578 +       - 2 = zero-value at borders and linear interpolation
 1.13579 +    **/
 1.13580 +    CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
 1.13581 +                    const unsigned int border_conditions=3, const unsigned int interpolation=1) {
 1.13582 +      return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
 1.13583 +    }
 1.13584 +
 1.13585 +    CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
 1.13586 +                       const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
 1.13587 +      if (interpolation>2)
 1.13588 +        throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
 1.13589 +                                    pixel_type(),interpolation);
 1.13590 +      if (is_empty()) return *this;
 1.13591 +      CImg<T> dest(width,height,depth,dim);
 1.13592 +      const float nangle = cimg::mod(angle,360.0f);
 1.13593 +      if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
 1.13594 +        const int iangle = (int)nangle/90;
 1.13595 +        switch (iangle) {
 1.13596 +        case 1 : {
 1.13597 +          dest.fill(0);
 1.13598 +          const unsigned int
 1.13599 +            xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
 1.13600 +            ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
 1.13601 +            xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
 1.13602 +            yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
 1.13603 +          cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
 1.13604 +            dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
 1.13605 +        } break;
 1.13606 +        case 2 : {
 1.13607 +          cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
 1.13608 +        } break;
 1.13609 +        case 3 : {
 1.13610 +          dest.fill(0);
 1.13611 +          const unsigned int
 1.13612 +            xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
 1.13613 +            ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
 1.13614 +            xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
 1.13615 +            yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
 1.13616 +          cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
 1.13617 +            dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
 1.13618 +        } break;
 1.13619 +        default :
 1.13620 +          return *this;
 1.13621 +        }
 1.13622 +      } else {
 1.13623 +        const float
 1.13624 +          rad = (float)((nangle*cimg::valuePI)/180.0),
 1.13625 +          ca = (float)cimg_std::cos(rad)/zoom,
 1.13626 +          sa = (float)cimg_std::sin(rad)/zoom;
 1.13627 +        switch (border_conditions) { // generic version
 1.13628 +        case 0 : {
 1.13629 +          switch (interpolation) {
 1.13630 +          case 2 : {
 1.13631 +            cimg_forXY(dest,x,y)
 1.13632 +              cimg_forZV(*this,z,v)
 1.13633 +              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);
 1.13634 +          } break;
 1.13635 +          case 1 : {
 1.13636 +            cimg_forXY(dest,x,y)
 1.13637 +              cimg_forZV(*this,z,v)
 1.13638 +              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);
 1.13639 +          } break;
 1.13640 +          default : {
 1.13641 +            cimg_forXY(dest,x,y)
 1.13642 +              cimg_forZV(*this,z,v)
 1.13643 +              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);
 1.13644 +          }
 1.13645 +          }
 1.13646 +        } break;
 1.13647 +        case 1 : {
 1.13648 +          switch (interpolation) {
 1.13649 +          case 2 : {
 1.13650 +            cimg_forXY(dest,x,y)
 1.13651 +              cimg_forZV(*this,z,v)
 1.13652 +              dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
 1.13653 +            } break;
 1.13654 +          case 1 : {
 1.13655 +            cimg_forXY(dest,x,y)
 1.13656 +              cimg_forZV(*this,z,v)
 1.13657 +              dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
 1.13658 +          } break;
 1.13659 +          default : {
 1.13660 +            cimg_forXY(dest,x,y)
 1.13661 +              cimg_forZV(*this,z,v)
 1.13662 +              dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
 1.13663 +          }
 1.13664 +          }
 1.13665 +        } break;
 1.13666 +        case 2 : {
 1.13667 +          switch (interpolation) {
 1.13668 +          case 2 : {
 1.13669 +            cimg_forXY(dest,x,y)
 1.13670 +              cimg_forZV(*this,z,v)
 1.13671 +              dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
 1.13672 +                                            cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
 1.13673 +            } break;
 1.13674 +          case 1 : {
 1.13675 +            cimg_forXY(dest,x,y)
 1.13676 +              cimg_forZV(*this,z,v)
 1.13677 +              dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
 1.13678 +                                             cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
 1.13679 +          } break;
 1.13680 +          default : {
 1.13681 +            cimg_forXY(dest,x,y)
 1.13682 +              cimg_forZV(*this,z,v)
 1.13683 +              dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
 1.13684 +                                      cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
 1.13685 +          }
 1.13686 +          }
 1.13687 +        } break;
 1.13688 +        default :
 1.13689 +          throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
 1.13690 +                                      pixel_type(),border_conditions);
 1.13691 +        }
 1.13692 +      }
 1.13693 +      return dest;
 1.13694 +    }
 1.13695 +
 1.13696 +    //! Resize an image.
 1.13697 +    /**
 1.13698 +       \param pdx Number of columns (new size along the X-axis).
 1.13699 +       \param pdy Number of rows (new size along the Y-axis).
 1.13700 +       \param pdz Number of slices (new size along the Z-axis).
 1.13701 +       \param pdv Number of vector-channels (new size along the V-axis).
 1.13702 +       \param interpolation_type Method of interpolation :
 1.13703 +       - -1 = no interpolation : raw memory resizing.
 1.13704 +       - 0 = no interpolation : additional space is filled according to \p border_condition.
 1.13705 +       - 1 = bloc interpolation (nearest point).
 1.13706 +       - 2 = moving average interpolation.
 1.13707 +       - 3 = linear interpolation.
 1.13708 +       - 4 = grid interpolation.
 1.13709 +       - 5 = bi-cubic interpolation.
 1.13710 +       \param border_condition Border condition type.
 1.13711 +       \param center Set centering type (only if \p interpolation_type=0).
 1.13712 +       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 1.13713 +    **/
 1.13714 +    CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 1.13715 +                    const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
 1.13716 +      if (!pdx || !pdy || !pdz || !pdv) return assign();
 1.13717 +      const unsigned int
 1.13718 +        tdx = pdx<0?-pdx*width/100:pdx,
 1.13719 +        tdy = pdy<0?-pdy*height/100:pdy,
 1.13720 +        tdz = pdz<0?-pdz*depth/100:pdz,
 1.13721 +        tdv = pdv<0?-pdv*dim/100:pdv,
 1.13722 +        dx = tdx?tdx:1,
 1.13723 +        dy = tdy?tdy:1,
 1.13724 +        dz = tdz?tdz:1,
 1.13725 +        dv = tdv?tdv:1;
 1.13726 +      if (width==dx && height==dy && depth==dz && dim==dv) return *this;
 1.13727 +      if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
 1.13728 +        width = dx; height = dy; depth = dz; dim = dv;
 1.13729 +        return *this;
 1.13730 +      }
 1.13731 +      return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
 1.13732 +    }
 1.13733 +
 1.13734 +    CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 1.13735 +                       const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
 1.13736 +      if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
 1.13737 +      const unsigned int
 1.13738 +        tdx = pdx<0?-pdx*width/100:pdx,
 1.13739 +        tdy = pdy<0?-pdy*height/100:pdy,
 1.13740 +        tdz = pdz<0?-pdz*depth/100:pdz,
 1.13741 +        tdv = pdv<0?-pdv*dim/100:pdv,
 1.13742 +        dx = tdx?tdx:1,
 1.13743 +        dy = tdy?tdy:1,
 1.13744 +        dz = tdz?tdz:1,
 1.13745 +        dv = tdv?tdv:1;
 1.13746 +      if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
 1.13747 +      if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
 1.13748 +
 1.13749 +      CImg<T> res;
 1.13750 +
 1.13751 +      switch (interpolation_type) {
 1.13752 +      case -1 : // Raw resizing
 1.13753 +        cimg_std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
 1.13754 +        break;
 1.13755 +
 1.13756 +      case 0 :  { // No interpolation
 1.13757 +        const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
 1.13758 +        res.assign(dx,dy,dz,dv);
 1.13759 +        switch (border_condition) {
 1.13760 +        case 1 : {
 1.13761 +          if (center) {
 1.13762 +            const int
 1.13763 +              x0 = (res.dimx()-dimx())/2,
 1.13764 +              y0 = (res.dimy()-dimy())/2,
 1.13765 +              z0 = (res.dimz()-dimz())/2,
 1.13766 +              v0 = (res.dimv()-dimv())/2,
 1.13767 +              x1 = x0 + (int)bx,
 1.13768 +              y1 = y0 + (int)by,
 1.13769 +              z1 = z0 + (int)bz,
 1.13770 +              v1 = v0 + (int)bv;
 1.13771 +            res.draw_image(x0,y0,z0,v0,*this);
 1.13772 +            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);
 1.13773 +          } else {
 1.13774 +            res.draw_image(*this);
 1.13775 +            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);
 1.13776 +          }
 1.13777 +          } break;
 1.13778 +        case 2 : {
 1.13779 +          int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
 1.13780 +          if (center) {
 1.13781 +            const int
 1.13782 +              x0 = (res.dimx()-dimx())/2,
 1.13783 +              y0 = (res.dimy()-dimy())/2,
 1.13784 +              z0 = (res.dimz()-dimz())/2,
 1.13785 +              v0 = (res.dimv()-dimv())/2;
 1.13786 +            nx0 = x0>0?x0-(1+x0/width)*width:x0;
 1.13787 +            ny0 = y0>0?y0-(1+y0/height)*height:y0;
 1.13788 +            nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
 1.13789 +            nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
 1.13790 +          }
 1.13791 +          for (int k = nv0; k<(int)dv; k+=dimv())
 1.13792 +            for (int z = nz0; z<(int)dz; z+=dimz())
 1.13793 +              for (int y = ny0; y<(int)dy; y+=dimy())
 1.13794 +                for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
 1.13795 +          } break;
 1.13796 +        default : {
 1.13797 +          res.fill(0);
 1.13798 +          if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
 1.13799 +          else res.draw_image(*this);
 1.13800 +        }
 1.13801 +        }
 1.13802 +      } break;
 1.13803 +
 1.13804 +      case 1 : { // Nearest-neighbor interpolation
 1.13805 +        res.assign(dx,dy,dz,dv);
 1.13806 +        unsigned int
 1.13807 +          *const offx = new unsigned int[dx],
 1.13808 +          *const offy = new unsigned int[dy+1],
 1.13809 +          *const offz = new unsigned int[dz+1],
 1.13810 +          *const offv = new unsigned int[dv+1],
 1.13811 +          *poffx, *poffy, *poffz, *poffv,
 1.13812 +          curr, old;
 1.13813 +        const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
 1.13814 +        poffx = offx; curr = 0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }}
 1.13815 +        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;
 1.13816 +        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;
 1.13817 +        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;
 1.13818 +        T *ptrd = res.data;
 1.13819 +        const T* ptrv = data;
 1.13820 +        poffv = offv;
 1.13821 +        for (unsigned int k=0; k<dv; ) {
 1.13822 +          const T *ptrz = ptrv;
 1.13823 +          poffz = offz;
 1.13824 +          for (unsigned int z=0; z<dz; ) {
 1.13825 +            const T *ptry = ptrz;
 1.13826 +            poffy = offy;
 1.13827 +            for (unsigned int y=0; y<dy; ) {
 1.13828 +              const T *ptrx = ptry;
 1.13829 +              poffx = offx;
 1.13830 +              cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
 1.13831 +              ++y;
 1.13832 +              unsigned int dy = *(poffy++);
 1.13833 +              for (;!dy && y<dy; cimg_std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
 1.13834 +              ptry+=dy;
 1.13835 +            }
 1.13836 +            ++z;
 1.13837 +            unsigned int dz = *(poffz++);
 1.13838 +            for (;!dz && z<dz; cimg_std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
 1.13839 +            ptrz+=dz;
 1.13840 +          }
 1.13841 +          ++k;
 1.13842 +          unsigned int dv = *(poffv++);
 1.13843 +          for (;!dv && k<dv; cimg_std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
 1.13844 +          ptrv+=dv;
 1.13845 +        }
 1.13846 +        delete[] offx; delete[] offy; delete[] offz; delete[] offv;
 1.13847 +      } break;
 1.13848 +
 1.13849 +      case 2 : { // Moving average
 1.13850 +        bool instance_first = true;
 1.13851 +        if (dx!=width) {
 1.13852 +          CImg<Tfloat> tmp(dx,height,depth,dim,0);
 1.13853 +          for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
 1.13854 +            const unsigned int d = cimg::min(b,c);
 1.13855 +            a-=d; b-=d; c-=d;
 1.13856 +            cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
 1.13857 +            if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
 1.13858 +            if (!c) { ++s; c = dx; }
 1.13859 +          }
 1.13860 +          tmp.transfer_to(res);
 1.13861 +          instance_first = false;
 1.13862 +        }
 1.13863 +        if (dy!=height) {
 1.13864 +          CImg<Tfloat> tmp(dx,dy,depth,dim,0);
 1.13865 +          for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
 1.13866 +            const unsigned int d = cimg::min(b,c);
 1.13867 +            a-=d; b-=d; c-=d;
 1.13868 +            if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
 1.13869 +            else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
 1.13870 +            if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
 1.13871 +            if (!c) { ++s; c = dy; }
 1.13872 +          }
 1.13873 +          tmp.transfer_to(res);
 1.13874 +          instance_first = false;
 1.13875 +        }
 1.13876 +        if (dz!=depth) {
 1.13877 +          CImg<Tfloat> tmp(dx,dy,dz,dim,0);
 1.13878 +          for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
 1.13879 +            const unsigned int d = cimg::min(b,c);
 1.13880 +            a-=d; b-=d; c-=d;
 1.13881 +            if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
 1.13882 +            else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
 1.13883 +            if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
 1.13884 +            if (!c) { ++s; c = dz; }
 1.13885 +          }
 1.13886 +          tmp.transfer_to(res);
 1.13887 +          instance_first = false;
 1.13888 +        }
 1.13889 +        if (dv!=dim) {
 1.13890 +          CImg<Tfloat> tmp(dx,dy,dz,dv,0);
 1.13891 +          for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
 1.13892 +            const unsigned int d = cimg::min(b,c);
 1.13893 +            a-=d; b-=d; c-=d;
 1.13894 +            if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
 1.13895 +            else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
 1.13896 +            if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
 1.13897 +            if (!c) { ++s; c = dv; }
 1.13898 +          }
 1.13899 +          tmp.transfer_to(res);
 1.13900 +          instance_first = false;
 1.13901 +        }
 1.13902 +      } break;
 1.13903 +
 1.13904 +      case 3 : { // Linear interpolation
 1.13905 +        const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
 1.13906 +        const float
 1.13907 +          sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
 1.13908 +          sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
 1.13909 +          sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
 1.13910 +          sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
 1.13911 +
 1.13912 +        unsigned int *const off = new unsigned int[dimmax], *poff;
 1.13913 +        float *const foff = new float[dimmax], *pfoff, old, curr;
 1.13914 +        CImg<T> resx, resy, resz, resv;
 1.13915 +        T *ptrd;
 1.13916 +
 1.13917 +        if (dx!=width) {
 1.13918 +          if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
 1.13919 +          else {
 1.13920 +            resx.assign(dx,height,depth,dim);
 1.13921 +            curr = old = 0; poff = off; pfoff = foff;
 1.13922 +            cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
 1.13923 +            ptrd = resx.data;
 1.13924 +            const T *ptrs0 = data;
 1.13925 +            cimg_forYZV(resx,y,z,k) {
 1.13926 +              poff = off; pfoff = foff;
 1.13927 +              const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
 1.13928 +              cimg_forX(resx,x) {
 1.13929 +                const float alpha = *(pfoff++);
 1.13930 +                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
 1.13931 +                *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
 1.13932 +                ptrs+=*(poff++);
 1.13933 +              }
 1.13934 +              ptrs0+=width;
 1.13935 +            }
 1.13936 +          }
 1.13937 +        } else resx.assign(*this,true);
 1.13938 +
 1.13939 +        if (dy!=height) {
 1.13940 +          if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
 1.13941 +          else {
 1.13942 +            resy.assign(dx,dy,depth,dim);
 1.13943 +            curr = old = 0; poff = off; pfoff = foff;
 1.13944 +            cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
 1.13945 +            cimg_forXZV(resy,x,z,k) {
 1.13946 +              ptrd = resy.ptr(x,0,z,k);
 1.13947 +              const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
 1.13948 +              poff = off; pfoff = foff;
 1.13949 +              cimg_forY(resy,y) {
 1.13950 +                const float alpha = *(pfoff++);
 1.13951 +                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
 1.13952 +                *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 1.13953 +                ptrd+=dx;
 1.13954 +                ptrs+=*(poff++);
 1.13955 +              }
 1.13956 +            }
 1.13957 +          }
 1.13958 +          resx.assign();
 1.13959 +        } else resy.assign(resx,true);
 1.13960 +
 1.13961 +        if (dz!=depth) {
 1.13962 +          if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
 1.13963 +          else {
 1.13964 +            const unsigned int wh = dx*dy;
 1.13965 +            resz.assign(dx,dy,dz,dim);
 1.13966 +            curr = old = 0; poff = off; pfoff = foff;
 1.13967 +            cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
 1.13968 +            cimg_forXYV(resz,x,y,k) {
 1.13969 +              ptrd = resz.ptr(x,y,0,k);
 1.13970 +              const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
 1.13971 +              poff = off; pfoff = foff;
 1.13972 +              cimg_forZ(resz,z) {
 1.13973 +                const float alpha = *(pfoff++);
 1.13974 +                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
 1.13975 +                *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 1.13976 +                ptrd+=wh;
 1.13977 +                ptrs+=*(poff++);
 1.13978 +              }
 1.13979 +            }
 1.13980 +          }
 1.13981 +          resy.assign();
 1.13982 +        } else resz.assign(resy,true);
 1.13983 +
 1.13984 +        if (dv!=dim) {
 1.13985 +          if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
 1.13986 +          else {
 1.13987 +            const unsigned int whd = dx*dy*dz;
 1.13988 +            resv.assign(dx,dy,dz,dv);
 1.13989 +            curr = old = 0; poff = off; pfoff = foff;
 1.13990 +            cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
 1.13991 +            cimg_forXYZ(resv,x,y,z) {
 1.13992 +              ptrd = resv.ptr(x,y,z,0);
 1.13993 +              const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
 1.13994 +              poff = off; pfoff = foff;
 1.13995 +              cimg_forV(resv,k) {
 1.13996 +                const float alpha = *(pfoff++);
 1.13997 +                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
 1.13998 +                *ptrd = (T)((1-alpha)*val1 + alpha*val2);
 1.13999 +                ptrd+=whd;
 1.14000 +                ptrs+=*(poff++);
 1.14001 +              }
 1.14002 +            }
 1.14003 +          }
 1.14004 +          resz.assign();
 1.14005 +        } else resv.assign(resz,true);
 1.14006 +
 1.14007 +        delete[] off; delete[] foff;
 1.14008 +        return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
 1.14009 +      } break;
 1.14010 +
 1.14011 +      case 4 : { // Grid filling
 1.14012 +        res.assign(dx,dy,dz,dv,0);
 1.14013 +        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);
 1.14014 +      } break;
 1.14015 +
 1.14016 +      case 5 : { // Cubic interpolation
 1.14017 +        const float
 1.14018 +          sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
 1.14019 +          sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
 1.14020 +          sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
 1.14021 +          sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
 1.14022 +        res.assign(dx,dy,dz,dv);
 1.14023 +        T *ptrd = res.ptr();
 1.14024 +        float cx, cy, cz, ck = 0;
 1.14025 +        cimg_forV(res,k) { cz = 0;
 1.14026 +        cimg_forZ(res,z) { cy = 0;
 1.14027 +        cimg_forY(res,y) { cx = 0;
 1.14028 +        cimg_forX(res,x) {
 1.14029 +          *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
 1.14030 +          cx+=sx;
 1.14031 +        } cy+=sy;
 1.14032 +        } cz+=sz;
 1.14033 +        } ck+=sv;
 1.14034 +        }
 1.14035 +      } break;
 1.14036 +
 1.14037 +      default : // Invalid interpolation method
 1.14038 +        throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
 1.14039 +                                    "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
 1.14040 +                                    pixel_type(),interpolation_type);
 1.14041 +      }
 1.14042 +      return res;
 1.14043 +    }
 1.14044 +
 1.14045 +    //! Resize an image.
 1.14046 +    /**
 1.14047 +       \param src  Image giving the geometry of the resize.
 1.14048 +       \param interpolation_type  Interpolation method :
 1.14049 +       - 1 = raw memory
 1.14050 +       - 0 = no interpolation : additional space is filled with 0.
 1.14051 +       - 1 = bloc interpolation (nearest point).
 1.14052 +       - 2 = mosaic : image is repeated if necessary.
 1.14053 +       - 3 = linear interpolation.
 1.14054 +       - 4 = grid interpolation.
 1.14055 +       - 5 = bi-cubic interpolation.
 1.14056 +       \param border_condition Border condition type.
 1.14057 +       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 1.14058 +    **/
 1.14059 +    template<typename t>
 1.14060 +    CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
 1.14061 +                    const int border_condition=-1, const bool center=false) {
 1.14062 +      return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 1.14063 +    }
 1.14064 +
 1.14065 +    template<typename t>
 1.14066 +    CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
 1.14067 +                       const int border_condition=-1, const bool center=false) const {
 1.14068 +      return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 1.14069 +    }
 1.14070 +
 1.14071 +    //! Resize an image.
 1.14072 +    /**
 1.14073 +       \param disp = Display giving the geometry of the resize.
 1.14074 +       \param interpolation_type = Resizing type :
 1.14075 +       - 0 = no interpolation : additional space is filled with 0.
 1.14076 +       - 1 = bloc interpolation (nearest point).
 1.14077 +       - 2 = mosaic : image is repeated if necessary.
 1.14078 +       - 3 = linear interpolation.
 1.14079 +       - 4 = grid interpolation.
 1.14080 +       - 5 = bi-cubic interpolation.
 1.14081 +       - 6 = moving average (best quality for photographs)
 1.14082 +       \param border_condition Border condition type.
 1.14083 +       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
 1.14084 +    **/
 1.14085 +    CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
 1.14086 +                    const int border_condition=-1, const bool center=false) {
 1.14087 +      return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 1.14088 +    }
 1.14089 +
 1.14090 +    CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
 1.14091 +                       const int border_condition=-1, const bool center=false) const {
 1.14092 +      return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 1.14093 +    }
 1.14094 +
 1.14095 +    //! Half-resize an image, using a special optimized filter.
 1.14096 +    CImg<T>& resize_halfXY() {
 1.14097 +      return get_resize_halfXY().transfer_to(*this);
 1.14098 +    }
 1.14099 +
 1.14100 +    CImg<T> get_resize_halfXY() const {
 1.14101 +      if (is_empty()) return *this;
 1.14102 +      const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
 1.14103 +                              0.1231940459f,  0.1935127547f, 0.1231940459f,
 1.14104 +                              0.07842776544f, 0.1231940459f, 0.07842776544f };
 1.14105 +      T I[9] = { 0 };
 1.14106 +      CImg<T> dest(width/2,height/2,depth,dim);
 1.14107 +      cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
 1.14108 +        if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
 1.14109 +                          (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 1.14110 +                           I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 1.14111 +                           I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 1.14112 +      return dest;
 1.14113 +    }
 1.14114 +
 1.14115 +    //! Upscale an image by a factor 2x.
 1.14116 +    /**
 1.14117 +       Use anisotropic upscaling algorithm described at
 1.14118 +       http://scale2x.sourceforge.net/algorithm.html
 1.14119 +    **/
 1.14120 +    CImg<T>& resize_doubleXY() {
 1.14121 +      return get_resize_doubleXY().transfer_to(*this);
 1.14122 +    }
 1.14123 +
 1.14124 +    CImg<T> get_resize_doubleXY() const {
 1.14125 +#define _cimg_gs2x_for3(bound,i) \
 1.14126 + for (int i = 0, _p1##i = 0, \
 1.14127 +      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 1.14128 +      _n1##i<(int)(bound) || i==--_n1##i; \
 1.14129 +      _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
 1.14130 +
 1.14131 +#define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
 1.14132 +  _cimg_gs2x_for3((img).height,y) for (int x = 0, \
 1.14133 +   _p1##x = 0, \
 1.14134 +   _n1##x = (int)( \
 1.14135 +   (I[1] = (img)(0,_p1##y,z,v)), \
 1.14136 +   (I[3] = I[4] = (img)(0,y,z,v)), \
 1.14137 +   (I[7] = (img)(0,_n1##y,z,v)),        \
 1.14138 +   1>=(img).width?(int)((img).width)-1:1); \
 1.14139 +   (_n1##x<(int)((img).width) && ( \
 1.14140 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 1.14141 +   (I[5] = (img)(_n1##x,y,z,v)), \
 1.14142 +   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 1.14143 +   x==--_n1##x; \
 1.14144 +   I[1] = I[2], \
 1.14145 +   I[3] = I[4], I[4] = I[5], \
 1.14146 +   I[7] = I[8], \
 1.14147 +   _p1##x = x++, ++_n1##x)
 1.14148 +
 1.14149 +      if (is_empty()) return *this;
 1.14150 +      CImg<T> res(2*width,2*height,depth,dim);
 1.14151 +      CImg_3x3(I,T);
 1.14152 +      cimg_forZV(*this,z,k) {
 1.14153 +        T
 1.14154 +          *ptrd1 = res.ptr(0,0,0,k),
 1.14155 +          *ptrd2 = ptrd1 + res.width;
 1.14156 +        _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
 1.14157 +          if (Icp!=Icn && Ipc!=Inc) {
 1.14158 +            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 1.14159 +            *(ptrd1++) = Icp==Inc?Inc:Icc;
 1.14160 +            *(ptrd2++) = Ipc==Icn?Ipc:Icc;
 1.14161 +            *(ptrd2++) = Icn==Inc?Inc:Icc;
 1.14162 +          } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
 1.14163 +        }
 1.14164 +      }
 1.14165 +      return res;
 1.14166 +    }
 1.14167 +
 1.14168 +    //! Upscale an image by a factor 3x.
 1.14169 +    /**
 1.14170 +       Use anisotropic upscaling algorithm described at
 1.14171 +       http://scale2x.sourceforge.net/algorithm.html
 1.14172 +    **/
 1.14173 +    CImg<T>& resize_tripleXY() {
 1.14174 +      return get_resize_tripleXY().transfer_to(*this);
 1.14175 +    }
 1.14176 +
 1.14177 +    CImg<T> get_resize_tripleXY() const {
 1.14178 +#define _cimg_gs3x_for3(bound,i) \
 1.14179 + for (int i = 0, _p1##i = 0, \
 1.14180 +      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 1.14181 +      _n1##i<(int)(bound) || i==--_n1##i; \
 1.14182 +      _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
 1.14183 +
 1.14184 +#define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
 1.14185 +  _cimg_gs3x_for3((img).height,y) for (int x = 0, \
 1.14186 +   _p1##x = 0, \
 1.14187 +   _n1##x = (int)( \
 1.14188 +   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
 1.14189 +   (I[3] = I[4] = (img)(0,y,z,v)), \
 1.14190 +   (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
 1.14191 +   1>=(img).width?(int)((img).width)-1:1); \
 1.14192 +   (_n1##x<(int)((img).width) && ( \
 1.14193 +   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 1.14194 +   (I[5] = (img)(_n1##x,y,z,v)), \
 1.14195 +   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 1.14196 +   x==--_n1##x; \
 1.14197 +   I[0] = I[1], I[1] = I[2], \
 1.14198 +   I[3] = I[4], I[4] = I[5], \
 1.14199 +   I[6] = I[7], I[7] = I[8], \
 1.14200 +   _p1##x = x++, ++_n1##x)
 1.14201 +
 1.14202 +      if (is_empty()) return *this;
 1.14203 +      CImg<T> res(3*width,3*height,depth,dim);
 1.14204 +      CImg_3x3(I,T);
 1.14205 +      cimg_forZV(*this,z,k) {
 1.14206 +        T
 1.14207 +          *ptrd1 = res.ptr(0,0,0,k),
 1.14208 +          *ptrd2 = ptrd1 + res.width,
 1.14209 +          *ptrd3 = ptrd2 + res.width;
 1.14210 +        _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
 1.14211 +          if (Icp != Icn && Ipc != Inc) {
 1.14212 +            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 1.14213 +            *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
 1.14214 +            *(ptrd1++) = Icp==Inc?Inc:Icc;
 1.14215 +            *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
 1.14216 +            *(ptrd2++) = Icc;
 1.14217 +            *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
 1.14218 +            *(ptrd3++) = Ipc==Icn?Ipc:Icc;
 1.14219 +            *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
 1.14220 +            *(ptrd3++) = Icn==Inc?Inc:Icc;
 1.14221 +          } else {
 1.14222 +            *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
 1.14223 +            *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
 1.14224 +            *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
 1.14225 +          }
 1.14226 +        }
 1.14227 +      }
 1.14228 +      return res;
 1.14229 +    }
 1.14230 +
 1.14231 +    // Warp an image.
 1.14232 +    template<typename t>
 1.14233 +    CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
 1.14234 +                  const bool interpolation=true, const unsigned int border_conditions=0) {
 1.14235 +      return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
 1.14236 +    }
 1.14237 +
 1.14238 +    template<typename t>
 1.14239 +    CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
 1.14240 +                     const bool interpolation=true, const unsigned int border_conditions=0) const {
 1.14241 +      if (is_empty() || !warp) return *this;
 1.14242 +      if (!is_sameXYZ(warp))
 1.14243 +        throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and warping field (%u,%u,%u,%u,%p) "
 1.14244 +                                    "have different XYZ dimensions.",
 1.14245 +                                    pixel_type(),width,height,depth,dim,data,
 1.14246 +                                    warp.width,warp.height,warp.depth,warp.dim,warp.data);
 1.14247 +      CImg<T> res(width,height,depth,dim);
 1.14248 +      switch (warp.dim) {
 1.14249 +      case 1 : // 1D warping.
 1.14250 +        if (relative) { // Relative warp coordinates
 1.14251 +          if (interpolation) switch (border_conditions) {
 1.14252 +          case 2 : {
 1.14253 +            cimg_forXYZV(*this,x,y,z,v)
 1.14254 +              res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
 1.14255 +          } break;
 1.14256 +          case 1 : {
 1.14257 +            cimg_forXYZV(*this,x,y,z,v)
 1.14258 +              res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
 1.14259 +          } break;
 1.14260 +          default : {
 1.14261 +            cimg_forXYZV(*this,x,y,z,v)
 1.14262 +              res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
 1.14263 +          }
 1.14264 +          } else switch (border_conditions) {
 1.14265 +          case 2 : {
 1.14266 +            cimg_forXYZV(*this,x,y,z,v)
 1.14267 +              res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
 1.14268 +          } break;
 1.14269 +          case 1 : {
 1.14270 +            cimg_forXYZV(*this,x,y,z,v)
 1.14271 +              res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
 1.14272 +          } break;
 1.14273 +          default : {
 1.14274 +            cimg_forXYZV(*this,x,y,z,v)
 1.14275 +              res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
 1.14276 +          }
 1.14277 +          }
 1.14278 +        } else { // Absolute warp coordinates
 1.14279 +          if (interpolation) switch (border_conditions) {
 1.14280 +          case 2 : {
 1.14281 +            cimg_forXYZV(*this,x,y,z,v)
 1.14282 +              res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
 1.14283 +          } break;
 1.14284 +          case 1 : {
 1.14285 +            cimg_forXYZV(*this,x,y,z,v)
 1.14286 +              res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
 1.14287 +          } break;
 1.14288 +          default : {
 1.14289 +            cimg_forXYZV(*this,x,y,z,v)
 1.14290 +              res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
 1.14291 +          }
 1.14292 +          } else switch (border_conditions) {
 1.14293 +          case 2 : {
 1.14294 +            cimg_forXYZV(*this,x,y,z,v)
 1.14295 +              res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
 1.14296 +          } break;
 1.14297 +          case 1 : {
 1.14298 +            cimg_forXYZV(*this,x,y,z,v)
 1.14299 +              res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
 1.14300 +          } break;
 1.14301 +          default : {
 1.14302 +            cimg_forXYZV(*this,x,y,z,v)
 1.14303 +              res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
 1.14304 +          }
 1.14305 +          }
 1.14306 +        }
 1.14307 +        break;
 1.14308 +
 1.14309 +      case 2 : // 2D warping
 1.14310 +        if (relative) { // Relative warp coordinates
 1.14311 +          if (interpolation) switch (border_conditions) {
 1.14312 +          case 2 : {
 1.14313 +            cimg_forXYZV(*this,x,y,z,v)
 1.14314 +              res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 1.14315 +                                             cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
 1.14316 +          } break;
 1.14317 +          case 1 : {
 1.14318 +            cimg_forXYZV(*this,x,y,z,v)
 1.14319 +              res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
 1.14320 +          } break;
 1.14321 +          default : {
 1.14322 +            cimg_forXYZV(*this,x,y,z,v)
 1.14323 +              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);
 1.14324 +          }
 1.14325 +          } else switch (border_conditions) {
 1.14326 +          case 2 : {
 1.14327 +            cimg_forXYZV(*this,x,y,z,v)
 1.14328 +              res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 1.14329 +                                     cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
 1.14330 +          } break;
 1.14331 +          case 1 : {
 1.14332 +            cimg_forXYZV(*this,x,y,z,v)
 1.14333 +              res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
 1.14334 +          } break;
 1.14335 +          default : {
 1.14336 +            cimg_forXYZV(*this,x,y,z,v)
 1.14337 +              res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
 1.14338 +          }
 1.14339 +          }
 1.14340 +        } else { // Absolute warp coordinates
 1.14341 +          if (interpolation) switch (border_conditions) {
 1.14342 +          case 2 : {
 1.14343 +            cimg_forXYZV(*this,x,y,z,v)
 1.14344 +              res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
 1.14345 +                                             cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
 1.14346 +          } break;
 1.14347 +          case 1 : {
 1.14348 +            cimg_forXYZV(*this,x,y,z,v)
 1.14349 +              res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
 1.14350 +          } break;
 1.14351 +          default : {
 1.14352 +            cimg_forXYZV(*this,x,y,z,v)
 1.14353 +              res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
 1.14354 +          }
 1.14355 +          } else switch (border_conditions) {
 1.14356 +          case 2 : {
 1.14357 +            cimg_forXYZV(*this,x,y,z,v)
 1.14358 +              res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 1.14359 +                                     cimg::mod((int)warp(x,y,z,1),(int)depth),z,v);
 1.14360 +          } break;
 1.14361 +          case 1 : {
 1.14362 +            cimg_forXYZV(*this,x,y,z,v)
 1.14363 +              res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
 1.14364 +          } break;
 1.14365 +          default : {
 1.14366 +            cimg_forXYZV(*this,x,y,z,v)
 1.14367 +              res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
 1.14368 +          }
 1.14369 +          }
 1.14370 +        }
 1.14371 +        break;
 1.14372 +
 1.14373 +      case 3 : // 3D warping
 1.14374 +        if (relative) { // Relative warp coordinates
 1.14375 +          if (interpolation) switch (border_conditions) {
 1.14376 +          case 2 : {
 1.14377 +            cimg_forXYZV(*this,x,y,z,v)
 1.14378 +              res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 1.14379 +                                              cimg::mod(y-(float)warp(x,y,z,1),(float)height),
 1.14380 +                                              cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
 1.14381 +          } break;
 1.14382 +          case 1 : {
 1.14383 +            cimg_forXYZV(*this,x,y,z,v)
 1.14384 +              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);
 1.14385 +          } break;
 1.14386 +          default : {
 1.14387 +            cimg_forXYZV(*this,x,y,z,v)
 1.14388 +              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);
 1.14389 +          }
 1.14390 +          } else switch (border_conditions) {
 1.14391 +          case 2 : {
 1.14392 +            cimg_forXYZV(*this,x,y,z,v)
 1.14393 +              res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 1.14394 +                                     cimg::mod(y-(int)warp(x,y,z,1),(int)height),
 1.14395 +                                     cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
 1.14396 +          } break;
 1.14397 +          case 1 : {
 1.14398 +            cimg_forXYZV(*this,x,y,z,v)
 1.14399 +              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);
 1.14400 +          } break;
 1.14401 +          default : {
 1.14402 +            cimg_forXYZV(*this,x,y,z,v)
 1.14403 +              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);
 1.14404 +          }
 1.14405 +          }
 1.14406 +        } else { // Absolute warp coordinates
 1.14407 +          if (interpolation) switch (border_conditions) {
 1.14408 +          case 2 : {
 1.14409 +            cimg_forXYZV(*this,x,y,z,v)
 1.14410 +              res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
 1.14411 +                                              cimg::mod((float)warp(x,y,z,1),(float)height),
 1.14412 +                                              cimg::mod((float)warp(x,y,z,2),(float)depth),v);
 1.14413 +          } break;
 1.14414 +          case 1 : {
 1.14415 +            cimg_forXYZV(*this,x,y,z,v)
 1.14416 +              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);
 1.14417 +          } break;
 1.14418 +          default : {
 1.14419 +            cimg_forXYZV(*this,x,y,z,v)
 1.14420 +              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);
 1.14421 +          }
 1.14422 +          } else switch (border_conditions) {
 1.14423 +          case 2 : {
 1.14424 +            cimg_forXYZV(*this,x,y,z,v)
 1.14425 +              res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 1.14426 +                                     cimg::mod((int)warp(x,y,z,1),(int)height),
 1.14427 +                                     cimg::mod((int)warp(x,y,z,2),(int)depth),v);
 1.14428 +          } break;
 1.14429 +          case 1 : {
 1.14430 +            cimg_forXYZV(*this,x,y,z,v)
 1.14431 +              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);
 1.14432 +          } break;
 1.14433 +          default : {
 1.14434 +            cimg_forXYZV(*this,x,y,z,v)
 1.14435 +              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);
 1.14436 +          }
 1.14437 +          }
 1.14438 +        }
 1.14439 +        break;
 1.14440 +
 1.14441 +      default : // 4D warping
 1.14442 +        if (relative) { // Relative warp coordinates
 1.14443 +          if (interpolation) switch (border_conditions) {
 1.14444 +          case 2 : {
 1.14445 +            cimg_forXYZV(*this,x,y,z,v)
 1.14446 +              res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
 1.14447 +                                               cimg::mod(y-(float)warp(x,y,z,1),(float)height),
 1.14448 +                                               cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
 1.14449 +                                               cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
 1.14450 +          } break;
 1.14451 +          case 1 : {
 1.14452 +            cimg_forXYZV(*this,x,y,z,v)
 1.14453 +              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));
 1.14454 +          } break;
 1.14455 +          default : {
 1.14456 +            cimg_forXYZV(*this,x,y,z,v)
 1.14457 +              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);
 1.14458 +          }
 1.14459 +          } else switch (border_conditions) {
 1.14460 +          case 2 : {
 1.14461 +            cimg_forXYZV(*this,x,y,z,v)
 1.14462 +              res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
 1.14463 +                                     cimg::mod(y-(int)warp(x,y,z,1),(int)height),
 1.14464 +                                     cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
 1.14465 +                                     cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
 1.14466 +          } break;
 1.14467 +          case 1 : {
 1.14468 +            cimg_forXYZV(*this,x,y,z,v)
 1.14469 +              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));
 1.14470 +          } break;
 1.14471 +          default : {
 1.14472 +            cimg_forXYZV(*this,x,y,z,v)
 1.14473 +              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);
 1.14474 +          }
 1.14475 +          }
 1.14476 +        } else { // Absolute warp coordinates
 1.14477 +          if (interpolation) switch (border_conditions) {
 1.14478 +          case 2 : {
 1.14479 +            cimg_forXYZV(*this,x,y,z,v)
 1.14480 +              res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
 1.14481 +                                               cimg::mod((float)warp(x,y,z,1),(float)height),
 1.14482 +                                               cimg::mod((float)warp(x,y,z,2),(float)depth),
 1.14483 +                                               cimg::mod((float)warp(x,y,z,3),(float)dim));
 1.14484 +          } break;
 1.14485 +          case 1 : {
 1.14486 +            cimg_forXYZV(*this,x,y,z,v)
 1.14487 +              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));
 1.14488 +          } break;
 1.14489 +          default : {
 1.14490 +            cimg_forXYZV(*this,x,y,z,v)
 1.14491 +              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);
 1.14492 +          }
 1.14493 +          } else switch (border_conditions) {
 1.14494 +          case 2 : {
 1.14495 +            cimg_forXYZV(*this,x,y,z,v)
 1.14496 +              res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
 1.14497 +                                     cimg::mod((int)warp(x,y,z,1),(int)height),
 1.14498 +                                     cimg::mod((int)warp(x,y,z,2),(int)depth),
 1.14499 +                                     cimg::mod((int)warp(x,y,z,3),(int)dim));
 1.14500 +          } break;
 1.14501 +          case 1 : {
 1.14502 +            cimg_forXYZV(*this,x,y,z,v)
 1.14503 +              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));
 1.14504 +          } break;
 1.14505 +          default : {
 1.14506 +            cimg_forXYZV(*this,x,y,z,v)
 1.14507 +              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);
 1.14508 +          }
 1.14509 +          }
 1.14510 +        }
 1.14511 +      }
 1.14512 +      return res;
 1.14513 +    }
 1.14514 +
 1.14515 +    // Permute axes order (internal).
 1.14516 +    template<typename t>
 1.14517 +    CImg<t> _get_permute_axes(const char *permut, const t&) const {
 1.14518 +      if (is_empty() || !permut) return CImg<t>(*this,false);
 1.14519 +      CImg<t> res;
 1.14520 +      const T* ptrs = data;
 1.14521 +      if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
 1.14522 +      if (!cimg::strncasecmp(permut,"xyvz",4)) {
 1.14523 +        res.assign(width,height,dim,depth);
 1.14524 +        cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
 1.14525 +      }
 1.14526 +      if (!cimg::strncasecmp(permut,"xzyv",4)) {
 1.14527 +        res.assign(width,depth,height,dim);
 1.14528 +        cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
 1.14529 +      }
 1.14530 +      if (!cimg::strncasecmp(permut,"xzvy",4)) {
 1.14531 +        res.assign(width,depth,dim,height);
 1.14532 +        cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
 1.14533 +      }
 1.14534 +      if (!cimg::strncasecmp(permut,"xvyz",4)) {
 1.14535 +        res.assign(width,dim,height,depth);
 1.14536 +        cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
 1.14537 +      }
 1.14538 +      if (!cimg::strncasecmp(permut,"xvzy",4)) {
 1.14539 +        res.assign(width,dim,depth,height);
 1.14540 +        cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
 1.14541 +      }
 1.14542 +      if (!cimg::strncasecmp(permut,"yxzv",4)) {
 1.14543 +        res.assign(height,width,depth,dim);
 1.14544 +        cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
 1.14545 +      }
 1.14546 +      if (!cimg::strncasecmp(permut,"yxvz",4)) {
 1.14547 +        res.assign(height,width,dim,depth);
 1.14548 +        cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
 1.14549 +      }
 1.14550 +      if (!cimg::strncasecmp(permut,"yzxv",4)) {
 1.14551 +        res.assign(height,depth,width,dim);
 1.14552 +        cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
 1.14553 +      }
 1.14554 +      if (!cimg::strncasecmp(permut,"yzvx",4)) {
 1.14555 +        res.assign(height,depth,dim,width);
 1.14556 +        switch (width) {
 1.14557 +        case 1 : {
 1.14558 +          t *ptrR = res.ptr(0,0,0,0);
 1.14559 +          for (unsigned long siz = height*depth*dim; siz; --siz) {
 1.14560 +            *(ptrR++) = (t)*(ptrs++);
 1.14561 +          }
 1.14562 +        } break;
 1.14563 +        case 2 : {
 1.14564 +          t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
 1.14565 +          for (unsigned long siz = height*depth*dim; siz; --siz) {
 1.14566 +            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
 1.14567 +          }
 1.14568 +        } break;
 1.14569 +        case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
 1.14570 +          t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
 1.14571 +          for (unsigned long siz = height*depth*dim; siz; --siz) {
 1.14572 +            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
 1.14573 +          }
 1.14574 +        } break;
 1.14575 +        case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
 1.14576 +          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);
 1.14577 +          for (unsigned long siz = height*depth*dim; siz; --siz) {
 1.14578 +            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
 1.14579 +          }
 1.14580 +        } break;
 1.14581 +        default : {
 1.14582 +          cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
 1.14583 +          return res;
 1.14584 +        }
 1.14585 +        }
 1.14586 +      }
 1.14587 +      if (!cimg::strncasecmp(permut,"yvxz",4)) {
 1.14588 +        res.assign(height,dim,width,depth);
 1.14589 +        cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
 1.14590 +      }
 1.14591 +      if (!cimg::strncasecmp(permut,"yvzx",4)) {
 1.14592 +        res.assign(height,dim,depth,width);
 1.14593 +        cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
 1.14594 +      }
 1.14595 +      if (!cimg::strncasecmp(permut,"zxyv",4)) {
 1.14596 +        res.assign(depth,width,height,dim);
 1.14597 +        cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
 1.14598 +      }
 1.14599 +      if (!cimg::strncasecmp(permut,"zxvy",4)) {
 1.14600 +        res.assign(depth,width,dim,height);
 1.14601 +        cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
 1.14602 +      }
 1.14603 +      if (!cimg::strncasecmp(permut,"zyxv",4)) {
 1.14604 +        res.assign(depth,height,width,dim);
 1.14605 +        cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
 1.14606 +      }
 1.14607 +      if (!cimg::strncasecmp(permut,"zyvx",4)) {
 1.14608 +        res.assign(depth,height,dim,width);
 1.14609 +        cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
 1.14610 +      }
 1.14611 +      if (!cimg::strncasecmp(permut,"zvxy",4)) {
 1.14612 +        res.assign(depth,dim,width,height);
 1.14613 +        cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
 1.14614 +      }
 1.14615 +      if (!cimg::strncasecmp(permut,"zvyx",4)) {
 1.14616 +        res.assign(depth,dim,height,width);
 1.14617 +        cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
 1.14618 +      }
 1.14619 +      if (!cimg::strncasecmp(permut,"vxyz",4)) {
 1.14620 +        res.assign(dim,width,height,depth);
 1.14621 +        switch (dim) {
 1.14622 +        case 1 : {
 1.14623 +          const T *ptrR = ptr(0,0,0,0);
 1.14624 +          t *ptrd = res.ptr();
 1.14625 +          for (unsigned long siz = width*height*depth; siz; --siz) {
 1.14626 +            *(ptrd++) = (t)*(ptrR++);
 1.14627 +          }
 1.14628 +        } break;
 1.14629 +        case 2 : {
 1.14630 +          const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
 1.14631 +          t *ptrd = res.ptr();
 1.14632 +          for (unsigned long siz = width*height*depth; siz; --siz) {
 1.14633 +            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
 1.14634 +          }
 1.14635 +        } break;
 1.14636 +        case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
 1.14637 +          const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
 1.14638 +          t *ptrd = res.ptr();
 1.14639 +          for (unsigned long siz = width*height*depth; siz; --siz) {
 1.14640 +            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
 1.14641 +          }
 1.14642 +        } break;
 1.14643 +        case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
 1.14644 +          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);
 1.14645 +          t *ptrd = res.ptr();
 1.14646 +          for (unsigned long siz = width*height*depth; siz; --siz) {
 1.14647 +            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
 1.14648 +          }
 1.14649 +        } break;
 1.14650 +        default : {
 1.14651 +          cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
 1.14652 +        }
 1.14653 +        }
 1.14654 +      }
 1.14655 +      if (!cimg::strncasecmp(permut,"vxzy",4)) {
 1.14656 +        res.assign(dim,width,depth,height);
 1.14657 +        cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
 1.14658 +      }
 1.14659 +      if (!cimg::strncasecmp(permut,"vyxz",4)) {
 1.14660 +        res.assign(dim,height,width,depth);
 1.14661 +        cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
 1.14662 +      }
 1.14663 +      if (!cimg::strncasecmp(permut,"vyzx",4)) {
 1.14664 +        res.assign(dim,height,depth,width);
 1.14665 +        cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
 1.14666 +      }
 1.14667 +      if (!cimg::strncasecmp(permut,"vzxy",4)) {
 1.14668 +        res.assign(dim,depth,width,height);
 1.14669 +        cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
 1.14670 +      }
 1.14671 +      if (!cimg::strncasecmp(permut,"vzyx",4)) {
 1.14672 +        res.assign(dim,depth,height,width);
 1.14673 +        cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
 1.14674 +      }
 1.14675 +      if (!res)
 1.14676 +        throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",
 1.14677 +                                    pixel_type(),permut);
 1.14678 +      return res;
 1.14679 +    }
 1.14680 +
 1.14681 +    //! Permute axes order.
 1.14682 +    /**
 1.14683 +       This function permutes image axes.
 1.14684 +       \param permut = String describing the permutation (4 characters).
 1.14685 +    **/
 1.14686 +    CImg<T>& permute_axes(const char *order) {
 1.14687 +      return get_permute_axes(order).transfer_to(*this);
 1.14688 +    }
 1.14689 +
 1.14690 +    CImg<T> get_permute_axes(const char *order) const {
 1.14691 +      const T foo = (T)0;
 1.14692 +      return _get_permute_axes(order,foo);
 1.14693 +    }
 1.14694 +
 1.14695 +    //! Invert endianness.
 1.14696 +    CImg<T>& invert_endianness() {
 1.14697 +      cimg::invert_endianness(data,size());
 1.14698 +      return *this;
 1.14699 +    }
 1.14700 +
 1.14701 +    CImg<T> get_invert_endianness() const {
 1.14702 +      return (+*this).invert_endianness();
 1.14703 +    }
 1.14704 +
 1.14705 +    //! Mirror an image along the specified axis.
 1.14706 +    CImg<T>& mirror(const char axis) {
 1.14707 +      if (is_empty()) return *this;
 1.14708 +      T *pf, *pb, *buf = 0;
 1.14709 +      switch (cimg::uncase(axis)) {
 1.14710 +      case 'x' : {
 1.14711 +        pf = data; pb = ptr(width-1);
 1.14712 +        const unsigned int width2 = width/2;
 1.14713 +        for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
 1.14714 +          for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
 1.14715 +          pf+=width - width2;
 1.14716 +          pb+=width + width2;
 1.14717 +        }
 1.14718 +      } break;
 1.14719 +      case 'y' : {
 1.14720 +        buf = new T[width];
 1.14721 +        pf = data; pb = ptr(0,height-1);
 1.14722 +        const unsigned int height2 = height/2;
 1.14723 +        for (unsigned int zv=0; zv<depth*dim; ++zv) {
 1.14724 +          for (unsigned int y=0; y<height2; ++y) {
 1.14725 +            cimg_std::memcpy(buf,pf,width*sizeof(T));
 1.14726 +            cimg_std::memcpy(pf,pb,width*sizeof(T));
 1.14727 +            cimg_std::memcpy(pb,buf,width*sizeof(T));
 1.14728 +            pf+=width;
 1.14729 +            pb-=width;
 1.14730 +          }
 1.14731 +          pf+=width*(height - height2);
 1.14732 +          pb+=width*(height + height2);
 1.14733 +        }
 1.14734 +      } break;
 1.14735 +      case 'z' : {
 1.14736 +        buf = new T[width*height];
 1.14737 +        pf = data; pb = ptr(0,0,depth-1);
 1.14738 +        const unsigned int depth2 = depth/2;
 1.14739 +        cimg_forV(*this,v) {
 1.14740 +          for (unsigned int z=0; z<depth2; ++z) {
 1.14741 +            cimg_std::memcpy(buf,pf,width*height*sizeof(T));
 1.14742 +            cimg_std::memcpy(pf,pb,width*height*sizeof(T));
 1.14743 +            cimg_std::memcpy(pb,buf,width*height*sizeof(T));
 1.14744 +            pf+=width*height;
 1.14745 +            pb-=width*height;
 1.14746 +          }
 1.14747 +          pf+=width*height*(depth - depth2);
 1.14748 +          pb+=width*height*(depth + depth2);
 1.14749 +        }
 1.14750 +      } break;
 1.14751 +      case 'v' : {
 1.14752 +        buf = new T[width*height*depth];
 1.14753 +        pf = data; pb = ptr(0,0,0,dim-1);
 1.14754 +        const unsigned int dim2 = dim/2;
 1.14755 +        for (unsigned int v=0; v<dim2; ++v) {
 1.14756 +          cimg_std::memcpy(buf,pf,width*height*depth*sizeof(T));
 1.14757 +          cimg_std::memcpy(pf,pb,width*height*depth*sizeof(T));
 1.14758 +          cimg_std::memcpy(pb,buf,width*height*depth*sizeof(T));
 1.14759 +          pf+=width*height*depth;
 1.14760 +          pb-=width*height*depth;
 1.14761 +        }
 1.14762 +      } break;
 1.14763 +      default :
 1.14764 +        throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
 1.14765 +                                    pixel_type(),axis);
 1.14766 +      }
 1.14767 +      if (buf) delete[] buf;
 1.14768 +      return *this;
 1.14769 +    }
 1.14770 +
 1.14771 +    CImg<T> get_mirror(const char axis) const {
 1.14772 +      return (+*this).mirror(axis);
 1.14773 +    }
 1.14774 +
 1.14775 +    //! Translate the image.
 1.14776 +    /**
 1.14777 +       \param deltax Amount of displacement along the X-axis.
 1.14778 +       \param deltay Amount of displacement along the Y-axis.
 1.14779 +       \param deltaz Amount of displacement along the Z-axis.
 1.14780 +       \param deltav Amount of displacement along the V-axis.
 1.14781 +       \param border_condition Border condition.
 1.14782 +
 1.14783 +       - \c border_condition can be :
 1.14784 +          - 0 : Zero border condition (Dirichlet).
 1.14785 +          - 1 : Nearest neighbors (Neumann).
 1.14786 +          - 2 : Repeat Pattern (Fourier style).
 1.14787 +    **/
 1.14788 +    CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 1.14789 +                       const int border_condition=0) {
 1.14790 +      if (is_empty()) return *this;
 1.14791 +      if (deltax) // Translate along X-axis
 1.14792 +        switch (border_condition) {
 1.14793 +        case 0 :
 1.14794 +          if (cimg::abs(deltax)>=dimx()) return fill(0);
 1.14795 +          if (deltax>0) cimg_forYZV(*this,y,z,k) {
 1.14796 +            cimg_std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
 1.14797 +            cimg_std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
 1.14798 +          } else cimg_forYZV(*this,y,z,k) {
 1.14799 +            cimg_std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T));
 1.14800 +            cimg_std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T));
 1.14801 +          }
 1.14802 +          break;
 1.14803 +        case 1 :
 1.14804 +          if (deltax>0) {
 1.14805 +            const int ndeltax = (deltax>=dimx())?width-1:deltax;
 1.14806 +            if (!ndeltax) return *this;
 1.14807 +            cimg_forYZV(*this,y,z,k) {
 1.14808 +              cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
 1.14809 +              T *ptrd = ptr(width-1,y,z,k);
 1.14810 +              const T val = *ptrd;
 1.14811 +              for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
 1.14812 +            }
 1.14813 +          } else {
 1.14814 +            const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
 1.14815 +            if (!ndeltax) return *this;
 1.14816 +            cimg_forYZV(*this,y,z,k) {
 1.14817 +              cimg_std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
 1.14818 +              T *ptrd = ptr(0,y,z,k);
 1.14819 +              const T val = *ptrd;
 1.14820 +              for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
 1.14821 +            }
 1.14822 +          }
 1.14823 +          break;
 1.14824 +        case 2 : {
 1.14825 +          const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
 1.14826 +          if (!ndeltax) return *this;
 1.14827 +          T* buf = new T[cimg::abs(ndeltax)];
 1.14828 +          if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
 1.14829 +            cimg_std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
 1.14830 +            cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
 1.14831 +            cimg_std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
 1.14832 +          } else cimg_forYZV(*this,y,z,k) {
 1.14833 +            cimg_std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
 1.14834 +            cimg_std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
 1.14835 +            cimg_std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
 1.14836 +          }
 1.14837 +          delete[] buf;
 1.14838 +        } break;
 1.14839 +        }
 1.14840 +
 1.14841 +      if (deltay) // Translate along Y-axis
 1.14842 +        switch (border_condition) {
 1.14843 +        case 0 :
 1.14844 +          if (cimg::abs(deltay)>=dimy()) return fill(0);
 1.14845 +          if (deltay>0) cimg_forZV(*this,z,k) {
 1.14846 +            cimg_std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
 1.14847 +            cimg_std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
 1.14848 +          } else cimg_forZV(*this,z,k) {
 1.14849 +            cimg_std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T));
 1.14850 +            cimg_std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T));
 1.14851 +          }
 1.14852 +          break;
 1.14853 +        case 1 :
 1.14854 +          if (deltay>0) {
 1.14855 +            const int ndeltay = (deltay>=dimy())?height-1:deltay;
 1.14856 +            if (!ndeltay) return *this;
 1.14857 +            cimg_forZV(*this,z,k) {
 1.14858 +              cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
 1.14859 +              T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
 1.14860 +              for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
 1.14861 +            }
 1.14862 +          } else {
 1.14863 +            const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
 1.14864 +            if (!ndeltay) return *this;
 1.14865 +            cimg_forZV(*this,z,k) {
 1.14866 +              cimg_std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
 1.14867 +              T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
 1.14868 +              for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
 1.14869 +            }
 1.14870 +          }
 1.14871 +          break;
 1.14872 +        case 2 : {
 1.14873 +          const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
 1.14874 +          if (!ndeltay) return *this;
 1.14875 +          T* buf = new T[width*cimg::abs(ndeltay)];
 1.14876 +          if (ndeltay>0) cimg_forZV(*this,z,k) {
 1.14877 +            cimg_std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
 1.14878 +            cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
 1.14879 +            cimg_std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
 1.14880 +          } else cimg_forZV(*this,z,k) {
 1.14881 +            cimg_std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
 1.14882 +            cimg_std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
 1.14883 +            cimg_std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
 1.14884 +          }
 1.14885 +          delete[] buf;
 1.14886 +        } break;
 1.14887 +        }
 1.14888 +
 1.14889 +      if (deltaz) // Translate along Z-axis
 1.14890 +        switch (border_condition) {
 1.14891 +        case 0 :
 1.14892 +          if (cimg::abs(deltaz)>=dimz()) return fill(0);
 1.14893 +          if (deltaz>0) cimg_forV(*this,k) {
 1.14894 +            cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
 1.14895 +            cimg_std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
 1.14896 +          } else cimg_forV(*this,k) {
 1.14897 +            cimg_std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T));
 1.14898 +            cimg_std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T));
 1.14899 +          }
 1.14900 +          break;
 1.14901 +        case 1 :
 1.14902 +          if (deltaz>0) {
 1.14903 +            const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
 1.14904 +            if (!ndeltaz) return *this;
 1.14905 +            cimg_forV(*this,k) {
 1.14906 +              cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
 1.14907 +              T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
 1.14908 +              for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
 1.14909 +            }
 1.14910 +          } else {
 1.14911 +            const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
 1.14912 +            if (!ndeltaz) return *this;
 1.14913 +            cimg_forV(*this,k) {
 1.14914 +              cimg_std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
 1.14915 +              T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
 1.14916 +              for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
 1.14917 +            }
 1.14918 +          }
 1.14919 +          break;
 1.14920 +        case 2 : {
 1.14921 +          const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
 1.14922 +          if (!ndeltaz) return *this;
 1.14923 +          T* buf = new T[width*height*cimg::abs(ndeltaz)];
 1.14924 +          if (ndeltaz>0) cimg_forV(*this,k) {
 1.14925 +            cimg_std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
 1.14926 +            cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
 1.14927 +            cimg_std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
 1.14928 +          } else cimg_forV(*this,k) {
 1.14929 +            cimg_std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
 1.14930 +            cimg_std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
 1.14931 +            cimg_std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
 1.14932 +          }
 1.14933 +          delete[] buf;
 1.14934 +        } break;
 1.14935 +        }
 1.14936 +
 1.14937 +      if (deltav) // Translate along V-axis
 1.14938 +        switch (border_condition) {
 1.14939 +        case 0 :
 1.14940 +          if (cimg::abs(deltav)>=dimv()) return fill(0);
 1.14941 +          if (deltav>0) {
 1.14942 +            cimg_std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
 1.14943 +            cimg_std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
 1.14944 +          } else cimg_forV(*this,k) {
 1.14945 +            cimg_std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T));
 1.14946 +            cimg_std::memset(data,0,-deltav*width*height*depth*sizeof(T));
 1.14947 +          }
 1.14948 +          break;
 1.14949 +        case 1 :
 1.14950 +          if (deltav>0) {
 1.14951 +            const int ndeltav = (deltav>=dimv())?dim-1:deltav;
 1.14952 +            if (!ndeltav) return *this;
 1.14953 +            cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
 1.14954 +            T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
 1.14955 +            for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
 1.14956 +          } else {
 1.14957 +            const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
 1.14958 +            if (!ndeltav) return *this;
 1.14959 +            cimg_std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
 1.14960 +            T *ptrd = ptr(0,0,0,1);
 1.14961 +            for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
 1.14962 +          }
 1.14963 +          break;
 1.14964 +        case 2 : {
 1.14965 +          const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
 1.14966 +          if (!ndeltav) return *this;
 1.14967 +          T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
 1.14968 +          if (ndeltav>0) {
 1.14969 +            cimg_std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
 1.14970 +            cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
 1.14971 +            cimg_std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
 1.14972 +          } else {
 1.14973 +            cimg_std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
 1.14974 +            cimg_std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
 1.14975 +            cimg_std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
 1.14976 +          }
 1.14977 +          delete[] buf;
 1.14978 +        } break;
 1.14979 +        }
 1.14980 +      return *this;
 1.14981 +    }
 1.14982 +
 1.14983 +    CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 1.14984 +                          const int border_condition=0) const {
 1.14985 +      return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
 1.14986 +    }
 1.14987 +
 1.14988 +    //! Get a square region of the image.
 1.14989 +    /**
 1.14990 +       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 1.14991 +       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 1.14992 +       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 1.14993 +       \param v0 = V-coordinate of the upper-left crop rectangle corner.
 1.14994 +       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 1.14995 +       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 1.14996 +       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 1.14997 +       \param v1 = V-coordinate of the lower-right crop rectangle corner.
 1.14998 +       \param border_condition = Dirichlet (false) or Neumann border conditions.
 1.14999 +    **/
 1.15000 +    CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
 1.15001 +                  const int x1, const int y1, const int z1, const int v1,
 1.15002 +                  const bool border_condition=false) {
 1.15003 +      return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
 1.15004 +    }
 1.15005 +
 1.15006 +    CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
 1.15007 +                     const int x1, const int y1, const int z1, const int v1,
 1.15008 +                     const bool border_condition=false) const {
 1.15009 +      if (is_empty()) return *this;
 1.15010 +      const int
 1.15011 +        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
 1.15012 +        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
 1.15013 +        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
 1.15014 +        nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
 1.15015 +      CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
 1.15016 +      if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
 1.15017 +        if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
 1.15018 +        else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
 1.15019 +      } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
 1.15020 +      return dest;
 1.15021 +    }
 1.15022 +
 1.15023 +    //! Get a rectangular part of the instance image.
 1.15024 +    /**
 1.15025 +       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 1.15026 +       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 1.15027 +       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 1.15028 +       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 1.15029 +       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 1.15030 +       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 1.15031 +       \param border_condition = determine the type of border condition if
 1.15032 +       some of the desired region is outside the image.
 1.15033 +    **/
 1.15034 +    CImg<T>& crop(const int x0, const int y0, const int z0,
 1.15035 +                  const int x1, const int y1, const int z1,
 1.15036 +                  const bool border_condition=false) {
 1.15037 +      return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 1.15038 +    }
 1.15039 +
 1.15040 +    CImg<T> get_crop(const int x0, const int y0, const int z0,
 1.15041 +                     const int x1, const int y1, const int z1,
 1.15042 +                     const bool border_condition=false) const {
 1.15043 +      return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 1.15044 +    }
 1.15045 +
 1.15046 +    //! Get a rectangular part of the instance image.
 1.15047 +    /**
 1.15048 +       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 1.15049 +       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 1.15050 +       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 1.15051 +       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 1.15052 +       \param border_condition = determine the type of border condition if
 1.15053 +       some of the desired region is outside the image.
 1.15054 +    **/
 1.15055 +    CImg<T>& crop(const int x0, const int y0,
 1.15056 +                  const int x1, const int y1,
 1.15057 +                  const bool border_condition=false) {
 1.15058 +      return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 1.15059 +    }
 1.15060 +
 1.15061 +    CImg<T> get_crop(const int x0, const int y0,
 1.15062 +                     const int x1, const int y1,
 1.15063 +                     const bool border_condition=false) const {
 1.15064 +      return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 1.15065 +    }
 1.15066 +
 1.15067 +    //! Get a rectangular part of the instance image.
 1.15068 +    /**
 1.15069 +       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 1.15070 +       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 1.15071 +       \param border_condition = determine the type of border condition if
 1.15072 +       some of the desired region is outside the image.
 1.15073 +    **/
 1.15074 +    CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
 1.15075 +      return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 1.15076 +    }
 1.15077 +
 1.15078 +    CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
 1.15079 +      return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 1.15080 +    }
 1.15081 +
 1.15082 +    //! Autocrop an image, regarding of the specified backround value.
 1.15083 +    CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
 1.15084 +      if (is_empty()) return *this;
 1.15085 +      const int lmax = cimg::strlen(axes);
 1.15086 +      for (int l = 0; l<lmax; ++l) autocrop(value,axes[l]);
 1.15087 +      return *this;
 1.15088 +    }
 1.15089 +
 1.15090 +    CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
 1.15091 +      return (+*this).autocrop(value,axes);
 1.15092 +    }
 1.15093 +
 1.15094 +    //! Autocrop an image, regarding of the specified backround color.
 1.15095 +    CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
 1.15096 +      if (is_empty()) return *this;
 1.15097 +      const int lmax = cimg::strlen(axes);
 1.15098 +      for (int l = 0; l<lmax; ++l) autocrop(color,axes[l]);
 1.15099 +      return *this;
 1.15100 +    }
 1.15101 +
 1.15102 +    CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
 1.15103 +      return (+*this).autocrop(color,axes);
 1.15104 +    }
 1.15105 +
 1.15106 +    //! Autocrop an image, regarding of the specified backround color.
 1.15107 +    template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
 1.15108 +      return get_autocrop(color,axes).transfer_to(*this);
 1.15109 +    }
 1.15110 +
 1.15111 +    template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
 1.15112 +      return get_autocrop(color.data,axes);
 1.15113 +    }
 1.15114 +
 1.15115 +    //! Autocrop an image along specified axis, regarding of the specified backround value.
 1.15116 +    CImg<T>& autocrop(const T value, const char axis) {
 1.15117 +      return get_autocrop(value,axis).transfer_to(*this);
 1.15118 +    }
 1.15119 +
 1.15120 +    CImg<T> get_autocrop(const T value, const char axis) const {
 1.15121 +      if (is_empty()) return *this;
 1.15122 +      CImg<T> res;
 1.15123 +      const CImg<intT> coords = _get_autocrop(value,axis);
 1.15124 +      switch (cimg::uncase(axis)) {
 1.15125 +        case 'x' : {
 1.15126 +          const int x0 = coords[0], x1 = coords[1];
 1.15127 +          if (x0>=0 && x1>=0) res = get_crop(x0,x1);
 1.15128 +        } break;
 1.15129 +        case 'y' : {
 1.15130 +          const int y0 = coords[0], y1 = coords[1];
 1.15131 +          if (y0>=0 && y1>=0) res = get_crop(0,y0,width-1,y1);
 1.15132 +        } break;
 1.15133 +        case 'z' : {
 1.15134 +          const int z0 = coords[0], z1 = coords[1];
 1.15135 +          if (z0>=0 && z1>=0) res = get_crop(0,0,z0,width-1,height-1,z1);
 1.15136 +        } break;
 1.15137 +        case 'v' : {
 1.15138 +          const int v0 = coords[0], v1 = coords[1];
 1.15139 +          if (v0>=0 && v1>=0) res = get_crop(0,0,0,v0,width-1,height-1,depth-1,v1);
 1.15140 +        } break;
 1.15141 +      }
 1.15142 +      return res;
 1.15143 +    }
 1.15144 +
 1.15145 +    //! Autocrop an image along specified axis, regarding of the specified backround color.
 1.15146 +    CImg<T>& autocrop(const T *const color, const char axis) {
 1.15147 +      return get_autocrop(color,axis).transfer_to(*this);
 1.15148 +    }
 1.15149 +
 1.15150 +    CImg<T> get_autocrop(const T *const color, const char axis) const {
 1.15151 +      if (is_empty()) return *this;
 1.15152 +      CImg<T> res;
 1.15153 +      switch (cimg::uncase(axis)) {
 1.15154 +        case 'x' : {
 1.15155 +          int x0 = width, x1 = -1;
 1.15156 +          cimg_forV(*this,k) {
 1.15157 +            const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 1.15158 +            const int nx0 = coords[0], nx1 = coords[1];
 1.15159 +            if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
 1.15160 +          }
 1.15161 +          if (x0<=x1) res = get_crop(x0,x1);
 1.15162 +        } break;
 1.15163 +        case 'y' : {
 1.15164 +          int y0 = height, y1 = -1;
 1.15165 +          cimg_forV(*this,k) {
 1.15166 +            const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 1.15167 +            const int ny0 = coords[0], ny1 = coords[1];
 1.15168 +            if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
 1.15169 +          }
 1.15170 +          if (y0<=y1) res = get_crop(0,y0,width-1,y1);
 1.15171 +        } break;
 1.15172 +        case 'z' : {
 1.15173 +          int z0 = depth, z1 = -1;
 1.15174 +          cimg_forV(*this,k) {
 1.15175 +            const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
 1.15176 +            const int nz0 = coords[0], nz1 = coords[1];
 1.15177 +            if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
 1.15178 +          }
 1.15179 +          if (z0<=z1) res = get_crop(0,0,z0,width-1,height-1,z1);
 1.15180 +        } break;
 1.15181 +      default :
 1.15182 +          throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c', must be 'x','y' or 'z'.",
 1.15183 +                                      pixel_type(),axis);
 1.15184 +      }
 1.15185 +      return res;
 1.15186 +    }
 1.15187 +
 1.15188 +    //! Autocrop an image along specified axis, regarding of the specified backround color.
 1.15189 +    template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char axis) {
 1.15190 +      return get_autocrop(color,axis).transfer_to(*this);
 1.15191 +    }
 1.15192 +
 1.15193 +    template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char axis) const {
 1.15194 +      return get_autocrop(color.data,axis);
 1.15195 +    }
 1.15196 +
 1.15197 +    CImg<intT> _get_autocrop(const T value, const char axis) const {
 1.15198 +      CImg<intT> res;
 1.15199 +      int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
 1.15200 +      switch (cimg::uncase(axis)) {
 1.15201 +      case 'x' : {
 1.15202 +        cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
 1.15203 +          if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 1.15204 +        if (x0>=0) {
 1.15205 +          for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
 1.15206 +            if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
 1.15207 +        }
 1.15208 +        res = CImg<intT>::vector(x0,x1);
 1.15209 +      } break;
 1.15210 +      case 'y' : {
 1.15211 +        cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
 1.15212 +          if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 1.15213 +        if (y0>=0) {
 1.15214 +          for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
 1.15215 +            if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
 1.15216 +        }
 1.15217 +        res = CImg<intT>::vector(y0,y1);
 1.15218 +      } break;
 1.15219 +      case 'z' : {
 1.15220 +        cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
 1.15221 +          if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 1.15222 +        if (z0>=0) {
 1.15223 +          for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
 1.15224 +            if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
 1.15225 +        }
 1.15226 +        res = CImg<intT>::vector(z0,z1);
 1.15227 +      } break;
 1.15228 +      case 'v' : {
 1.15229 +        cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
 1.15230 +          if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
 1.15231 +        if (v0>=0) {
 1.15232 +          for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
 1.15233 +            if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
 1.15234 +        }
 1.15235 +        res = CImg<intT>::vector(v0,v1);
 1.15236 +      } break;
 1.15237 +      default :
 1.15238 +        throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
 1.15239 +                                    pixel_type(),axis);
 1.15240 +      }
 1.15241 +      return res;
 1.15242 +    }
 1.15243 +
 1.15244 +    //! Get a set of columns.
 1.15245 +    CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
 1.15246 +      return get_columns(x0,x1).transfer_to(*this);
 1.15247 +    }
 1.15248 +
 1.15249 +    CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
 1.15250 +      return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
 1.15251 +    }
 1.15252 +
 1.15253 +    //! Get one column.
 1.15254 +    CImg<T>& column(const unsigned int x0) {
 1.15255 +      return columns(x0,x0);
 1.15256 +    }
 1.15257 +
 1.15258 +    CImg<T> get_column(const unsigned int x0) const {
 1.15259 +      return get_columns(x0,x0);
 1.15260 +    }
 1.15261 +
 1.15262 +    //! Get a set of lines.
 1.15263 +    CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
 1.15264 +      return get_lines(y0,y1).transfer_to(*this);
 1.15265 +    }
 1.15266 +
 1.15267 +    CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
 1.15268 +      return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
 1.15269 +    }
 1.15270 +
 1.15271 +    //! Get a line.
 1.15272 +    CImg<T>& line(const unsigned int y0) {
 1.15273 +      return lines(y0,y0);
 1.15274 +    }
 1.15275 +
 1.15276 +    CImg<T> get_line(const unsigned int y0) const {
 1.15277 +      return get_lines(y0,y0);
 1.15278 +    }
 1.15279 +
 1.15280 +    //! Get a set of slices.
 1.15281 +    CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
 1.15282 +      return get_slices(z0,z1).transfer_to(*this);
 1.15283 +    }
 1.15284 +
 1.15285 +    CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
 1.15286 +      return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
 1.15287 +    }
 1.15288 +
 1.15289 +    //! Get a slice.
 1.15290 +    CImg<T>& slice(const unsigned int z0) {
 1.15291 +      return slices(z0,z0);
 1.15292 +    }
 1.15293 +
 1.15294 +    CImg<T> get_slice(const unsigned int z0) const {
 1.15295 +      return get_slices(z0,z0);
 1.15296 +    }
 1.15297 +
 1.15298 +    //! Get a set of channels.
 1.15299 +    CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
 1.15300 +      return get_channels(v0,v1).transfer_to(*this);
 1.15301 +    }
 1.15302 +
 1.15303 +    CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
 1.15304 +      return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
 1.15305 +    }
 1.15306 +
 1.15307 +    //! Get a channel.
 1.15308 +    CImg<T>& channel(const unsigned int v0) {
 1.15309 +      return channels(v0,v0);
 1.15310 +    }
 1.15311 +
 1.15312 +    CImg<T> get_channel(const unsigned int v0) const {
 1.15313 +      return get_channels(v0,v0);
 1.15314 +    }
 1.15315 +
 1.15316 +    //! Get a shared-memory image referencing a set of points of the instance image.
 1.15317 +    CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 1.15318 +                              const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
 1.15319 +      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 1.15320 +      if (beg>end || beg>=size() || end>=size())
 1.15321 +        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 1.15322 +                                    "a (%u,%u,%u,%u) image.",
 1.15323 +                                    pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 1.15324 +      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 1.15325 +    }
 1.15326 +
 1.15327 +    const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 1.15328 +                                    const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
 1.15329 +      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 1.15330 +      if (beg>end || beg>=size() || end>=size())
 1.15331 +        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 1.15332 +                                    "a (%u,%u,%u,%u) image.",
 1.15333 +                                    pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 1.15334 +      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 1.15335 +    }
 1.15336 +
 1.15337 +    //! Return a shared-memory image referencing a set of lines of the instance image.
 1.15338 +    CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 1.15339 +                             const unsigned int z0=0, const unsigned int v0=0) {
 1.15340 +      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 1.15341 +      if (beg>end || beg>=size() || end>=size())
 1.15342 +        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 1.15343 +                                    "a (%u,%u,%u,%u) image.",
 1.15344 +                                    pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 1.15345 +      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 1.15346 +    }
 1.15347 +
 1.15348 +    const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 1.15349 +                                   const unsigned int z0=0, const unsigned int v0=0) const {
 1.15350 +      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 1.15351 +      if (beg>end || beg>=size() || end>=size())
 1.15352 +        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 1.15353 +                                    "a (%u,%u,%u,%u) image.",
 1.15354 +                                    pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 1.15355 +      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 1.15356 +    }
 1.15357 +
 1.15358 +    //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
 1.15359 +    CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
 1.15360 +      return get_shared_lines(y0,y0,z0,v0);
 1.15361 +    }
 1.15362 +
 1.15363 +    const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
 1.15364 +      return get_shared_lines(y0,y0,z0,v0);
 1.15365 +    }
 1.15366 +
 1.15367 +    //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
 1.15368 +    CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
 1.15369 +      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 1.15370 +      if (beg>end || beg>=size() || end>=size())
 1.15371 +        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 1.15372 +                                    "a (%u,%u,%u,%u) image.",
 1.15373 +                                    pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 1.15374 +      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 1.15375 +    }
 1.15376 +
 1.15377 +    const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
 1.15378 +      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 1.15379 +      if (beg>end || beg>=size() || end>=size())
 1.15380 +        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 1.15381 +                                    "a (%u,%u,%u,%u) image.",
 1.15382 +                                    pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 1.15383 +      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 1.15384 +    }
 1.15385 +
 1.15386 +    //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
 1.15387 +    CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
 1.15388 +      return get_shared_planes(z0,z0,v0);
 1.15389 +    }
 1.15390 +
 1.15391 +    const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
 1.15392 +      return get_shared_planes(z0,z0,v0);
 1.15393 +    }
 1.15394 +
 1.15395 +    //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
 1.15396 +    CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
 1.15397 +      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 1.15398 +      if (beg>end || beg>=size() || end>=size())
 1.15399 +        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 1.15400 +                                    "a (%u,%u,%u,%u) image.",
 1.15401 +                                    pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 1.15402 +      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 1.15403 +    }
 1.15404 +
 1.15405 +    const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
 1.15406 +      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 1.15407 +      if (beg>end || beg>=size() || end>=size())
 1.15408 +        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 1.15409 +                                    "a (%u,%u,%u,%u) image.",
 1.15410 +                                    pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 1.15411 +      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 1.15412 +    }
 1.15413 +
 1.15414 +    //! Return a shared-memory image referencing one channel v0 of the instance image.
 1.15415 +    CImg<T> get_shared_channel(const unsigned int v0) {
 1.15416 +      return get_shared_channels(v0,v0);
 1.15417 +    }
 1.15418 +
 1.15419 +    const CImg<T> get_shared_channel(const unsigned int v0) const {
 1.15420 +      return get_shared_channels(v0,v0);
 1.15421 +    }
 1.15422 +
 1.15423 +    //! Return a shared version of the instance image.
 1.15424 +    CImg<T> get_shared() {
 1.15425 +      return CImg<T>(data,width,height,depth,dim,true);
 1.15426 +    }
 1.15427 +
 1.15428 +    const CImg<T> get_shared() const {
 1.15429 +      return CImg<T>(data,width,height,depth,dim,true);
 1.15430 +    }
 1.15431 +
 1.15432 +    //! Return a 2D representation of a 3D image, with three slices.
 1.15433 +    CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 1.15434 +                           const int dx=-100, const int dy=-100, const int dz=-100) {
 1.15435 +      return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
 1.15436 +    }
 1.15437 +
 1.15438 +    CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 1.15439 +                              const int dx=-100, const int dy=-100, const int dz=-100) const {
 1.15440 +      if (is_empty()) return *this;
 1.15441 +      const unsigned int
 1.15442 +        nx0 = (x0>=width)?width-1:x0,
 1.15443 +        ny0 = (y0>=height)?height-1:y0,
 1.15444 +        nz0 = (z0>=depth)?depth-1:z0;
 1.15445 +      CImg<T>
 1.15446 +        imgxy(width,height,1,dim),
 1.15447 +        imgzy(depth,height,1,dim),
 1.15448 +        imgxz(width,depth,1,dim);
 1.15449 +      { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
 1.15450 +      { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
 1.15451 +      { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
 1.15452 +      imgxy.resize(dx,dy,1,dim,1);
 1.15453 +      imgzy.resize(dz,dy,1,dim,1);
 1.15454 +      imgxz.resize(dx,dz,1,dim,1);
 1.15455 +      return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
 1.15456 +        draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
 1.15457 +    }
 1.15458 +
 1.15459 +    //! Compute the image histogram.
 1.15460 +    /**
 1.15461 +       The histogram H of an image I is a 1D-function where H(x) is the number of
 1.15462 +       occurences of the value x in I.
 1.15463 +       \param nblevels = Number of different levels of the computed histogram.
 1.15464 +       For classical images, this value is 256. You should specify more levels
 1.15465 +       if you are working with CImg<float> or images with high range of pixel values.
 1.15466 +       \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
 1.15467 +       won't be counted.
 1.15468 +       \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
 1.15469 +       won't be counted.
 1.15470 +       \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum
 1.15471 +       pixel values of the current image, then uses these values for the histogram computation.
 1.15472 +       \result The histogram is returned as a 1D CImg<float> image H, having a size of (nblevels,1,1,1) such that
 1.15473 +       H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I.
 1.15474 +       \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
 1.15475 +       are not multi-dimensional.
 1.15476 +    **/
 1.15477 +    CImg<T>& histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
 1.15478 +      return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
 1.15479 +    }
 1.15480 +
 1.15481 +    CImg<floatT> get_histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
 1.15482 +      if (is_empty()) return CImg<floatT>();
 1.15483 +      if (!nblevels)
 1.15484 +        throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
 1.15485 +                                    pixel_type());
 1.15486 +      T vmin = val_min, vmax = val_max;
 1.15487 +      CImg<floatT> res(nblevels,1,1,1,0);
 1.15488 +      if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
 1.15489 +      if (vmin<vmax) cimg_for(*this,ptr,T) {
 1.15490 +        const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
 1.15491 +        if (pos>=0 && pos<(int)nblevels) ++res[pos];
 1.15492 +      } else res[0]+=size();
 1.15493 +      return res;
 1.15494 +    }
 1.15495 +
 1.15496 +    //! Compute the histogram-equalized version of the instance image.
 1.15497 +    /**
 1.15498 +       The histogram equalization is a classical image processing algorithm that enhances the image contrast
 1.15499 +       by expanding its histogram.
 1.15500 +       \param nblevels = Number of different levels of the computed histogram.
 1.15501 +       For classical images, this value is 256. You should specify more levels
 1.15502 +       if you are working with CImg<float> or images with high range of pixel values.
 1.15503 +       \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
 1.15504 +       won't be changed.
 1.15505 +       \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
 1.15506 +       won't be changed.
 1.15507 +       \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
 1.15508 +       \return A new image with same size is returned, where pixels have been equalized.
 1.15509 +    **/
 1.15510 +    CImg<T>& equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
 1.15511 +      if (is_empty()) return *this;
 1.15512 +      T vmin = val_min, vmax = val_max;
 1.15513 +      if (vmin==vmax && vmin==0) vmin = minmax(vmax);
 1.15514 +      if (vmin<vmax) {
 1.15515 +        CImg<floatT> hist = get_histogram(nblevels,vmin,vmax);
 1.15516 +        float cumul = 0;
 1.15517 +        cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
 1.15518 +        cimg_for(*this,ptr,T) {
 1.15519 +          const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
 1.15520 +          if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
 1.15521 +        }
 1.15522 +      }
 1.15523 +      return *this;
 1.15524 +    }
 1.15525 +
 1.15526 +    CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
 1.15527 +      return (+*this).equalize(nblevels,val_min,val_max);
 1.15528 +    }
 1.15529 +
 1.15530 +    //! Get a label map of disconnected regions with same intensities.
 1.15531 +    CImg<T>& label_regions() {
 1.15532 +      return get_label_regions().transfer_to(*this);
 1.15533 +    }
 1.15534 +
 1.15535 +    CImg<uintT> get_label_regions() const {
 1.15536 +#define _cimg_get_label_test(p,q) { \
 1.15537 +  flag = true; \
 1.15538 +  const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
 1.15539 +  for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
 1.15540 +}
 1.15541 +      if (depth>1)
 1.15542 +        throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
 1.15543 +      CImg<uintT> res(width,height,depth,1,0);
 1.15544 +      unsigned int label = 1;
 1.15545 +      const unsigned int wh = width*height, siz = width*height*dim;
 1.15546 +      const int W1 = dimx()-1, H1 = dimy()-1;
 1.15547 +      bool flag;
 1.15548 +      cimg_forXY(*this,x,y) {
 1.15549 +        bool done = false;
 1.15550 +        if (y) {
 1.15551 +          _cimg_get_label_test(x,y-1);
 1.15552 +          if (flag) {
 1.15553 +            const unsigned int lab = (res(x,y) = res(x,y-1));
 1.15554 +            done = true;
 1.15555 +            if (x && res(x-1,y)!=lab) {
 1.15556 +              _cimg_get_label_test(x-1,y);
 1.15557 +              if (flag) {
 1.15558 +                const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
 1.15559 +                for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
 1.15560 +              }
 1.15561 +            }
 1.15562 +          }
 1.15563 +        }
 1.15564 +        if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
 1.15565 +        if (!done) res(x,y) = label++;
 1.15566 +      }
 1.15567 +      { for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
 1.15568 +        bool done = false;
 1.15569 +        if (y<H1) {
 1.15570 +          _cimg_get_label_test(x,y+1);
 1.15571 +          if (flag) {
 1.15572 +            const unsigned int lab = (res(x,y) = res(x,y+1));
 1.15573 +            done = true;
 1.15574 +            if (x<W1 && res(x+1,y)!=lab) {
 1.15575 +              _cimg_get_label_test(x+1,y);
 1.15576 +              if (flag) {
 1.15577 +                const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
 1.15578 +                for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
 1.15579 +              }
 1.15580 +            }
 1.15581 +          }
 1.15582 +        }
 1.15583 +        if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
 1.15584 +      }}
 1.15585 +      const unsigned int lab0 = res.max()+1;
 1.15586 +      label = lab0;
 1.15587 +      cimg_foroff(res,off) { // Relabel regions
 1.15588 +        const unsigned int lab = res[off];
 1.15589 +        if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
 1.15590 +      }
 1.15591 +      return (res-=lab0);
 1.15592 +    }
 1.15593 +
 1.15594 +    //! Compute the scalar image of vector norms.
 1.15595 +    /**
 1.15596 +       When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
 1.15597 +       vector-valued pixel.
 1.15598 +       \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
 1.15599 +       \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
 1.15600 +       of the corresponding pixels in the original vector-valued image.
 1.15601 +    **/
 1.15602 +    CImg<T>& pointwise_norm(int norm_type=2) {
 1.15603 +      return get_pointwise_norm(norm_type).transfer_to(*this);
 1.15604 +    }
 1.15605 +
 1.15606 +    CImg<Tfloat> get_pointwise_norm(int norm_type=2) const {
 1.15607 +      if (is_empty()) return *this;
 1.15608 +      if (dim==1) return get_abs();
 1.15609 +      CImg<Tfloat> res(width,height,depth);
 1.15610 +      switch (norm_type) {
 1.15611 +      case -1 : {             // Linf norm
 1.15612 +        cimg_forXYZ(*this,x,y,z) {
 1.15613 +          Tfloat n = 0; cimg_forV(*this,v) {
 1.15614 +            const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
 1.15615 +            if (tmp>n) n=tmp; res(x,y,z) = n;
 1.15616 +          }
 1.15617 +        }
 1.15618 +      } break;
 1.15619 +      case 1 : {              // L1 norm
 1.15620 +        cimg_forXYZ(*this,x,y,z) {
 1.15621 +          Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
 1.15622 +        }
 1.15623 +      } break;
 1.15624 +      default : {             // L2 norm
 1.15625 +        cimg_forXYZ(*this,x,y,z) {
 1.15626 +          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);
 1.15627 +        }
 1.15628 +      }
 1.15629 +      }
 1.15630 +      return res;
 1.15631 +    }
 1.15632 +
 1.15633 +    //! Compute the image of normalized vectors.
 1.15634 +    /**
 1.15635 +       When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
 1.15636 +       (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
 1.15637 +       \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
 1.15638 +    **/
 1.15639 +    CImg<T>& pointwise_orientation() {
 1.15640 +      cimg_forXYZ(*this,x,y,z) {
 1.15641 +        float n = 0;
 1.15642 +        cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
 1.15643 +        n = (float)cimg_std::sqrt(n);
 1.15644 +        if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
 1.15645 +        else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
 1.15646 +      }
 1.15647 +      return *this;
 1.15648 +    }
 1.15649 +
 1.15650 +    CImg<Tfloat> get_pointwise_orientation() const {
 1.15651 +      if (is_empty()) return *this;
 1.15652 +      return CImg<Tfloat>(*this,false).pointwise_orientation();
 1.15653 +    }
 1.15654 +
 1.15655 +    //! Split image into a list.
 1.15656 +    CImgList<T> get_split(const char axis, const unsigned int nb=0) const {
 1.15657 +      if (is_empty()) return CImgList<T>();
 1.15658 +      CImgList<T> res;
 1.15659 +      switch (cimg::uncase(axis)) {
 1.15660 +      case 'x' : {
 1.15661 +        if (nb>width)
 1.15662 +          throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.",
 1.15663 +                                      pixel_type(),width,height,depth,dim,data,nb);
 1.15664 +        res.assign(nb?nb:width);
 1.15665 +        const unsigned int delta = (unsigned int)cimg::round((float)width/res.size,1);
 1.15666 +        unsigned int l, x;
 1.15667 +        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);
 1.15668 +        res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1);
 1.15669 +      } break;
 1.15670 +      case 'y' : {
 1.15671 +        if (nb>height)
 1.15672 +          throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.",
 1.15673 +                                      pixel_type(),width,height,depth,dim,data,nb);
 1.15674 +        res.assign(nb?nb:height);
 1.15675 +        const unsigned int delta = (unsigned int)cimg::round((float)height/res.size,1);
 1.15676 +        unsigned int l, y;
 1.15677 +        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);
 1.15678 +        res[res.size-1] = get_crop(0,y,0,0,width-1,height-1,depth-1,dim-1);
 1.15679 +      } break;
 1.15680 +      case 'z' : {
 1.15681 +        if (nb>depth)
 1.15682 +          throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.",
 1.15683 +                                      pixel_type(),width,height,depth,dim,data,nb);
 1.15684 +        res.assign(nb?nb:depth);
 1.15685 +        const unsigned int delta = (unsigned int)cimg::round((float)depth/res.size,1);
 1.15686 +        unsigned int l, z;
 1.15687 +        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);
 1.15688 +        res[res.size-1] = get_crop(0,0,z,0,width-1,height-1,depth-1,dim-1);
 1.15689 +      } break;
 1.15690 +      case 'v' : {
 1.15691 +        if (nb>dim)
 1.15692 +          throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.",
 1.15693 +                                      pixel_type(),width,height,depth,dim,data,nb);
 1.15694 +        res.assign(nb?nb:dim);
 1.15695 +        const unsigned int delta = (unsigned int)cimg::round((float)dim/res.size,1);
 1.15696 +        unsigned int l, v;
 1.15697 +        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);
 1.15698 +        res[res.size-1] = get_crop(0,0,0,v,width-1,height-1,depth-1,dim-1);
 1.15699 +      } break;
 1.15700 +      default :
 1.15701 +        throw CImgArgumentException("CImg<%s>::get_split() : Unknow axis '%c', must be 'x','y','z' or 'v'",
 1.15702 +                                    pixel_type(),axis);
 1.15703 +      }
 1.15704 +      return res;
 1.15705 +    }
 1.15706 +
 1.15707 +    // Split image into a list of vectors, according to a given splitting value.
 1.15708 +    CImgList<T> get_split(const T value, const bool keep_values, const bool shared) const {
 1.15709 +      CImgList<T> res;
 1.15710 +      const T *ptr0 = data, *const ptr_end = data + size();
 1.15711 +      while (ptr0<ptr_end) {
 1.15712 +        const T *ptr1 = ptr0;
 1.15713 +        while (ptr1<ptr_end && *ptr1==value) ++ptr1;
 1.15714 +        const unsigned int siz0 = ptr1 - ptr0;
 1.15715 +        if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
 1.15716 +        ptr0 = ptr1;
 1.15717 +        while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
 1.15718 +        const unsigned int siz1 = ptr1 - ptr0;
 1.15719 +        if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
 1.15720 +        ptr0 = ptr1;
 1.15721 +      }
 1.15722 +      return res;
 1.15723 +    }
 1.15724 +
 1.15725 +    //! Append an image to another one.
 1.15726 +    CImg<T>& append(const CImg<T>& img, const char axis, const char align='p') {
 1.15727 +      if (!img) return *this;
 1.15728 +      if (is_empty()) return (*this=img);
 1.15729 +      return get_append(img,axis,align).transfer_to(*this);
 1.15730 +    }
 1.15731 +
 1.15732 +    CImg<T> get_append(const CImg<T>& img, const char axis, const char align='p') const {
 1.15733 +      if (!img) return *this;
 1.15734 +      if (is_empty()) return img;
 1.15735 +      CImgList<T> temp(2);
 1.15736 +      temp[0].width = width; temp[0].height = height; temp[0].depth = depth;
 1.15737 +      temp[0].dim = dim; temp[0].data = data;
 1.15738 +      temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth;
 1.15739 +      temp[1].dim = img.dim; temp[1].data = img.data;
 1.15740 +      const CImg<T> res = temp.get_append(axis,align);
 1.15741 +      temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0;
 1.15742 +      temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0;
 1.15743 +      return res;
 1.15744 +    }
 1.15745 +
 1.15746 +    //! Compute the list of images, corresponding to the XY-gradients of an image.
 1.15747 +    /**
 1.15748 +       \param scheme = Numerical scheme used for the gradient computation :
 1.15749 +       - -1 = Backward finite differences
 1.15750 +       - 0 = Centered finite differences
 1.15751 +       - 1 = Forward finite differences
 1.15752 +       - 2 = Using Sobel masks
 1.15753 +       - 3 = Using rotation invariant masks
 1.15754 +       - 4 = Using Deriche recusrsive filter.
 1.15755 +    **/
 1.15756 +    CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
 1.15757 +      CImgList<Tfloat> grad(2,width,height,depth,dim);
 1.15758 +      bool threed = false;
 1.15759 +      if (axes) {
 1.15760 +        for (unsigned int a = 0; axes[a]; ++a) {
 1.15761 +          const char axis = cimg::uncase(axes[a]);
 1.15762 +          switch (axis) {
 1.15763 +          case 'x' : case 'y' : break;
 1.15764 +          case 'z' : threed = true; break;
 1.15765 +          default :
 1.15766 +            throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
 1.15767 +                                        pixel_type(),axis);
 1.15768 +          }
 1.15769 +        }
 1.15770 +      } else threed = (depth>1);
 1.15771 +      if (threed) {
 1.15772 +        grad.insert(1); grad[2].assign(width,height,depth,dim);
 1.15773 +        switch (scheme) { // Compute 3D gradient
 1.15774 +        case -1 : { // backward finite differences
 1.15775 +          CImg_3x3x3(I,T);
 1.15776 +          cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 1.15777 +            grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
 1.15778 +            grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
 1.15779 +            grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
 1.15780 +          }
 1.15781 +        } break;
 1.15782 +        case 1 : { // forward finite differences
 1.15783 +          CImg_2x2x2(I,T);
 1.15784 +          cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
 1.15785 +            grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
 1.15786 +            grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
 1.15787 +            grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
 1.15788 +          }
 1.15789 +        } break;
 1.15790 +        case 4 : { // using Deriche filter with low standard variation
 1.15791 +          grad[0] = get_deriche(0,1,'x');
 1.15792 +          grad[1] = get_deriche(0,1,'y');
 1.15793 +          grad[2] = get_deriche(0,1,'z');
 1.15794 +        } break;
 1.15795 +        default : { // central finite differences
 1.15796 +          CImg_3x3x3(I,T);
 1.15797 +          cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 1.15798 +            grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
 1.15799 +            grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
 1.15800 +            grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
 1.15801 +          }
 1.15802 +        }
 1.15803 +        }
 1.15804 +      } else switch (scheme) { // Compute 2D-gradient
 1.15805 +      case -1 : { // backward finite differences
 1.15806 +        CImg_3x3(I,T);
 1.15807 +        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 1.15808 +          grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
 1.15809 +          grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
 1.15810 +        }
 1.15811 +      } break;
 1.15812 +      case 1 : { // forward finite differences
 1.15813 +        CImg_2x2(I,T);
 1.15814 +        cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
 1.15815 +          grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
 1.15816 +          grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
 1.15817 +        }
 1.15818 +      } break;
 1.15819 +      case 2 : { // using Sobel mask
 1.15820 +        CImg_3x3(I,T);
 1.15821 +        const Tfloat a = 1, b = 2;
 1.15822 +        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 1.15823 +          grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
 1.15824 +          grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
 1.15825 +        }
 1.15826 +      } break;
 1.15827 +      case 3 : { // using rotation invariant mask
 1.15828 +        CImg_3x3(I,T);
 1.15829 +        const Tfloat a = (Tfloat)(0.25f*(2-cimg_std::sqrt(2.0f))), b = (Tfloat)(0.5f*(cimg_std::sqrt(2.0f)-1));
 1.15830 +        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 1.15831 +          grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
 1.15832 +          grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
 1.15833 +        }
 1.15834 +      } break;
 1.15835 +      case 4 : { // using Deriche filter with low standard variation
 1.15836 +        grad[0] = get_deriche(0,1,'x');
 1.15837 +        grad[1] = get_deriche(0,1,'y');
 1.15838 +      } break;
 1.15839 +      default : { // central finite differences
 1.15840 +        CImg_3x3(I,T);
 1.15841 +        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 1.15842 +          grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
 1.15843 +          grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
 1.15844 +        }
 1.15845 +      }
 1.15846 +      }
 1.15847 +      if (!axes) return grad;
 1.15848 +      CImgList<Tfloat> res;
 1.15849 +      for (unsigned int l = 0; axes[l]; ++l) {
 1.15850 +        const char axis = cimg::uncase(axes[l]);
 1.15851 +        switch (axis) {
 1.15852 +        case 'x' : res.insert(grad[0]); break;
 1.15853 +        case 'y' : res.insert(grad[1]); break;
 1.15854 +        case 'z' : res.insert(grad[2]); break;
 1.15855 +        }
 1.15856 +      }
 1.15857 +      grad.assign();
 1.15858 +      return res;
 1.15859 +    }
 1.15860 +
 1.15861 +    //! Compute the structure tensor field of an image.
 1.15862 +    CImg<T>& structure_tensor(const bool central_scheme=false) {
 1.15863 +      return get_structure_tensor(central_scheme).transfer_to(*this);
 1.15864 +    }
 1.15865 +
 1.15866 +    CImg<Tfloat> get_structure_tensor(const bool central_scheme=false) const {
 1.15867 +      if (is_empty()) return *this;
 1.15868 +      CImg<Tfloat> res;
 1.15869 +      if (depth>1) { // 3D version
 1.15870 +        res.assign(width,height,depth,6,0);
 1.15871 +        CImg_3x3x3(I,T);
 1.15872 +        if (central_scheme) cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // classical central finite differences
 1.15873 +          const Tfloat
 1.15874 +            ix = 0.5f*((Tfloat)Incc - Ipcc),
 1.15875 +            iy = 0.5f*((Tfloat)Icnc - Icpc),
 1.15876 +            iz = 0.5f*((Tfloat)Iccn - Iccp);
 1.15877 +          res(x,y,z,0)+=ix*ix;
 1.15878 +          res(x,y,z,1)+=ix*iy;
 1.15879 +          res(x,y,z,2)+=ix*iz;
 1.15880 +          res(x,y,z,3)+=iy*iy;
 1.15881 +          res(x,y,z,4)+=iy*iz;
 1.15882 +          res(x,y,z,5)+=iz*iz;
 1.15883 +        } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // Precise forward/backward finite differences
 1.15884 +          const Tfloat
 1.15885 +            ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
 1.15886 +            iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
 1.15887 +            izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
 1.15888 +          res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
 1.15889 +          res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
 1.15890 +          res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
 1.15891 +          res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
 1.15892 +          res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
 1.15893 +          res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
 1.15894 +        }
 1.15895 +      } else { // 2D version
 1.15896 +        res.assign(width,height,depth,3,0);
 1.15897 +        CImg_3x3(I,T);
 1.15898 +        if (central_scheme) cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // classical central finite differences
 1.15899 +          const Tfloat
 1.15900 +            ix = 0.5f*((Tfloat)Inc - Ipc),
 1.15901 +            iy = 0.5f*((Tfloat)Icn - Icp);
 1.15902 +          res(x,y,0,0)+=ix*ix;
 1.15903 +          res(x,y,0,1)+=ix*iy;
 1.15904 +          res(x,y,0,2)+=iy*iy;
 1.15905 +        } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // Precise forward/backward finite differences
 1.15906 +          const Tfloat
 1.15907 +            ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
 1.15908 +            iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
 1.15909 +          res(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
 1.15910 +          res(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
 1.15911 +          res(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
 1.15912 +        }
 1.15913 +      }
 1.15914 +      return res;
 1.15915 +    }
 1.15916 +
 1.15917 +    //! Get components of the Hessian matrix of an image.
 1.15918 +    CImgList<Tfloat> get_hessian(const char *const axes=0) const {
 1.15919 +      const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
 1.15920 +      if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
 1.15921 +      CImgList<Tfloat> res;
 1.15922 +      const int lmax = cimg::strlen(naxes);
 1.15923 +      if (lmax%2)
 1.15924 +        throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
 1.15925 +                                    pixel_type(),naxes);
 1.15926 +      res.assign(lmax/2,width,height,depth,dim);
 1.15927 +      if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
 1.15928 +        CImg_3x3x3(I,T);
 1.15929 +        cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 1.15930 +          res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc;              // Ixx
 1.15931 +          res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
 1.15932 +          res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
 1.15933 +          res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc;              // Iyy
 1.15934 +          res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
 1.15935 +          res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;              // Izz
 1.15936 +        }
 1.15937 +      } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
 1.15938 +        CImg_3x3(I,T);
 1.15939 +        cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 1.15940 +          res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc;             // Ixx
 1.15941 +          res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
 1.15942 +          res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc;             // Iyy
 1.15943 +        }
 1.15944 +      } else for (int l = 0; l<lmax; ) { // Version with custom axes.
 1.15945 +          const int l2 = l/2;
 1.15946 +          char axis1 = naxes[l++], axis2 = naxes[l++];
 1.15947 +          if (axis1>axis2) cimg::swap(axis1,axis2);
 1.15948 +          bool valid_axis = false;
 1.15949 +          if (axis1=='x' && axis2=='x') { // Ixx
 1.15950 +            valid_axis = true; CImg_3x3(I,T);
 1.15951 +            cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
 1.15952 +          }
 1.15953 +          else if (axis1=='x' && axis2=='y') { // Ixy
 1.15954 +            valid_axis = true; CImg_3x3(I,T);
 1.15955 +            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);
 1.15956 +          }
 1.15957 +          else if (axis1=='x' && axis2=='z') { // Ixz
 1.15958 +            valid_axis = true; CImg_3x3x3(I,T);
 1.15959 +            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);
 1.15960 +          }
 1.15961 +          else if (axis1=='y' && axis2=='y') { // Iyy
 1.15962 +            valid_axis = true; CImg_3x3(I,T);
 1.15963 +            cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
 1.15964 +          }
 1.15965 +          else if (axis1=='y' && axis2=='z') { // Iyz
 1.15966 +            valid_axis = true; CImg_3x3x3(I,T);
 1.15967 +            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);
 1.15968 +          }
 1.15969 +          else if (axis1=='z' && axis2=='z') { // Izz
 1.15970 +            valid_axis = true; CImg_3x3x3(I,T);
 1.15971 +            cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
 1.15972 +          }
 1.15973 +          else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
 1.15974 +                                                            pixel_type(),naxes);
 1.15975 +      }
 1.15976 +      return res;
 1.15977 +    }
 1.15978 +
 1.15979 +    //! Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE.
 1.15980 +    CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
 1.15981 +      if (is_empty()) return *this;
 1.15982 +      CImg<Tfloat> veloc(*this);
 1.15983 +      for (unsigned int iter = 0; iter<nb_iter; ++iter) {
 1.15984 +        veloc.fill(0);
 1.15985 +        if (depth>1) { // 3D version
 1.15986 +          CImg_3x3x3(I,T);
 1.15987 +          cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
 1.15988 +            const Tfloat
 1.15989 +              gx = 0.5f*((Tfloat)Incc - Ipcc),
 1.15990 +              gy = 0.5f*((Tfloat)Icnc - Icpc),
 1.15991 +              gz = 0.5f*((Tfloat)Iccn - Iccp),
 1.15992 +              sgn = -cimg::sign((Tfloat)Iccc),
 1.15993 +              ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
 1.15994 +              iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
 1.15995 +              iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
 1.15996 +              ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy + gz*gz),
 1.15997 +              ngx = gx/ng,
 1.15998 +              ngy = gy/ng,
 1.15999 +              ngz = gz/ng;
 1.16000 +            veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
 1.16001 +          }
 1.16002 +        } else { // 2D version
 1.16003 +          CImg_3x3(I,T);
 1.16004 +          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
 1.16005 +            const Tfloat
 1.16006 +              gx = 0.5f*((Tfloat)Inc - Ipc),
 1.16007 +              gy = 0.5f*((Tfloat)Icn - Icp),
 1.16008 +              sgn = -cimg::sign((Tfloat)Icc),
 1.16009 +              ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
 1.16010 +              iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
 1.16011 +              ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy),
 1.16012 +              ngx = gx/ng,
 1.16013 +              ngy = gy/ng;
 1.16014 +            veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
 1.16015 +          }
 1.16016 +        }
 1.16017 +        float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
 1.16018 +        *this+=(veloc*=xdt);
 1.16019 +      }
 1.16020 +      return *this;
 1.16021 +    }
 1.16022 +
 1.16023 +    CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
 1.16024 +      return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
 1.16025 +    }
 1.16026 +
 1.16027 +    //! Compute the Euclidean distance map to a shape of specified isovalue.
 1.16028 +    CImg<T>& distance(const T isovalue,
 1.16029 +                      const float sizex=1, const float sizey=1, const float sizez=1,
 1.16030 +                      const bool compute_sqrt=true) {
 1.16031 +      return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
 1.16032 +    }
 1.16033 +
 1.16034 +    CImg<floatT> get_distance(const T isovalue,
 1.16035 +                              const float sizex=1, const float sizey=1, const float sizez=1,
 1.16036 +                              const bool compute_sqrt=true) const {
 1.16037 +      if (is_empty()) return *this;
 1.16038 +      const int dx = dimx(), dy = dimy(), dz = dimz();
 1.16039 +      CImg<floatT> res(dx,dy,dz,dim);
 1.16040 +      const float maxdist = (float)cimg_std::sqrt((float)dx*dx + dy*dy + dz*dz);
 1.16041 +      cimg_forV(*this,k) {
 1.16042 +        bool is_isophote = false;
 1.16043 +
 1.16044 +        if (depth>1) { // 3D version
 1.16045 +          { cimg_forYZ(*this,y,z) {
 1.16046 +            if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
 1.16047 +            for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
 1.16048 +            else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
 1.16049 +            { 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; }
 1.16050 +          }}
 1.16051 +          if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
 1.16052 +          CImg<floatT> tmp(cimg::max(dy,dz));
 1.16053 +          CImg<intT> s(tmp.width), t(s.width);
 1.16054 +          { cimg_forXZ(*this,x,z) {
 1.16055 +            { cimg_forY(*this,y) tmp[y] = res(x,y,z,k); }
 1.16056 +            int q = s[0] = t[0] = 0;
 1.16057 +            { for (int y = 1; y<dy; ++y) {
 1.16058 +              const float val = tmp[y], val2 = val*val;
 1.16059 +              while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
 1.16060 +              if (q<0) { q = 0; s[0] = y; }
 1.16061 +              else {
 1.16062 +                const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
 1.16063 +                if (w<dy) { s[++q] = y; t[q] = w; }
 1.16064 +              }
 1.16065 +            }}
 1.16066 +            { for (int y = dy - 1; y>=0; --y) {
 1.16067 +              res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
 1.16068 +              if (y==t[q]) --q;
 1.16069 +            }}
 1.16070 +          }}
 1.16071 +          { cimg_forXY(*this,x,y) {
 1.16072 +            { cimg_forZ(*this,z) tmp[z] = res(x,y,z,k); }
 1.16073 +            int q = s[0] = t[0] = 0;
 1.16074 +            { for (int z = 1; z<dz; ++z) {
 1.16075 +              const float val = tmp[z];
 1.16076 +              while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
 1.16077 +              if (q<0) { q = 0; s[0] = z; }
 1.16078 +              else {
 1.16079 +                const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
 1.16080 +                if (w<dz) { s[++q] = z; t[q] = w; }
 1.16081 +              }
 1.16082 +            }}
 1.16083 +            { for (int z = dz - 1; z>=0; --z) {
 1.16084 +              const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
 1.16085 +              res(x,y,z,k) = compute_sqrt?(float)cimg_std::sqrt(val):val;
 1.16086 +              if (z==t[q]) --q;
 1.16087 +            }}
 1.16088 +          }}
 1.16089 +        } else { // 2D version (with small optimizations)
 1.16090 +          cimg_forX(*this,x) {
 1.16091 +            const T *ptrs = ptr(x,0,0,k);
 1.16092 +            float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
 1.16093 +            for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
 1.16094 +            { for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }}
 1.16095 +          }
 1.16096 +          if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
 1.16097 +          CImg<floatT> tmp(dx);
 1.16098 +          CImg<intT> s(dx), t(dx);
 1.16099 +          cimg_forY(*this,y) {
 1.16100 +            float *ptmp = tmp.ptr();
 1.16101 +            cimg_std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
 1.16102 +            int q = s[0] = t[0] = 0;
 1.16103 +            for (int x = 1; x<dx; ++x) {
 1.16104 +              const float val = *(++ptmp), val2 = val*val;
 1.16105 +              while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
 1.16106 +              if (q<0) { q = 0; s[0] = x; }
 1.16107 +              else {
 1.16108 +                const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
 1.16109 +                if (w<dx) { q++; s[q] = x; t[q] = w; }
 1.16110 +              }
 1.16111 +            }
 1.16112 +            float *pres = res.ptr(0,y,0,k) + width;
 1.16113 +            { for (int x = dx - 1; x>=0; --x) {
 1.16114 +              const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
 1.16115 +              *(--pres) = compute_sqrt?(float)cimg_std::sqrt(val):val;
 1.16116 +              if (x==t[q]) --q;
 1.16117 +            }}
 1.16118 +          }
 1.16119 +        }
 1.16120 +      }
 1.16121 +      return res;
 1.16122 +    }
 1.16123 +
 1.16124 +    static float _distance_f(const int x, const int i, const float gi2, const float fact) {
 1.16125 +      const float xmi = fact*((float)x - i);
 1.16126 +      return xmi*xmi + gi2;
 1.16127 +    }
 1.16128 +    static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
 1.16129 +      const float fact2 = fact*fact;
 1.16130 +      return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
 1.16131 +    }
 1.16132 +
 1.16133 +    //! Compute minimal path in a graph, using the Dijkstra algorithm.
 1.16134 +    /**
 1.16135 +       \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
 1.16136 +       \param nb_nodes Number of graph nodes.
 1.16137 +       \param starting_node Indice of the starting node.
 1.16138 +       \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
 1.16139 +       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 1.16140 +       \return Array of distances of each node to the starting node.
 1.16141 +    **/
 1.16142 +    template<typename tf, typename t>
 1.16143 +    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
 1.16144 +                            const unsigned int starting_node, const unsigned int ending_node,
 1.16145 +                            CImg<t>& previous) {
 1.16146 +
 1.16147 +      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
 1.16148 +      dist(starting_node) = 0;
 1.16149 +      previous.assign(1,nb_nodes,1,1,(t)-1);
 1.16150 +      previous(starting_node) = (t)starting_node;
 1.16151 +      CImg<uintT> Q(nb_nodes);
 1.16152 +      cimg_forX(Q,u) Q(u) = u;
 1.16153 +      cimg::swap(Q(starting_node),Q(0));
 1.16154 +      unsigned int sizeQ = nb_nodes;
 1.16155 +      while (sizeQ) {
 1.16156 +        // Update neighbors from minimal vertex
 1.16157 +        const unsigned int umin = Q(0);
 1.16158 +        if (umin==ending_node) sizeQ = 0;
 1.16159 +        else {
 1.16160 +          const T dmin = dist(umin);
 1.16161 +          const T infty = cimg::type<T>::max();
 1.16162 +          for (unsigned int q=1; q<sizeQ; ++q) {
 1.16163 +            const unsigned int v = Q(q);
 1.16164 +            const T d = (T)distance(v,umin);
 1.16165 +            if (d<infty) {
 1.16166 +              const T alt = dmin + d;
 1.16167 +              if (alt<dist(v)) {
 1.16168 +                dist(v) = alt;
 1.16169 +                previous(v) = (t)umin;
 1.16170 +                const T distpos = dist(Q(q));
 1.16171 +                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
 1.16172 +              }
 1.16173 +            }
 1.16174 +          }
 1.16175 +          // Remove minimal vertex from queue
 1.16176 +          Q(0) = Q(--sizeQ);
 1.16177 +          const T distpos = dist(Q(0));
 1.16178 +          for (unsigned int pos = 0, left = 0, right = 0;
 1.16179 +               ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
 1.16180 +            if (right<sizeQ) {
 1.16181 +              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
 1.16182 +              else { cimg::swap(Q(pos),Q(right)); pos = right; }
 1.16183 +            } else { cimg::swap(Q(pos),Q(left)); pos = left; }
 1.16184 +          }
 1.16185 +        }
 1.16186 +      }
 1.16187 +      return dist;
 1.16188 +    }
 1.16189 +
 1.16190 +    //! Return minimal path in a graph, using the Dijkstra algorithm.
 1.16191 +    template<typename tf, typename t>
 1.16192 +    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
 1.16193 +                            const unsigned int starting_node, const unsigned int ending_node=~0U) {
 1.16194 +      CImg<uintT> foo;
 1.16195 +      return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
 1.16196 +    }
 1.16197 +
 1.16198 +    //! Return minimal path in a graph, using the Dijkstra algorithm.
 1.16199 +    /**
 1.16200 +       Instance image corresponds to the adjacency matrix of the graph.
 1.16201 +       \param starting_node Indice of the starting node.
 1.16202 +       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 1.16203 +       \return Array of distances of each node to the starting node.
 1.16204 +    **/
 1.16205 +    template<typename t>
 1.16206 +    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
 1.16207 +      return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
 1.16208 +    }
 1.16209 +
 1.16210 +    template<typename t>
 1.16211 +    CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
 1.16212 +      if (width!=height || depth!=1 || dim!=1)
 1.16213 +        throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
 1.16214 +                                    pixel_type(),width,height,depth,dim,data);
 1.16215 +      return dijkstra(*this,width,starting_node,ending_node,previous);
 1.16216 +    }
 1.16217 +
 1.16218 +    //! Return minimal path in a graph, using the Dijkstra algorithm.
 1.16219 +    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
 1.16220 +      return get_dijkstra(starting_node,ending_node).transfer_to(*this);
 1.16221 +    }
 1.16222 +
 1.16223 +    CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
 1.16224 +      CImg<uintT> foo;
 1.16225 +      return get_dijkstra(starting_node,ending_node,foo);
 1.16226 +    }
 1.16227 +
 1.16228 +    //@}
 1.16229 +    //-------------------------------------
 1.16230 +    //
 1.16231 +    //! \name Meshes and Triangulations
 1.16232 +    //@{
 1.16233 +    //-------------------------------------
 1.16234 +
 1.16235 +    //! Return a 3D centered cube.
 1.16236 +    template<typename tf>
 1.16237 +    static CImg<floatT> cube3d(CImgList<tf>& primitives, const float size=100) {
 1.16238 +      const double s = size/2.0;
 1.16239 +      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);
 1.16240 +      return CImg<floatT>(8,3,1,1,
 1.16241 +                          -s,s,s,-s,-s,s,s,-s,
 1.16242 +                          -s,-s,s,s,-s,-s,s,s,
 1.16243 +                          -s,-s,-s,-s,s,s,s,s);
 1.16244 +    }
 1.16245 +
 1.16246 +    //! Return a 3D centered cuboid.
 1.16247 +    template<typename tf>
 1.16248 +    static CImg<floatT> cuboid3d(CImgList<tf>& primitives, const float sizex=200,
 1.16249 +                                 const float sizey=100, const float sizez=100) {
 1.16250 +      const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
 1.16251 +      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);
 1.16252 +      return CImg<floatT>(8,3,1,1,
 1.16253 +                          -sx,sx,sx,-sx,-sx,sx,sx,-sx,
 1.16254 +                          -sy,-sy,sy,sy,-sy,-sy,sy,sy,
 1.16255 +                          -sz,-sz,-sz,-sz,sz,sz,sz,sz);
 1.16256 +    }
 1.16257 +
 1.16258 +    //! Return a 3D centered cone.
 1.16259 +    template<typename tf>
 1.16260 +    static CImg<floatT> cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 1.16261 +                               const unsigned int subdivisions=24, const bool symetrize=false) {
 1.16262 +      primitives.assign();
 1.16263 +      if (!subdivisions) return CImg<floatT>();
 1.16264 +      const double r = (double)radius, h = (double)height/2;
 1.16265 +      CImgList<floatT> points(2,1,3,1,1,
 1.16266 +                              0.0,0.0,h,
 1.16267 +                              0.0,0.0,-h);
 1.16268 +      const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
 1.16269 +      for (float angle = 0; angle<360; angle+=delta) {
 1.16270 +        const float a = (float)(angle*cimg::valuePI/180);
 1.16271 +        points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),nh));
 1.16272 +      }
 1.16273 +      const unsigned int nbr = points.size-2;
 1.16274 +      for (unsigned int p = 0; p<nbr; ++p) {
 1.16275 +        const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
 1.16276 +        primitives.insert(CImg<tf>::vector(1,next,curr)).
 1.16277 +          insert(CImg<tf>::vector(0,curr,next));
 1.16278 +      }
 1.16279 +      return points.get_append('x');
 1.16280 +    }
 1.16281 +
 1.16282 +    //! Return a 3D centered cylinder.
 1.16283 +    template<typename tf>
 1.16284 +    static CImg<floatT> cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 1.16285 +                                   const unsigned int subdivisions=24) {
 1.16286 +      primitives.assign();
 1.16287 +      if (!subdivisions) return CImg<floatT>();
 1.16288 +      const double r = (double)radius, h = (double)height/2;
 1.16289 +      CImgList<floatT> points(2,1,3,1,1,
 1.16290 +                              0.0,0.0,-h,
 1.16291 +                              0.0,0.0,h);
 1.16292 +
 1.16293 +      const float delta = 360.0f/subdivisions;
 1.16294 +      for (float angle = 0; angle<360; angle+=delta) {
 1.16295 +        const float a = (float)(angle*cimg::valuePI/180);
 1.16296 +        points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),-(float)h));
 1.16297 +        points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),(float)h));
 1.16298 +      }
 1.16299 +      const unsigned int nbr = (points.size-2)/2;
 1.16300 +      for (unsigned int p = 0; p<nbr; ++p) {
 1.16301 +        const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
 1.16302 +        primitives.insert(CImg<tf>::vector(0,next,curr)).
 1.16303 +          insert(CImg<tf>::vector(1,curr+1,next+1)).
 1.16304 +          insert(CImg<tf>::vector(curr,next,next+1,curr+1));
 1.16305 +      }
 1.16306 +      return points.get_append('x');
 1.16307 +    }
 1.16308 +
 1.16309 +    //! Return a 3D centered torus.
 1.16310 +    template<typename tf>
 1.16311 +    static CImg<floatT> torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
 1.16312 +                                const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
 1.16313 +      primitives.assign();
 1.16314 +      if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
 1.16315 +      CImgList<floatT> points;
 1.16316 +      for (unsigned int v = 0; v<subdivisions1; ++v) {
 1.16317 +        const float
 1.16318 +          beta = (float)(v*2*cimg::valuePI/subdivisions1),
 1.16319 +          xc = radius1*(float)cimg_std::cos(beta),
 1.16320 +          yc = radius1*(float)cimg_std::sin(beta);
 1.16321 +        for (unsigned int u=0; u<subdivisions2; ++u) {
 1.16322 +          const float
 1.16323 +            alpha = (float)(u*2*cimg::valuePI/subdivisions2),
 1.16324 +            x = xc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::cos(beta)),
 1.16325 +            y = yc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::sin(beta)),
 1.16326 +            z = radius2*(float)cimg_std::sin(alpha);
 1.16327 +          points.insert(CImg<floatT>::vector(x,y,z));
 1.16328 +        }
 1.16329 +      }
 1.16330 +      for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
 1.16331 +        const unsigned int nv = (vv+1)%subdivisions1;
 1.16332 +        for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
 1.16333 +          const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
 1.16334 +          primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
 1.16335 +          primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
 1.16336 +        }
 1.16337 +      }
 1.16338 +      return points.get_append('x');
 1.16339 +    }
 1.16340 +
 1.16341 +    //! Return a 3D centered XY plane.
 1.16342 +    template<typename tf>
 1.16343 +    static CImg<floatT> plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
 1.16344 +                                const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
 1.16345 +                                const bool double_sided=false) {
 1.16346 +      primitives.assign();
 1.16347 +      if (!subdivisionsx || !subdivisionsy) return CImg<floatT>();
 1.16348 +      CImgList<floatT> points;
 1.16349 +      const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
 1.16350 +      const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
 1.16351 +      for (unsigned int yy = 0; yy<h; ++yy)
 1.16352 +        for (unsigned int xx = 0; xx<w; ++xx)
 1.16353 +          points.insert(CImg<floatT>::vector(fx*(xx-w2),fy*(yy-h2),0));
 1.16354 +      for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
 1.16355 +        const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
 1.16356 +        primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
 1.16357 +        if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
 1.16358 +      }
 1.16359 +      return points.get_append('x');
 1.16360 +    }
 1.16361 +
 1.16362 +    //! Return a 3D centered sphere.
 1.16363 +    template<typename tf>
 1.16364 +    static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
 1.16365 +
 1.16366 +      // Create initial icosahedron
 1.16367 +      primitives.assign();
 1.16368 +      if (!subdivisions) return CImg<floatT>();
 1.16369 +      const double tmp = (1+cimg_std::sqrt(5.0f))/2, a = 1.0/cimg_std::sqrt(1+tmp*tmp), b = tmp*a;
 1.16370 +      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,
 1.16371 +                              -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
 1.16372 +      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,
 1.16373 +                        8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
 1.16374 +                        5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
 1.16375 +
 1.16376 +      // Recurse subdivisions
 1.16377 +      for (unsigned int i = 0; i<subdivisions; ++i) {
 1.16378 +        const unsigned int L = primitives.size;
 1.16379 +        for (unsigned int l = 0; l<L; ++l) {
 1.16380 +          const unsigned int
 1.16381 +            p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
 1.16382 +          const float
 1.16383 +            x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
 1.16384 +            x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
 1.16385 +            x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
 1.16386 +            tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)cimg_std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
 1.16387 +            tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)cimg_std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
 1.16388 +            tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)cimg_std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
 1.16389 +            nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
 1.16390 +            nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
 1.16391 +            nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
 1.16392 +          int i0 = -1, i1 = -1, i2 = -1;
 1.16393 +          cimglist_for(points,p) {
 1.16394 +            const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
 1.16395 +            if (x==nx0 && y==ny0 && z==nz0) i0 = p;
 1.16396 +            if (x==nx1 && y==ny1 && z==nz1) i1 = p;
 1.16397 +            if (x==nx2 && y==ny2 && z==nz2) i2 = p;
 1.16398 +          }
 1.16399 +          if (i0<0) { points.insert(CImg<floatT>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
 1.16400 +          if (i1<0) { points.insert(CImg<floatT>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
 1.16401 +          if (i2<0) { points.insert(CImg<floatT>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
 1.16402 +          primitives.remove(0);
 1.16403 +          primitives.insert(CImg<tf>::vector(p0,i0,i1)).
 1.16404 +            insert(CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2)).
 1.16405 +            insert(CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2)).
 1.16406 +            insert(CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2));
 1.16407 +        }
 1.16408 +      }
 1.16409 +      return points.get_append('x')*=radius;
 1.16410 +    }
 1.16411 +
 1.16412 +    //! Return a 3D centered ellipsoid.
 1.16413 +    template<typename tf, typename t>
 1.16414 +    static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor,
 1.16415 +                                    const unsigned int subdivisions=3) {
 1.16416 +      primitives.assign();
 1.16417 +      if (!subdivisions) return CImg<floatT>();
 1.16418 +      typedef typename cimg::superset<t,float>::type tfloat;
 1.16419 +      CImg<tfloat> S,V;
 1.16420 +      tensor.symmetric_eigen(S,V);
 1.16421 +      const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
 1.16422 +      CImg<floatT> points = sphere(primitives,subdivisions);
 1.16423 +      cimg_forX(points,p) {
 1.16424 +        points(p,0) = (float)(points(p,0)*l0);
 1.16425 +        points(p,1) = (float)(points(p,1)*l1);
 1.16426 +        points(p,2) = (float)(points(p,2)*l2);
 1.16427 +      }
 1.16428 +      V.transpose();
 1.16429 +      points = V*points;
 1.16430 +      return points;
 1.16431 +    }
 1.16432 +
 1.16433 +    //! Return a 3D elevation object of the instance image.
 1.16434 +    template<typename tf, typename tc, typename te>
 1.16435 +    CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
 1.16436 +      primitives.assign();
 1.16437 +      colors.assign();
 1.16438 +      if (is_empty()) return *this;
 1.16439 +      if (depth>1)
 1.16440 +        throw CImgInstanceException("CImg<%s>::get_elevation3d() : Instance image (%u,%u,%u,%u,%p) is not a 2D image.",
 1.16441 +                                    pixel_type(),width,height,depth,dim,data);
 1.16442 +      if (!is_sameXY(elevation))
 1.16443 +        throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
 1.16444 +                                    "have different sizes.",pixel_type(),
 1.16445 +                                    elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
 1.16446 +                                    width,height,depth,dim,data,pixel_type());
 1.16447 +      float m, M = (float)maxmin(m);
 1.16448 +      if (M==m) ++M;
 1.16449 +      const unsigned int w = width + 1, h = height + 1;
 1.16450 +      CImg<floatT> points(w*h,3);
 1.16451 +      cimg_forXY(*this,x,y) {
 1.16452 +        const int yw = y*w, xpyw = x + yw, xpyww = xpyw + w;
 1.16453 +        points(xpyw,0) = points(xpyw+1,0) = points(xpyww+1,0) = points(xpyww,0) = (float)x;
 1.16454 +        points(xpyw,1) = points(xpyw+1,1) = points(xpyww+1,1) = points(xpyww,1) = (float)y;
 1.16455 +        points(xpyw,2) = points(xpyw+1,2) = points(xpyww+1,2) = points(xpyww,2) = (float)elevation(x,y);
 1.16456 +        primitives.insert(CImg<tf>::vector(xpyw,xpyw+1,xpyww+1,xpyww));
 1.16457 +        const unsigned char
 1.16458 +          r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
 1.16459 +          g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
 1.16460 +          b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
 1.16461 +        colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
 1.16462 +      }
 1.16463 +      return points;
 1.16464 +    }
 1.16465 +
 1.16466 +    // Inner routine used by the Marching square algorithm.
 1.16467 +    template<typename t>
 1.16468 +    static int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
 1.16469 +                                        const unsigned int x, const unsigned int nx) {
 1.16470 +      switch (edge) {
 1.16471 +      case 0 : return (int)indices1(x,0);
 1.16472 +      case 1 : return (int)indices1(nx,1);
 1.16473 +      case 2 : return (int)indices2(x,0);
 1.16474 +      case 3 : return (int)indices1(x,1);
 1.16475 +      }
 1.16476 +      return 0;
 1.16477 +    }
 1.16478 +
 1.16479 +    //! Polygonize an implicit 2D function by the marching squares algorithm.
 1.16480 +    template<typename tf, typename tfunc>
 1.16481 +    static CImg<floatT> marching_squares(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
 1.16482 +                                         const float x0, const float y0,
 1.16483 +                                         const float x1, const float y1,
 1.16484 +                                         const float resx, const float resy) {
 1.16485 +      static unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
 1.16486 +      static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
 1.16487 +                                     { 1,2,-1,-1 },   { 0,1,2,3 },   { 0,2,-1,-1 }, { 2,3,-1,-1 },
 1.16488 +                                     { 2,3,-1,-1 },   { 0,2,-1,-1},  { 0,3,1,2 },   { 1,2,-1,-1 },
 1.16489 +                                     { 1,3,-1,-1 },   { 0,1,-1,-1},  { 0,3,-1,-1},  { -1,-1,-1,-1 } };
 1.16490 +      const unsigned int
 1.16491 +        nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
 1.16492 +        ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1;
 1.16493 +      if (!nxm1 || !nym1) return CImg<floatT>();
 1.16494 +
 1.16495 +      primitives.assign();
 1.16496 +      CImgList<floatT> points;
 1.16497 +      CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
 1.16498 +      CImg<floatT> values1(nx), values2(nx);
 1.16499 +      float X = 0, Y = 0, nX = 0, nY = 0;
 1.16500 +
 1.16501 +      // Fill first line with values
 1.16502 +      cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; }
 1.16503 +
 1.16504 +      // Run the marching squares algorithm
 1.16505 +      Y = y0; nY = Y + resy;
 1.16506 +      for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) {
 1.16507 +        X = x0; nX = X + resx;
 1.16508 +        indices2.fill(-1);
 1.16509 +        for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) {
 1.16510 +
 1.16511 +          // Determine cube configuration
 1.16512 +          const float
 1.16513 +            val0 = values1(xi), val1 = values1(nxi),
 1.16514 +            val2 = values2(nxi) = (float)func(nX,nY),
 1.16515 +            val3 = values2(xi) = (float)func(X,nY);
 1.16516 +
 1.16517 +          const unsigned int configuration = (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0),
 1.16518 +            edge = edges[configuration];
 1.16519 +
 1.16520 +          // Compute intersection points
 1.16521 +          if (edge) {
 1.16522 +            if ((edge&1) && indices1(xi,0)<0) {
 1.16523 +              const float Xi = X + (isovalue-val0)*resx/(val1-val0);
 1.16524 +              indices1(xi,0) = points.size;
 1.16525 +              points.insert(CImg<floatT>::vector(Xi,Y));
 1.16526 +            }
 1.16527 +            if ((edge&2) && indices1(nxi,1)<0) {
 1.16528 +              const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
 1.16529 +              indices1(nxi,1) = points.size;
 1.16530 +              points.insert(CImg<floatT>::vector(nX,Yi));
 1.16531 +            }
 1.16532 +            if ((edge&4) && indices2(xi,0)<0) {
 1.16533 +              const float Xi = X + (isovalue-val3)*resx/(val2-val3);
 1.16534 +              indices2(xi,0) = points.size;
 1.16535 +              points.insert(CImg<floatT>::vector(Xi,nY));
 1.16536 +            }
 1.16537 +            if ((edge&8) && indices1(xi,1)<0) {
 1.16538 +              const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
 1.16539 +              indices1(xi,1) = points.size;
 1.16540 +              points.insert(CImg<floatT>::vector(X,Yi));
 1.16541 +            }
 1.16542 +
 1.16543 +            // Create segments
 1.16544 +            for (int *segment = segments[configuration]; *segment!=-1; ) {
 1.16545 +              const unsigned int p0 = *(segment++), p1 = *(segment++);
 1.16546 +              const tf
 1.16547 +                i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)),
 1.16548 +                i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi));
 1.16549 +              primitives.insert(CImg<tf>::vector(i0,i1));
 1.16550 +            }
 1.16551 +          }
 1.16552 +        }
 1.16553 +        values1.swap(values2);
 1.16554 +        indices1.swap(indices2);
 1.16555 +      }
 1.16556 +      return points.get_append('x');
 1.16557 +    }
 1.16558 +
 1.16559 +    // Inner routine used by the Marching cube algorithm.
 1.16560 +    template<typename t>
 1.16561 +    static int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
 1.16562 +                                      const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
 1.16563 +      switch (edge) {
 1.16564 +      case 0 : return indices1(x,y,0);
 1.16565 +      case 1 : return indices1(nx,y,1);
 1.16566 +      case 2 : return indices1(x,ny,0);
 1.16567 +      case 3 : return indices1(x,y,1);
 1.16568 +      case 4 : return indices2(x,y,0);
 1.16569 +      case 5 : return indices2(nx,y,1);
 1.16570 +      case 6 : return indices2(x,ny,0);
 1.16571 +      case 7 : return indices2(x,y,1);
 1.16572 +      case 8 : return indices1(x,y,2);
 1.16573 +      case 9 : return indices1(nx,y,2);
 1.16574 +      case 10 : return indices1(nx,ny,2);
 1.16575 +      case 11 : return indices1(x,ny,2);
 1.16576 +      }
 1.16577 +      return 0;
 1.16578 +    }
 1.16579 +
 1.16580 +    //! Polygonize an implicit function
 1.16581 +    // This function uses the Marching Cubes Tables published on the web page :
 1.16582 +    // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
 1.16583 +    template<typename tf, typename tfunc>
 1.16584 +    static CImg<floatT> marching_cubes(CImgList<tf>& primitives,
 1.16585 +                                       const tfunc& func, const float isovalue,
 1.16586 +                                       const float x0, const float y0, const float z0,
 1.16587 +                                       const float x1, const float y1, const float z1,
 1.16588 +                                       const float resx, const float resy, const float resz,
 1.16589 +                                       const bool invert_faces=false) {
 1.16590 +
 1.16591 +      static unsigned int edges[256] = {
 1.16592 +        0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
 1.16593 +        0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
 1.16594 +        0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
 1.16595 +        0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
 1.16596 +        0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
 1.16597 +        0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
 1.16598 +        0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
 1.16599 +        0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
 1.16600 +        0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
 1.16601 +        0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
 1.16602 +        0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
 1.16603 +        0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
 1.16604 +        0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
 1.16605 +        0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
 1.16606 +        0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
 1.16607 +        0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
 1.16608 +
 1.16609 +      static int triangles[256][16] =
 1.16610 +        {{ -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 },
 1.16611 +         { 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 },
 1.16612 +         { 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 },
 1.16613 +         { 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 },
 1.16614 +         { 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 },
 1.16615 +         { 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 },
 1.16616 +         { 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 },
 1.16617 +         { 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 },
 1.16618 +         { 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 },
 1.16619 +         { 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 },
 1.16620 +         { 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 },
 1.16621 +         { 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 },
 1.16622 +         { 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 },
 1.16623 +         { 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 },
 1.16624 +         { 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 },
 1.16625 +         { 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 },
 1.16626 +         { 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 },
 1.16627 +         { 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 },
 1.16628 +         { 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 },
 1.16629 +         { 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 },
 1.16630 +         { 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 },
 1.16631 +         { 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 },
 1.16632 +         { 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 },
 1.16633 +         { 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 },
 1.16634 +         { 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 },
 1.16635 +         { 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 },
 1.16636 +         { 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 },
 1.16637 +         { 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 },
 1.16638 +         { 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 },
 1.16639 +         { 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 },
 1.16640 +         { 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 },
 1.16641 +         { 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 },
 1.16642 +         { 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 },
 1.16643 +         { 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 },
 1.16644 +         { 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 },
 1.16645 +         { 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 },
 1.16646 +         { 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 },
 1.16647 +         { 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 },
 1.16648 +         { 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 },
 1.16649 +         { 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 },
 1.16650 +         { 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 },
 1.16651 +         { 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 },
 1.16652 +         { 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 },
 1.16653 +         { 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 },
 1.16654 +         { 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 },
 1.16655 +         { 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 },
 1.16656 +         { 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 },
 1.16657 +         { 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 },
 1.16658 +         { 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 },
 1.16659 +         { 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 },
 1.16660 +         { 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 },
 1.16661 +         { 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 },
 1.16662 +         { 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 },
 1.16663 +         { 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 },
 1.16664 +         { 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 },
 1.16665 +         { 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 },
 1.16666 +         { 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 },
 1.16667 +         { 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 },
 1.16668 +         { 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 },
 1.16669 +         { 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 },
 1.16670 +         { 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 },
 1.16671 +         { 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 },
 1.16672 +         { 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 },
 1.16673 +         { 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 },
 1.16674 +         { 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 },
 1.16675 +         { 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 },
 1.16676 +         { 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 },
 1.16677 +         { 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 },
 1.16678 +         { 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 },
 1.16679 +         { 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 },
 1.16680 +         { 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 },
 1.16681 +         { 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 },
 1.16682 +         { 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 },
 1.16683 +         { 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 },
 1.16684 +         { 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 },
 1.16685 +         { 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 },
 1.16686 +         { 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 },
 1.16687 +         { 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 },
 1.16688 +         { 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 },
 1.16689 +         { 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 },
 1.16690 +         { 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 },
 1.16691 +         { 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 },
 1.16692 +         { 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 },
 1.16693 +         { 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 },
 1.16694 +         { 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 },
 1.16695 +         { 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 },
 1.16696 +         { 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 },
 1.16697 +         { 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 },
 1.16698 +         { 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 },
 1.16699 +         { 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 },
 1.16700 +         { 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 },
 1.16701 +         { 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 },
 1.16702 +         { 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 },
 1.16703 +         { 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 },
 1.16704 +         { 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 },
 1.16705 +         { 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 },
 1.16706 +         { 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 },
 1.16707 +         { 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 },
 1.16708 +         { 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 },
 1.16709 +         { 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 },
 1.16710 +         { 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 },
 1.16711 +         { 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 },
 1.16712 +         { 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 },
 1.16713 +         { 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 },
 1.16714 +         { 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 },
 1.16715 +         { 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 },
 1.16716 +         { 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 },
 1.16717 +         { 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 },
 1.16718 +         { 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 },
 1.16719 +         { 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 },
 1.16720 +         { 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 },
 1.16721 +         { 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 },
 1.16722 +         { 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 },
 1.16723 +         { 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 },
 1.16724 +         { 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 },
 1.16725 +         { 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 },
 1.16726 +         { 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 },
 1.16727 +         { 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 },
 1.16728 +         { 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 },
 1.16729 +         { 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 },
 1.16730 +         { 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 },
 1.16731 +         { 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 },
 1.16732 +         { 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 },
 1.16733 +         { 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 },
 1.16734 +         { 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 },
 1.16735 +         { 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 },
 1.16736 +         { 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 },
 1.16737 +         { 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 }};
 1.16738 +
 1.16739 +      const unsigned int
 1.16740 +        nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
 1.16741 +        ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1,
 1.16742 +        nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1;
 1.16743 +      if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
 1.16744 +
 1.16745 +      primitives.assign();
 1.16746 +      CImgList<floatT> points;
 1.16747 +      CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
 1.16748 +      CImg<floatT> values1(nx,ny), values2(nx,ny);
 1.16749 +      float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
 1.16750 +
 1.16751 +      // Fill the first plane with function values
 1.16752 +      Y = y0;
 1.16753 +      cimg_forY(values1,y) {
 1.16754 +        X = x0;
 1.16755 +        cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; }
 1.16756 +        Y+=resy;
 1.16757 +      }
 1.16758 +
 1.16759 +      // Run Marching Cubes algorithm
 1.16760 +      Z = z0; nZ = Z + resz;
 1.16761 +      for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=resz) {
 1.16762 +        Y = y0; nY = Y + resy;
 1.16763 +        indices2.fill(-1);
 1.16764 +        for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=resy) {
 1.16765 +          X = x0; nX = X + resx;
 1.16766 +          for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=resx) {
 1.16767 +
 1.16768 +            // Determine cube configuration
 1.16769 +            const float
 1.16770 +              val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi),
 1.16771 +              val4 = values2(xi,yi) = (float)func(X,Y,nZ),
 1.16772 +              val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
 1.16773 +              val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
 1.16774 +              val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
 1.16775 +
 1.16776 +            const unsigned int configuration =
 1.16777 +              (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0) |
 1.16778 +              (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
 1.16779 +              edge = edges[configuration];
 1.16780 +
 1.16781 +            // Compute intersection points
 1.16782 +            if (edge) {
 1.16783 +              if ((edge&1) && indices1(xi,yi,0)<0) {
 1.16784 +                const float Xi = X + (isovalue-val0)*resx/(val1-val0);
 1.16785 +                indices1(xi,yi,0) = points.size;
 1.16786 +                points.insert(CImg<floatT>::vector(Xi,Y,Z));
 1.16787 +              }
 1.16788 +              if ((edge&2) && indices1(nxi,yi,1)<0) {
 1.16789 +                const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
 1.16790 +                indices1(nxi,yi,1) = points.size;
 1.16791 +                points.insert(CImg<floatT>::vector(nX,Yi,Z));
 1.16792 +              }
 1.16793 +              if ((edge&4) && indices1(xi,nyi,0)<0) {
 1.16794 +                const float Xi = X + (isovalue-val3)*resx/(val2-val3);
 1.16795 +                indices1(xi,nyi,0) = points.size;
 1.16796 +                points.insert(CImg<floatT>::vector(Xi,nY,Z));
 1.16797 +              }
 1.16798 +              if ((edge&8) && indices1(xi,yi,1)<0) {
 1.16799 +                const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
 1.16800 +                indices1(xi,yi,1) = points.size;
 1.16801 +                points.insert(CImg<floatT>::vector(X,Yi,Z));
 1.16802 +              }
 1.16803 +              if ((edge&16) && indices2(xi,yi,0)<0) {
 1.16804 +                const float Xi = X + (isovalue-val4)*resx/(val5-val4);
 1.16805 +                indices2(xi,yi,0) = points.size;
 1.16806 +                points.insert(CImg<floatT>::vector(Xi,Y,nZ));
 1.16807 +              }
 1.16808 +              if ((edge&32) && indices2(nxi,yi,1)<0) {
 1.16809 +                const float Yi = Y + (isovalue-val5)*resy/(val6-val5);
 1.16810 +                indices2(nxi,yi,1) = points.size;
 1.16811 +                points.insert(CImg<floatT>::vector(nX,Yi,nZ));
 1.16812 +              }
 1.16813 +              if ((edge&64) && indices2(xi,nyi,0)<0) {
 1.16814 +                const float Xi = X + (isovalue-val7)*resx/(val6-val7);
 1.16815 +                indices2(xi,nyi,0) = points.size;
 1.16816 +                points.insert(CImg<floatT>::vector(Xi,nY,nZ));
 1.16817 +              }
 1.16818 +              if ((edge&128) && indices2(xi,yi,1)<0)  {
 1.16819 +                const float Yi = Y + (isovalue-val4)*resy/(val7-val4);
 1.16820 +                indices2(xi,yi,1) = points.size;
 1.16821 +                points.insert(CImg<floatT>::vector(X,Yi,nZ));
 1.16822 +              }
 1.16823 +              if ((edge&256) && indices1(xi,yi,2)<0) {
 1.16824 +                const float Zi = Z+ (isovalue-val0)*resz/(val4-val0);
 1.16825 +                indices1(xi,yi,2) = points.size;
 1.16826 +                points.insert(CImg<floatT>::vector(X,Y,Zi));
 1.16827 +              }
 1.16828 +              if ((edge&512) && indices1(nxi,yi,2)<0)  {
 1.16829 +                const float Zi = Z + (isovalue-val1)*resz/(val5-val1);
 1.16830 +                indices1(nxi,yi,2) = points.size;
 1.16831 +                points.insert(CImg<floatT>::vector(nX,Y,Zi));
 1.16832 +              }
 1.16833 +              if ((edge&1024) && indices1(nxi,nyi,2)<0) {
 1.16834 +                const float Zi = Z + (isovalue-val2)*resz/(val6-val2);
 1.16835 +                indices1(nxi,nyi,2) = points.size;
 1.16836 +                points.insert(CImg<floatT>::vector(nX,nY,Zi));
 1.16837 +              }
 1.16838 +              if ((edge&2048) && indices1(xi,nyi,2)<0) {
 1.16839 +                const float Zi = Z + (isovalue-val3)*resz/(val7-val3);
 1.16840 +                indices1(xi,nyi,2) = points.size;
 1.16841 +                points.insert(CImg<floatT>::vector(X,nY,Zi));
 1.16842 +              }
 1.16843 +
 1.16844 +              // Create triangles
 1.16845 +              for (int *triangle = triangles[configuration]; *triangle!=-1; ) {
 1.16846 +                const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
 1.16847 +                const tf
 1.16848 +                  i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
 1.16849 +                  i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
 1.16850 +                  i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
 1.16851 +                if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
 1.16852 +                else primitives.insert(CImg<tf>::vector(i0,i2,i1));
 1.16853 +              }
 1.16854 +            }
 1.16855 +          }
 1.16856 +        }
 1.16857 +        cimg::swap(values1,values2);
 1.16858 +        cimg::swap(indices1,indices2);
 1.16859 +      }
 1.16860 +      return points.get_append('x');
 1.16861 +    }
 1.16862 +
 1.16863 +    struct _marching_squares_func {
 1.16864 +      const CImg<T>& ref;
 1.16865 +      _marching_squares_func(const CImg<T>& pref):ref(pref) {}
 1.16866 +      float operator()(const float x, const float y) const {
 1.16867 +        return (float)ref((int)x,(int)y);
 1.16868 +      }
 1.16869 +    };
 1.16870 +
 1.16871 +    struct _marching_cubes_func {
 1.16872 +      const CImg<T>& ref;
 1.16873 +      _marching_cubes_func(const CImg<T>& pref):ref(pref) {}
 1.16874 +      float operator()(const float x, const float y, const float z) const {
 1.16875 +        return (float)ref((int)x,(int)y,(int)z);
 1.16876 +      }
 1.16877 +    };
 1.16878 +
 1.16879 +    struct _marching_squares_func_float {
 1.16880 +      const CImg<T>& ref;
 1.16881 +      _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
 1.16882 +      float operator()(const float x, const float y) const {
 1.16883 +        return (float)ref._linear_atXY(x,y);
 1.16884 +      }
 1.16885 +    };
 1.16886 +
 1.16887 +    struct _marching_cubes_func_float {
 1.16888 +      const CImg<T>& ref;
 1.16889 +      _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
 1.16890 +      float operator()(const float x, const float y, const float z) const {
 1.16891 +        return (float)ref._linear_atXYZ(x,y,z);
 1.16892 +      }
 1.16893 +    };
 1.16894 +
 1.16895 +    //! Compute a vectorization of an implicit function.
 1.16896 +    template<typename tf>
 1.16897 +    CImg<floatT> get_isovalue3d(CImgList<tf>& primitives, const float isovalue,
 1.16898 +                                const float resx=1, const float resy=1, const float resz=1,
 1.16899 +                                const bool invert_faces=false) const {
 1.16900 +      primitives.assign();
 1.16901 +      if (is_empty()) return *this;
 1.16902 +      if (dim>1)
 1.16903 +        throw CImgInstanceException("CImg<%s>::get_isovalue3d() : Instance image (%u,%u,%u,%u,%p) is not a scalar image.",
 1.16904 +                                    pixel_type(),width,height,depth,dim,data);
 1.16905 +      CImg<floatT> points;
 1.16906 +      if (depth>1) {
 1.16907 +        if (resx==1 && resy==1 && resz==1) {
 1.16908 +          const _marching_cubes_func func(*this);
 1.16909 +          points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
 1.16910 +        } else {
 1.16911 +          const _marching_cubes_func_float func(*this);
 1.16912 +          points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
 1.16913 +        }
 1.16914 +      } else {
 1.16915 +        if (resx==1 && resy==1) {
 1.16916 +          const _marching_squares_func func(*this);
 1.16917 +          points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
 1.16918 +        } else {
 1.16919 +          const _marching_squares_func_float func(*this);
 1.16920 +          points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
 1.16921 +        }
 1.16922 +        if (points) points.resize(-100,3,1,1,0);
 1.16923 +      }
 1.16924 +      return points;
 1.16925 +    }
 1.16926 +
 1.16927 +    //! Translate a 3D object.
 1.16928 +    CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
 1.16929 +      get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
 1.16930 +      return *this;
 1.16931 +    }
 1.16932 +
 1.16933 +    CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
 1.16934 +      return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
 1.16935 +    }
 1.16936 +
 1.16937 +    //! Translate a 3D object so that it becomes centered.
 1.16938 +    CImg<T>& translate_object3d() {
 1.16939 +      CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 1.16940 +      float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 1.16941 +      xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
 1.16942 +      return *this;
 1.16943 +    }
 1.16944 +
 1.16945 +    CImg<Tfloat> get_translate_object3d() const {
 1.16946 +      return CImg<Tfloat>(*this,false).translate_object3d();
 1.16947 +    }
 1.16948 +
 1.16949 +    //! Resize a 3D object.
 1.16950 +    CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
 1.16951 +      CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 1.16952 +      float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 1.16953 +      if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
 1.16954 +      if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
 1.16955 +      if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
 1.16956 +      return *this;
 1.16957 +    }
 1.16958 +
 1.16959 +    CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
 1.16960 +      return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
 1.16961 +    }
 1.16962 +
 1.16963 +    // Resize a 3D object so that its max dimension if one.
 1.16964 +    CImg<T> resize_object3d() const {
 1.16965 +      CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 1.16966 +      float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
 1.16967 +      const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
 1.16968 +      if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
 1.16969 +      return *this;
 1.16970 +    }
 1.16971 +
 1.16972 +    CImg<Tfloat> get_resize_object3d() const {
 1.16973 +      return CImg<Tfloat>(*this,false).resize_object3d();
 1.16974 +    }
 1.16975 +
 1.16976 +    //! Append a 3D object to another one.
 1.16977 +    template<typename tf, typename tp, typename tff>
 1.16978 +    CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
 1.16979 +      const unsigned int P = width;
 1.16980 +      append(obj_points,'x');
 1.16981 +      const unsigned int N = primitives.size;
 1.16982 +      primitives.insert(obj_primitives);
 1.16983 +      for (unsigned int i = N; i<primitives.size; ++i) {
 1.16984 +        CImg<tf> &p = primitives[i];
 1.16985 +        if (p.size()!=5) p+=P;
 1.16986 +        else { p[0]+=P; if (p[2]==0) p[1]+=P; }
 1.16987 +      }
 1.16988 +      return *this;
 1.16989 +    }
 1.16990 +
 1.16991 +    //@}
 1.16992 +    //----------------------------
 1.16993 +    //
 1.16994 +    //! \name Color bases
 1.16995 +    //@{
 1.16996 +    //----------------------------
 1.16997 +
 1.16998 +    //! Return a default indexed color palette with 256 (R,G,B) entries.
 1.16999 +    /**
 1.17000 +       The default color palette is used by %CImg when displaying images on 256 colors displays.
 1.17001 +       It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
 1.17002 +       (i.e 8 levels for the Red and Green and 4 levels for the Blue).
 1.17003 +       \return a 1x256x1x3 color image defining the palette entries.
 1.17004 +    **/
 1.17005 +    static CImg<Tuchar> default_LUT8() {
 1.17006 +      static CImg<Tuchar> palette;
 1.17007 +      if (!palette) {
 1.17008 +        palette.assign(1,256,1,3);
 1.17009 +        for (unsigned int index = 0, r = 16; r<256; r+=32)
 1.17010 +          for (unsigned int g = 16; g<256; g+=32)
 1.17011 +            for (unsigned int b = 32; b<256; b+=64) {
 1.17012 +              palette(0,index,0) = (Tuchar)r;
 1.17013 +              palette(0,index,1) = (Tuchar)g;
 1.17014 +              palette(0,index++,2) = (Tuchar)b;
 1.17015 +            }
 1.17016 +      }
 1.17017 +      return palette;
 1.17018 +    }
 1.17019 +
 1.17020 +    //! Return a rainbow color palette with 256 (R,G,B) entries.
 1.17021 +    static CImg<Tuchar> rainbow_LUT8() {
 1.17022 +      static CImg<Tuchar> palette;
 1.17023 +      if (!palette) {
 1.17024 +        CImg<Tint> tmp(1,256,1,3,1);
 1.17025 +        tmp.get_shared_channel(0).sequence(0,359);
 1.17026 +        palette = tmp.HSVtoRGB();
 1.17027 +      }
 1.17028 +      return palette;
 1.17029 +    }
 1.17030 +
 1.17031 +    //! Return a contrasted color palette with 256 (R,G,B) entries.
 1.17032 +    static CImg<Tuchar> contrast_LUT8() {
 1.17033 +      static const unsigned char pal[] = {
 1.17034 +        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,
 1.17035 +        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,
 1.17036 +        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,
 1.17037 +        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,
 1.17038 +        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,
 1.17039 +        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,
 1.17040 +        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,
 1.17041 +        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,
 1.17042 +        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,
 1.17043 +        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,
 1.17044 +        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,
 1.17045 +        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,
 1.17046 +        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,
 1.17047 +        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,
 1.17048 +        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,
 1.17049 +        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,
 1.17050 +        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,
 1.17051 +        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,
 1.17052 +        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,
 1.17053 +        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,
 1.17054 +        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,
 1.17055 +        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,
 1.17056 +        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,
 1.17057 +        23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
 1.17058 +      static const CImg<Tuchar> palette(pal,1,256,1,3,false);
 1.17059 +      return palette;
 1.17060 +    }
 1.17061 +
 1.17062 +    //! Convert (R,G,B) color image to indexed color image.
 1.17063 +    template<typename t>
 1.17064 +    CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
 1.17065 +      return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
 1.17066 +    }
 1.17067 +
 1.17068 +    template<typename t>
 1.17069 +    CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
 1.17070 +      if (is_empty()) return CImg<t>();
 1.17071 +      if (dim!=3)
 1.17072 +        throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
 1.17073 +                                    "should be a (R,G,B) image.",
 1.17074 +                                    pixel_type(),dim);
 1.17075 +      if (palette.data && palette.dim!=3)
 1.17076 +        throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
 1.17077 +                                    "should be a (R,G,B) palette",
 1.17078 +                                    pixel_type(),palette.dim);
 1.17079 +      CImg<t> res(width,height,depth,indexing?1:3);
 1.17080 +      float *line1 = new float[3*width], *line2 = new float[3*width];
 1.17081 +      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);
 1.17082 +      cimg_forZ(*this,z) {
 1.17083 +        const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
 1.17084 +        float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
 1.17085 +        cimg_forY(*this,y) {
 1.17086 +          cimg::swap(line1,line2);
 1.17087 +          if (y<dimy()-1) {
 1.17088 +            const int ny = y + 1;
 1.17089 +            const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
 1.17090 +            float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
 1.17091 +          }
 1.17092 +          float *ptr1 = line1, *ptr2 = line2;
 1.17093 +          cimg_forX(*this,x) {
 1.17094 +            float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
 1.17095 +            R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
 1.17096 +            t Rbest = 0, Gbest = 0, Bbest = 0;
 1.17097 +            int best_index = 0;
 1.17098 +            if (palette) { // find best match in given color palette
 1.17099 +              const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
 1.17100 +              const unsigned int Npal = palette.width*palette.height*palette.depth;
 1.17101 +              float min = cimg::type<float>::max();
 1.17102 +              for (unsigned int off = 0; off<Npal; ++off) {
 1.17103 +                const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
 1.17104 +                const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
 1.17105 +                if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
 1.17106 +              }
 1.17107 +            } else {
 1.17108 +              Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
 1.17109 +              best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
 1.17110 +            }
 1.17111 +            if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
 1.17112 +            if (dithering) { // apply dithering to neighborhood pixels if needed
 1.17113 +              const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
 1.17114 +              if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
 1.17115 +              if (y<dimy()-1) {
 1.17116 +                *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2;
 1.17117 +                if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; }
 1.17118 +                if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; }
 1.17119 +              }
 1.17120 +            }
 1.17121 +            ptr2+=3;
 1.17122 +          }
 1.17123 +        }
 1.17124 +      }
 1.17125 +      delete[] line1; delete[] line2;
 1.17126 +      return res;
 1.17127 +    }
 1.17128 +
 1.17129 +    //! Convert color pixels from (R,G,B) to match the default palette.
 1.17130 +    CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
 1.17131 +      return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
 1.17132 +    }
 1.17133 +
 1.17134 +    CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
 1.17135 +      static const CImg<Tuchar> empty;
 1.17136 +      return get_RGBtoLUT(empty,dithering,indexing);
 1.17137 +    }
 1.17138 +
 1.17139 +    //! Convert an indexed image to a (R,G,B) image using the specified color palette.
 1.17140 +    CImg<T>& LUTtoRGB(const CImg<T>& palette) {
 1.17141 +      return get_LUTtoRGB(palette).transfer_to(*this);
 1.17142 +    }
 1.17143 +
 1.17144 +    template<typename t>
 1.17145 +    CImg<t> get_LUTtoRGB(const CImg<t>& palette) const {
 1.17146 +      if (is_empty()) return CImg<t>();
 1.17147 +      if (dim!=1)
 1.17148 +        throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, "
 1.17149 +                                    "should be a LUT image",
 1.17150 +                                    pixel_type(),dim);
 1.17151 +      if (palette.data && palette.dim!=3)
 1.17152 +        throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
 1.17153 +                                    "should be a (R,G,B) palette",
 1.17154 +                                    pixel_type(),palette.dim);
 1.17155 +      const CImg<t> pal = palette.data?palette:CImg<t>(default_LUT8());
 1.17156 +      CImg<t> res(width,height,depth,3);
 1.17157 +      const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
 1.17158 +      t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
 1.17159 +      const unsigned int Npal = palette.width*palette.height*palette.depth;
 1.17160 +      cimg_for(*this,ptr,T) {
 1.17161 +        const unsigned int index = ((unsigned int)*ptr)%Npal;
 1.17162 +        *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
 1.17163 +      }
 1.17164 +      return res;
 1.17165 +    }
 1.17166 +
 1.17167 +    //! Convert an indexed image (with the default palette) to a (R,G,B) image.
 1.17168 +    CImg<T>& LUTtoRGB() {
 1.17169 +      return get_LUTtoRGB().transfer_to(*this);
 1.17170 +    }
 1.17171 +
 1.17172 +    CImg<Tuchar> get_LUTtoRGB() const {
 1.17173 +      static const CImg<Tuchar> empty;
 1.17174 +      return get_LUTtoRGB(empty);
 1.17175 +    }
 1.17176 +
 1.17177 +    //! Convert color pixels from (R,G,B) to (H,S,V).
 1.17178 +    CImg<T>& RGBtoHSV() {
 1.17179 +      if (is_empty()) return *this;
 1.17180 +      if (dim!=3)
 1.17181 +        throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
 1.17182 +                                    "should be a (R,G,B) image.",
 1.17183 +                                    pixel_type(),dim);
 1.17184 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17185 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17186 +        const Tfloat
 1.17187 +          R = (Tfloat)*p1,
 1.17188 +          G = (Tfloat)*p2,
 1.17189 +          B = (Tfloat)*p3,
 1.17190 +          nR = (R<0?0:(R>255?255:R))/255,
 1.17191 +          nG = (G<0?0:(G>255?255:G))/255,
 1.17192 +          nB = (B<0?0:(B>255?255:B))/255,
 1.17193 +          m = cimg::min(nR,nG,nB),
 1.17194 +          M = cimg::max(nR,nG,nB);
 1.17195 +        Tfloat H = 0, S = 0;
 1.17196 +        if (M!=m) {
 1.17197 +          const Tfloat
 1.17198 +            f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 1.17199 +            i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
 1.17200 +          H = (i-f/(M-m));
 1.17201 +          if (H>=6) H-=6;
 1.17202 +          H*=60;
 1.17203 +          S = (M-m)/M;
 1.17204 +        }
 1.17205 +        *(p1++) = (T)H;
 1.17206 +        *(p2++) = (T)S;
 1.17207 +        *(p3++) = (T)M;
 1.17208 +      }
 1.17209 +      return *this;
 1.17210 +    }
 1.17211 +
 1.17212 +    CImg<Tfloat> get_RGBtoHSV() const {
 1.17213 +      return CImg<Tfloat>(*this,false).RGBtoHSV();
 1.17214 +    }
 1.17215 +
 1.17216 +    //! Convert color pixels from (H,S,V) to (R,G,B).
 1.17217 +    CImg<T>& HSVtoRGB() {
 1.17218 +    if (is_empty()) return *this;
 1.17219 +    if (dim!=3)
 1.17220 +      throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
 1.17221 +                                  "should be a (H,S,V) image",
 1.17222 +                                  pixel_type(),dim);
 1.17223 +    T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17224 +    for (unsigned long N = width*height*depth; N; --N) {
 1.17225 +      Tfloat
 1.17226 +        H = (Tfloat)*p1,
 1.17227 +        S = (Tfloat)*p2,
 1.17228 +        V = (Tfloat)*p3,
 1.17229 +        R = 0, G = 0, B = 0;
 1.17230 +      if (H==0 && S==0) R = G = B = V;
 1.17231 +      else {
 1.17232 +        H/=60;
 1.17233 +        const int i = (int)cimg_std::floor(H);
 1.17234 +        const Tfloat
 1.17235 +          f = (i&1)?(H-i):(1-H+i),
 1.17236 +          m = V*(1-S),
 1.17237 +          n = V*(1-S*f);
 1.17238 +        switch (i) {
 1.17239 +        case 6 :
 1.17240 +        case 0 : R = V; G = n; B = m; break;
 1.17241 +        case 1 : R = n; G = V; B = m; break;
 1.17242 +        case 2 : R = m; G = V; B = n; break;
 1.17243 +        case 3 : R = m; G = n; B = V; break;
 1.17244 +        case 4 : R = n; G = m; B = V; break;
 1.17245 +        case 5 : R = V; G = m; B = n; break;
 1.17246 +        }
 1.17247 +      }
 1.17248 +      R*=255; G*=255; B*=255;
 1.17249 +      *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17250 +      *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17251 +      *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17252 +    }
 1.17253 +    return *this;
 1.17254 +    }
 1.17255 +
 1.17256 +    CImg<Tuchar> get_HSVtoRGB() const {
 1.17257 +      return CImg<Tuchar>(*this,false).HSVtoRGB();
 1.17258 +    }
 1.17259 +
 1.17260 +    //! Convert color pixels from (R,G,B) to (H,S,L).
 1.17261 +    CImg<T>& RGBtoHSL() {
 1.17262 +      if (is_empty()) return *this;
 1.17263 +      if (dim!=3)
 1.17264 +        throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
 1.17265 +                                    "should be a (R,G,B) image.",
 1.17266 +                                    pixel_type(),dim);
 1.17267 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17268 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17269 +        const Tfloat
 1.17270 +          R = (Tfloat)*p1,
 1.17271 +          G = (Tfloat)*p2,
 1.17272 +          B = (Tfloat)*p3,
 1.17273 +          nR = (R<0?0:(R>255?255:R))/255,
 1.17274 +          nG = (G<0?0:(G>255?255:G))/255,
 1.17275 +          nB = (B<0?0:(B>255?255:B))/255,
 1.17276 +          m = cimg::min(nR,nG,nB),
 1.17277 +          M = cimg::max(nR,nG,nB),
 1.17278 +          L = (m+M)/2;
 1.17279 +        Tfloat H = 0, S = 0;
 1.17280 +        if (M==m) H = S = 0;
 1.17281 +        else {
 1.17282 +          const Tfloat
 1.17283 +            f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 1.17284 +            i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
 1.17285 +          H = (i-f/(M-m));
 1.17286 +          if (H>=6) H-=6;
 1.17287 +          H*=60;
 1.17288 +          S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
 1.17289 +        }
 1.17290 +        *(p1++) = (T)H;
 1.17291 +        *(p2++) = (T)S;
 1.17292 +        *(p3++) = (T)L;
 1.17293 +      }
 1.17294 +      return *this;
 1.17295 +    }
 1.17296 +
 1.17297 +    CImg<Tfloat> get_RGBtoHSL() const {
 1.17298 +      return CImg< Tfloat>(*this,false).RGBtoHSL();
 1.17299 +    }
 1.17300 +
 1.17301 +    //! Convert color pixels from (H,S,L) to (R,G,B).
 1.17302 +    CImg<T>& HSLtoRGB() {
 1.17303 +      if (is_empty()) return *this;
 1.17304 +      if (dim!=3)
 1.17305 +        throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
 1.17306 +                                    "should be a (H,S,V) image",
 1.17307 +                                    pixel_type(),dim);
 1.17308 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17309 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17310 +        const Tfloat
 1.17311 +          H = (Tfloat)*p1,
 1.17312 +          S = (Tfloat)*p2,
 1.17313 +          L = (Tfloat)*p3,
 1.17314 +          q = 2*L<1?L*(1+S):(L+S-L*S),
 1.17315 +          p = 2*L-q,
 1.17316 +          h = H/360,
 1.17317 +          tr = h + 1.0f/3,
 1.17318 +          tg = h,
 1.17319 +          tb = h - 1.0f/3,
 1.17320 +          ntr = tr<0?tr+1:(tr>1?tr-1:tr),
 1.17321 +          ntg = tg<0?tg+1:(tg>1?tg-1:tg),
 1.17322 +          ntb = tb<0?tb+1:(tb>1?tb-1:tb),
 1.17323 +          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))),
 1.17324 +          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))),
 1.17325 +          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)));
 1.17326 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17327 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17328 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17329 +      }
 1.17330 +      return *this;
 1.17331 +    }
 1.17332 +
 1.17333 +    CImg<Tuchar> get_HSLtoRGB() const {
 1.17334 +      return CImg<Tuchar>(*this,false).HSLtoRGB();
 1.17335 +    }
 1.17336 +
 1.17337 +    //! Convert color pixels from (R,G,B) to (H,S,I).
 1.17338 +    //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
 1.17339 +    CImg<T>& RGBtoHSI() {
 1.17340 +      if (is_empty()) return *this;
 1.17341 +      if (dim!=3)
 1.17342 +        throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
 1.17343 +                                    "should be a (R,G,B) image.",
 1.17344 +                                    pixel_type(),dim);
 1.17345 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17346 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17347 +        const Tfloat
 1.17348 +          R = (Tfloat)*p1,
 1.17349 +          G = (Tfloat)*p2,
 1.17350 +          B = (Tfloat)*p3,
 1.17351 +          nR = (R<0?0:(R>255?255:R))/255,
 1.17352 +          nG = (G<0?0:(G>255?255:G))/255,
 1.17353 +          nB = (B<0?0:(B>255?255:B))/255,
 1.17354 +          m = cimg::min(nR,nG,nB),
 1.17355 +          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),
 1.17356 +          sum = nR + nG + nB;
 1.17357 +        Tfloat H = 0, S = 0, I = 0;
 1.17358 +        if (theta>0) H = (nB<=nG)?theta:360-theta;
 1.17359 +        if (sum>0) S = 1 - 3/sum*m;
 1.17360 +        I = sum/3;
 1.17361 +        *(p1++) = (T)H;
 1.17362 +        *(p2++) = (T)S;
 1.17363 +        *(p3++) = (T)I;
 1.17364 +      }
 1.17365 +      return *this;
 1.17366 +    }
 1.17367 +
 1.17368 +    CImg<Tfloat> get_RGBtoHSI() const {
 1.17369 +      return CImg<Tfloat>(*this,false).RGBtoHSI();
 1.17370 +    }
 1.17371 +
 1.17372 +    //! Convert color pixels from (H,S,I) to (R,G,B).
 1.17373 +    CImg<T>& HSItoRGB() {
 1.17374 +      if (is_empty()) return *this;
 1.17375 +      if (dim!=3)
 1.17376 +        throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
 1.17377 +                                    "should be a (H,S,I) image",
 1.17378 +                                    pixel_type(),dim);
 1.17379 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17380 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17381 +        Tfloat
 1.17382 +          H = (Tfloat)*p1,
 1.17383 +          S = (Tfloat)*p2,
 1.17384 +          I = (Tfloat)*p3,
 1.17385 +          a = I*(1-S),
 1.17386 +          R = 0, G = 0, B = 0;
 1.17387 +        if (H<120) {
 1.17388 +          B = a;
 1.17389 +          R = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 1.17390 +          G = 3*I-(R+B);
 1.17391 +        } else if (H<240) {
 1.17392 +          H-=120;
 1.17393 +          R = a;
 1.17394 +          G = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 1.17395 +          B = 3*I-(R+G);
 1.17396 +        } else {
 1.17397 +          H-=240;
 1.17398 +          G = a;
 1.17399 +          B = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
 1.17400 +          R = 3*I-(G+B);
 1.17401 +        }
 1.17402 +        R*=255; G*=255; B*=255;
 1.17403 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17404 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17405 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17406 +      }
 1.17407 +      return *this;
 1.17408 +    }
 1.17409 +
 1.17410 +    CImg<Tfloat> get_HSItoRGB() const {
 1.17411 +      return CImg< Tuchar>(*this,false).HSItoRGB();
 1.17412 +    }
 1.17413 +
 1.17414 +    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 1.17415 +    CImg<T>& RGBtoYCbCr() {
 1.17416 +      if (is_empty()) return *this;
 1.17417 +      if (dim!=3)
 1.17418 +        throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
 1.17419 +                                    "should be a (R,G,B) image (dim=3)",
 1.17420 +                                    pixel_type(),dim);
 1.17421 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17422 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17423 +        const Tfloat
 1.17424 +          R = (Tfloat)*p1,
 1.17425 +          G = (Tfloat)*p2,
 1.17426 +          B = (Tfloat)*p3,
 1.17427 +          Y = (66*R + 129*G + 25*B + 128)/256 + 16,
 1.17428 +          Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
 1.17429 +          Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
 1.17430 +        *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
 1.17431 +        *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
 1.17432 +        *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
 1.17433 +      }
 1.17434 +      return *this;
 1.17435 +    }
 1.17436 +
 1.17437 +    CImg<Tuchar> get_RGBtoYCbCr() const {
 1.17438 +      return CImg<Tuchar>(*this,false).RGBtoYCbCr();
 1.17439 +    }
 1.17440 +
 1.17441 +    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 1.17442 +    CImg<T>& YCbCrtoRGB() {
 1.17443 +      if (is_empty()) return *this;
 1.17444 +      if (dim!=3)
 1.17445 +        throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
 1.17446 +                                    "should be a (Y,Cb,Cr)_8 image (dim=3)",
 1.17447 +                                    pixel_type(),dim);
 1.17448 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17449 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17450 +        const Tfloat
 1.17451 +          Y = (Tfloat)*p1 - 16,
 1.17452 +          Cb = (Tfloat)*p2 - 128,
 1.17453 +          Cr = (Tfloat)*p3 - 128,
 1.17454 +          R = (298*Y + 409*Cr + 128)/256,
 1.17455 +          G = (298*Y - 100*Cb - 208*Cr + 128)/256,
 1.17456 +          B = (298*Y + 516*Cb + 128)/256;
 1.17457 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17458 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17459 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17460 +      }
 1.17461 +      return *this;
 1.17462 +    }
 1.17463 +
 1.17464 +    CImg<Tuchar> get_YCbCrtoRGB() const {
 1.17465 +      return CImg<Tuchar>(*this,false).YCbCrtoRGB();
 1.17466 +    }
 1.17467 +
 1.17468 +    //! Convert color pixels from (R,G,B) to (Y,U,V).
 1.17469 +    CImg<T>& RGBtoYUV() {
 1.17470 +      if (is_empty()) return *this;
 1.17471 +      if (dim!=3)
 1.17472 +        throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
 1.17473 +                                    "should be a (R,G,B) image (dim=3)",
 1.17474 +                                    pixel_type(),dim);
 1.17475 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17476 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17477 +        const Tfloat
 1.17478 +          R = (Tfloat)*p1/255,
 1.17479 +          G = (Tfloat)*p2/255,
 1.17480 +          B = (Tfloat)*p3/255,
 1.17481 +          Y = 0.299f*R + 0.587f*G + 0.114f*B;
 1.17482 +        *(p1++) = (T)Y;
 1.17483 +        *(p2++) = (T)(0.492f*(B-Y));
 1.17484 +        *(p3++) = (T)(0.877*(R-Y));
 1.17485 +      }
 1.17486 +      return *this;
 1.17487 +    }
 1.17488 +
 1.17489 +    CImg<Tfloat> get_RGBtoYUV() const {
 1.17490 +      return CImg<Tfloat>(*this,false).RGBtoYUV();
 1.17491 +    }
 1.17492 +
 1.17493 +    //! Convert color pixels from (Y,U,V) to (R,G,B).
 1.17494 +    CImg<T>& YUVtoRGB() {
 1.17495 +      if (is_empty()) return *this;
 1.17496 +      if (dim!=3)
 1.17497 +        throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
 1.17498 +                                    "should be a (Y,U,V) image (dim=3)",
 1.17499 +                                    pixel_type(),dim);
 1.17500 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17501 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17502 +        const Tfloat
 1.17503 +          Y = (Tfloat)*p1,
 1.17504 +          U = (Tfloat)*p2,
 1.17505 +          V = (Tfloat)*p3,
 1.17506 +          R = (Y + 1.140f*V)*255,
 1.17507 +          G = (Y - 0.395f*U - 0.581f*V)*255,
 1.17508 +          B = (Y + 2.032f*U)*255;
 1.17509 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17510 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17511 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17512 +      }
 1.17513 +      return *this;
 1.17514 +    }
 1.17515 +
 1.17516 +    CImg<Tuchar> get_YUVtoRGB() const {
 1.17517 +      return CImg< Tuchar>(*this,false).YUVtoRGB();
 1.17518 +    }
 1.17519 +
 1.17520 +    //! Convert color pixels from (R,G,B) to (C,M,Y).
 1.17521 +    CImg<T>& RGBtoCMY() {
 1.17522 +      if (is_empty()) return *this;
 1.17523 +      if (dim!=3)
 1.17524 +        throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
 1.17525 +                                    "should be a (R,G,B) image (dim=3)",
 1.17526 +                                    pixel_type(),dim);
 1.17527 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17528 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17529 +        const Tfloat
 1.17530 +          R = (Tfloat)*p1/255,
 1.17531 +          G = (Tfloat)*p2/255,
 1.17532 +          B = (Tfloat)*p3/255;
 1.17533 +        *(p1++) = (T)(1 - R);
 1.17534 +        *(p2++) = (T)(1 - G);
 1.17535 +        *(p3++) = (T)(1 - B);
 1.17536 +      }
 1.17537 +      return *this;
 1.17538 +    }
 1.17539 +
 1.17540 +    CImg<Tfloat> get_RGBtoCMY() const {
 1.17541 +      return CImg<Tfloat>(*this,false).RGBtoCMY();
 1.17542 +    }
 1.17543 +
 1.17544 +    //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
 1.17545 +    CImg<T>& CMYtoRGB() {
 1.17546 +      if (is_empty()) return *this;
 1.17547 +      if (dim!=3)
 1.17548 +        throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
 1.17549 +                                    "should be a (C,M,Y) image (dim=3)",
 1.17550 +                                    pixel_type(),dim);
 1.17551 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17552 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17553 +        const Tfloat
 1.17554 +          C = (Tfloat)*p1,
 1.17555 +          M = (Tfloat)*p2,
 1.17556 +          Y = (Tfloat)*p3,
 1.17557 +          R = 255*(1 - C),
 1.17558 +          G = 255*(1 - M),
 1.17559 +          B = 255*(1 - Y);
 1.17560 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17561 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17562 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17563 +      }
 1.17564 +      return *this;
 1.17565 +    }
 1.17566 +
 1.17567 +    CImg<Tuchar> get_CMYtoRGB() const {
 1.17568 +      return CImg<Tuchar>(*this,false).CMYtoRGB();
 1.17569 +    }
 1.17570 +
 1.17571 +    //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
 1.17572 +    CImg<T>& CMYtoCMYK() {
 1.17573 +      return get_CMYtoCMYK().transfer_to(*this);
 1.17574 +    }
 1.17575 +
 1.17576 +    CImg<Tfloat> get_CMYtoCMYK() const {
 1.17577 +      if (is_empty()) return *this;
 1.17578 +      if (dim!=3)
 1.17579 +        throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
 1.17580 +                                    "should be a (C,M,Y) image (dim=3)",
 1.17581 +                                    pixel_type(),dim);
 1.17582 +      CImg<Tfloat> res(width,height,depth,4);
 1.17583 +      const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
 1.17584 +      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);
 1.17585 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17586 +        Tfloat
 1.17587 +          C = (Tfloat)*(ps1++),
 1.17588 +          M = (Tfloat)*(ps2++),
 1.17589 +          Y = (Tfloat)*(ps3++),
 1.17590 +          K = cimg::min(C,M,Y);
 1.17591 +        if (K==1) C = M = Y = 0;
 1.17592 +        else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
 1.17593 +        *(pd1++) = C;
 1.17594 +        *(pd2++) = M;
 1.17595 +        *(pd3++) = Y;
 1.17596 +        *(pd4++) = K;
 1.17597 +      }
 1.17598 +      return res;
 1.17599 +    }
 1.17600 +
 1.17601 +    //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
 1.17602 +    CImg<T>& CMYKtoCMY() {
 1.17603 +      return get_CMYKtoCMY().transfer_to(*this);
 1.17604 +    }
 1.17605 +
 1.17606 +    CImg<Tfloat> get_CMYKtoCMY() const {
 1.17607 +      if (is_empty()) return *this;
 1.17608 +      if (dim!=4)
 1.17609 +        throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
 1.17610 +                                    "should be a (C,M,Y,K) image (dim=4)",
 1.17611 +                                    pixel_type(),dim);
 1.17612 +      CImg<Tfloat> res(width,height,depth,3);
 1.17613 +      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);
 1.17614 +      Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
 1.17615 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17616 +        const Tfloat
 1.17617 +          C = (Tfloat)*ps1,
 1.17618 +          M = (Tfloat)*ps2,
 1.17619 +          Y = (Tfloat)*ps3,
 1.17620 +          K = (Tfloat)*ps4,
 1.17621 +          K1 = 1 - K;
 1.17622 +        *(pd1++) = C*K1 + K;
 1.17623 +        *(pd2++) = M*K1 + K;
 1.17624 +        *(pd3++) = Y*K1 + K;
 1.17625 +      }
 1.17626 +      return res;
 1.17627 +    }
 1.17628 +
 1.17629 +    //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
 1.17630 +    CImg<T>& RGBtoXYZ() {
 1.17631 +      if (is_empty()) return *this;
 1.17632 +      if (dim!=3)
 1.17633 +        throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
 1.17634 +                                    "should be a (R,G,B) image (dim=3)",
 1.17635 +                                    pixel_type(),dim);
 1.17636 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17637 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17638 +        const Tfloat
 1.17639 +          R = (Tfloat)*p1/255,
 1.17640 +          G = (Tfloat)*p2/255,
 1.17641 +          B = (Tfloat)*p3/255;
 1.17642 +        *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
 1.17643 +        *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
 1.17644 +        *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
 1.17645 +      }
 1.17646 +      return *this;
 1.17647 +    }
 1.17648 +
 1.17649 +    CImg<Tfloat> get_RGBtoXYZ() const {
 1.17650 +      return CImg<Tfloat>(*this,false).RGBtoXYZ();
 1.17651 +    }
 1.17652 +
 1.17653 +    //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
 1.17654 +    CImg<T>& XYZtoRGB() {
 1.17655 +      if (is_empty()) return *this;
 1.17656 +      if (dim!=3)
 1.17657 +        throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
 1.17658 +                                    "should be a (X,Y,Z) image (dim=3)",
 1.17659 +                                    pixel_type(),dim);
 1.17660 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17661 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17662 +        const Tfloat
 1.17663 +          X = (Tfloat)*p1*255,
 1.17664 +          Y = (Tfloat)*p2*255,
 1.17665 +          Z = (Tfloat)*p3*255,
 1.17666 +          R = 3.240479f*X  - 1.537150f*Y - 0.498535f*Z,
 1.17667 +          G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
 1.17668 +          B = 0.055648f*X  - 0.204043f*Y + 1.057311f*Z;
 1.17669 +        *(p1++) = (T)(R<0?0:(R>255?255:R));
 1.17670 +        *(p2++) = (T)(G<0?0:(G>255?255:G));
 1.17671 +        *(p3++) = (T)(B<0?0:(B>255?255:B));
 1.17672 +      }
 1.17673 +      return *this;
 1.17674 +    }
 1.17675 +
 1.17676 +    CImg<Tuchar> get_XYZtoRGB() const {
 1.17677 +      return CImg<Tuchar>(*this,false).XYZtoRGB();
 1.17678 +    }
 1.17679 +
 1.17680 +    //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
 1.17681 +    CImg<T>& XYZtoLab() {
 1.17682 +#define _cimg_Labf(x) ((x)>=0.008856f?(cimg_std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
 1.17683 +      if (is_empty()) return *this;
 1.17684 +      if (dim!=3)
 1.17685 +        throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
 1.17686 +                                    "should be a (X,Y,Z) image (dim=3)",
 1.17687 +                                    pixel_type(),dim);
 1.17688 +      const Tfloat
 1.17689 +        Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 1.17690 +        Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 1.17691 +        Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 1.17692 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17693 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17694 +        const Tfloat
 1.17695 +          X = (Tfloat)*p1,
 1.17696 +          Y = (Tfloat)*p2,
 1.17697 +          Z = (Tfloat)*p3,
 1.17698 +          XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
 1.17699 +          fX = (Tfloat)_cimg_Labf(XXn),
 1.17700 +          fY = (Tfloat)_cimg_Labf(YYn),
 1.17701 +          fZ = (Tfloat)_cimg_Labf(ZZn);
 1.17702 +        *(p1++) = (T)(116*fY - 16);
 1.17703 +        *(p2++) = (T)(500*(fX - fY));
 1.17704 +        *(p3++) = (T)(200*(fY - fZ));
 1.17705 +      }
 1.17706 +      return *this;
 1.17707 +    }
 1.17708 +
 1.17709 +    CImg<Tfloat> get_XYZtoLab() const {
 1.17710 +      return CImg<Tfloat>(*this,false).XYZtoLab();
 1.17711 +    }
 1.17712 +
 1.17713 +    //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
 1.17714 +    CImg<T>& LabtoXYZ() {
 1.17715 +#define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
 1.17716 +      if (is_empty()) return *this;
 1.17717 +      if (dim!=3)
 1.17718 +        throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
 1.17719 +                                    "should be a (X,Y,Z) image (dim=3)",
 1.17720 +                                    pixel_type(),dim);
 1.17721 +      const Tfloat
 1.17722 +        Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 1.17723 +        Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 1.17724 +        Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 1.17725 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17726 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17727 +        const Tfloat
 1.17728 +          L = (Tfloat)*p1,
 1.17729 +          a = (Tfloat)*p2,
 1.17730 +          b = (Tfloat)*p3,
 1.17731 +          cY = (L + 16)/116,
 1.17732 +          Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
 1.17733 +          pY = (Tfloat)cimg_std::pow(Y/Yn,(Tfloat)1/3),
 1.17734 +          cX = a/500 + pY,
 1.17735 +          X = Xn*cX*cX*cX,
 1.17736 +          cZ = pY - b/200,
 1.17737 +          Z = Zn*cZ*cZ*cZ;
 1.17738 +        *(p1++) = (T)(X);
 1.17739 +        *(p2++) = (T)(Y);
 1.17740 +        *(p3++) = (T)(Z);
 1.17741 +      }
 1.17742 +      return *this;
 1.17743 +    }
 1.17744 +
 1.17745 +    CImg<Tfloat> get_LabtoXYZ() const {
 1.17746 +      return CImg<Tfloat>(*this,false).LabtoXYZ();
 1.17747 +    }
 1.17748 +
 1.17749 +    //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
 1.17750 +    CImg<T>& XYZtoxyY() {
 1.17751 +      if (is_empty()) return *this;
 1.17752 +      if (dim!=3)
 1.17753 +        throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
 1.17754 +                                    "should be a (X,Y,Z) image (dim=3)",
 1.17755 +                                    pixel_type(),dim);
 1.17756 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17757 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17758 +        const Tfloat
 1.17759 +          X = (Tfloat)*p1,
 1.17760 +          Y = (Tfloat)*p2,
 1.17761 +          Z = (Tfloat)*p3,
 1.17762 +          sum = (X+Y+Z),
 1.17763 +          nsum = sum>0?sum:1;
 1.17764 +        *(p1++) = (T)(X/nsum);
 1.17765 +        *(p2++) = (T)(Y/nsum);
 1.17766 +        *(p3++) = (T)Y;
 1.17767 +      }
 1.17768 +      return *this;
 1.17769 +    }
 1.17770 +
 1.17771 +    CImg<Tfloat> get_XYZtoxyY() const {
 1.17772 +      return CImg<Tfloat>(*this,false).XYZtoxyY();
 1.17773 +    }
 1.17774 +
 1.17775 +    //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
 1.17776 +    CImg<T>& xyYtoXYZ() {
 1.17777 +      if (is_empty()) return *this;
 1.17778 +      if (dim!=3)
 1.17779 +        throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
 1.17780 +                                    "should be a (x,y,Y) image (dim=3)",
 1.17781 +                                    pixel_type(),dim);
 1.17782 +      T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 1.17783 +      for (unsigned long N = width*height*depth; N; --N) {
 1.17784 +        const Tfloat
 1.17785 +         px = (Tfloat)*p1,
 1.17786 +         py = (Tfloat)*p2,
 1.17787 +         Y = (Tfloat)*p3,
 1.17788 +         ny = py>0?py:1;
 1.17789 +        *(p1++) = (T)(px*Y/ny);
 1.17790 +        *(p2++) = (T)Y;
 1.17791 +        *(p3++) = (T)((1-px-py)*Y/ny);
 1.17792 +      }
 1.17793 +      return *this;
 1.17794 +    }
 1.17795 +
 1.17796 +    CImg<Tfloat> get_xyYtoXYZ() const {
 1.17797 +      return CImg<Tfloat>(*this,false).xyYtoXYZ();
 1.17798 +    }
 1.17799 +
 1.17800 +    //! Convert a (R,G,B) image to a (L,a,b) one.
 1.17801 +    CImg<T>& RGBtoLab() {
 1.17802 +      return RGBtoXYZ().XYZtoLab();
 1.17803 +    }
 1.17804 +
 1.17805 +    CImg<Tfloat> get_RGBtoLab() const {
 1.17806 +      return CImg<Tfloat>(*this,false).RGBtoLab();
 1.17807 +    }
 1.17808 +
 1.17809 +    //! Convert a (L,a,b) image to a (R,G,B) one.
 1.17810 +    CImg<T>& LabtoRGB() {
 1.17811 +      return LabtoXYZ().XYZtoRGB();
 1.17812 +    }
 1.17813 +
 1.17814 +    CImg<Tuchar> get_LabtoRGB() const {
 1.17815 +      return CImg<Tuchar>(*this,false).LabtoRGB();
 1.17816 +    }
 1.17817 +
 1.17818 +    //! Convert a (R,G,B) image to a (x,y,Y) one.
 1.17819 +    CImg<T>& RGBtoxyY() {
 1.17820 +      return RGBtoXYZ().XYZtoxyY();
 1.17821 +    }
 1.17822 +
 1.17823 +    CImg<Tfloat> get_RGBtoxyY() const {
 1.17824 +      return CImg<Tfloat>(*this,false).RGBtoxyY();
 1.17825 +    }
 1.17826 +
 1.17827 +    //! Convert a (x,y,Y) image to a (R,G,B) one.
 1.17828 +    CImg<T>& xyYtoRGB() {
 1.17829 +      return xyYtoXYZ().XYZtoRGB();
 1.17830 +    }
 1.17831 +
 1.17832 +    CImg<Tuchar> get_xyYtoRGB() const {
 1.17833 +      return CImg<Tuchar>(*this,false).xyYtoRGB();
 1.17834 +    }
 1.17835 +
 1.17836 +    //! Convert a (R,G,B) image to a (C,M,Y,K) one.
 1.17837 +    CImg<T>& RGBtoCMYK() {
 1.17838 +      return RGBtoCMY().CMYtoCMYK();
 1.17839 +    }
 1.17840 +
 1.17841 +    CImg<Tfloat> get_RGBtoCMYK() const {
 1.17842 +      return CImg<Tfloat>(*this,false).RGBtoCMYK();
 1.17843 +    }
 1.17844 +
 1.17845 +    //! Convert a (C,M,Y,K) image to a (R,G,B) one.
 1.17846 +    CImg<T>& CMYKtoRGB() {
 1.17847 +      return CMYKtoCMY().CMYtoRGB();
 1.17848 +    }
 1.17849 +
 1.17850 +    CImg<Tuchar> get_CMYKtoRGB() const {
 1.17851 +      return CImg<Tuchar>(*this,false).CMYKtoRGB();
 1.17852 +    }
 1.17853 +
 1.17854 +    //! Convert a (R,G,B) image to a Bayer-coded representation.
 1.17855 +    /**
 1.17856 +       \note First (upper-left) pixel if the red component of the pixel color.
 1.17857 +    **/
 1.17858 +    CImg<T>& RGBtoBayer() {
 1.17859 +      return get_RGBtoBayer().transfer_to(*this);
 1.17860 +    }
 1.17861 +
 1.17862 +    CImg<T> get_RGBtoBayer() const {
 1.17863 +      if (is_empty()) return *this;
 1.17864 +      if (dim!=3)
 1.17865 +        throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
 1.17866 +                                    "should be a (R,G,B) image (dim=3)",
 1.17867 +                                    pixel_type(),dim);
 1.17868 +      CImg<T> res(width,height,depth,1);
 1.17869 +      const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
 1.17870 +      T *ptrd = res.data;
 1.17871 +      cimg_forXYZ(*this,x,y,z) {
 1.17872 +        if (y%2) {
 1.17873 +          if (x%2) *(ptrd++) = *pB;
 1.17874 +          else *(ptrd++) = *pG;
 1.17875 +        } else {
 1.17876 +          if (x%2) *(ptrd++) = *pG;
 1.17877 +          else *(ptrd++) = *pR;
 1.17878 +        }
 1.17879 +        ++pR; ++pG; ++pB;
 1.17880 +      }
 1.17881 +      return res;
 1.17882 +    }
 1.17883 +
 1.17884 +    //! Convert a Bayer-coded image to a (R,G,B) color image.
 1.17885 +    CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
 1.17886 +      return get_BayertoRGB(interpolation_type).transfer_to(*this);
 1.17887 +    }
 1.17888 +
 1.17889 +    CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
 1.17890 +      if (is_empty()) return *this;
 1.17891 +      if (dim!=1)
 1.17892 +        throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
 1.17893 +                                    "should be a Bayer image (dim=1)",
 1.17894 +                                    pixel_type(),dim);
 1.17895 +      CImg<Tuchar> res(width,height,depth,3);
 1.17896 +      CImg_3x3(I,T);
 1.17897 +      Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
 1.17898 +      switch (interpolation_type) {
 1.17899 +      case 3 : { // Edge-directed
 1.17900 +        CImg_3x3(R,T);
 1.17901 +        CImg_3x3(G,T);
 1.17902 +        CImg_3x3(B,T);
 1.17903 +        cimg_forXYZ(*this,x,y,z) {
 1.17904 +          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;
 1.17905 +          cimg_get3x3(*this,x,y,z,0,I);
 1.17906 +          if (y%2) {
 1.17907 +            if (x%2) {
 1.17908 +              const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 1.17909 +              *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 1.17910 +            } else *pG = (Tuchar)Icc;
 1.17911 +          } else {
 1.17912 +            if (x%2) *pG = (Tuchar)Icc;
 1.17913 +            else {
 1.17914 +              const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 1.17915 +              *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 1.17916 +            }
 1.17917 +          }
 1.17918 +          ++pG;
 1.17919 +        }
 1.17920 +        cimg_forXYZ(*this,x,y,z) {
 1.17921 +          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;
 1.17922 +          cimg_get3x3(*this,x,y,z,0,I);
 1.17923 +          cimg_get3x3(res,x,y,z,1,G);
 1.17924 +          if (y%2) {
 1.17925 +            if (x%2) *pB = (Tuchar)Icc;
 1.17926 +            else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
 1.17927 +          } else {
 1.17928 +            if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
 1.17929 +            else *pR = (Tuchar)Icc;
 1.17930 +          }
 1.17931 +          ++pR; ++pB;
 1.17932 +        }
 1.17933 +        pR = res.ptr(0,0,0,0);
 1.17934 +        pG = res.ptr(0,0,0,1);
 1.17935 +        pB = res.ptr(0,0,0,2);
 1.17936 +        cimg_forXYZ(*this,x,y,z) {
 1.17937 +          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;
 1.17938 +          cimg_get3x3(res,x,y,z,0,R);
 1.17939 +          cimg_get3x3(res,x,y,z,1,G);
 1.17940 +          cimg_get3x3(res,x,y,z,2,B);
 1.17941 +          if (y%2) {
 1.17942 +            if (x%2) {
 1.17943 +              const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 1.17944 +              *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
 1.17945 +            }
 1.17946 +          } else {
 1.17947 +            if (!(x%2)) {
 1.17948 +              const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 1.17949 +              *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
 1.17950 +            }
 1.17951 +          }
 1.17952 +          ++pR; ++pG; ++pB;
 1.17953 +        }
 1.17954 +      } break;
 1.17955 +      case 2 : { // Linear interpolation
 1.17956 +        cimg_forXYZ(*this,x,y,z) {
 1.17957 +          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;
 1.17958 +          cimg_get3x3(*this,x,y,z,0,I);
 1.17959 +          if (y%2) {
 1.17960 +            if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
 1.17961 +            else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
 1.17962 +          } else {
 1.17963 +            if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
 1.17964 +            else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
 1.17965 +          }
 1.17966 +          ++pR; ++pG; ++pB;
 1.17967 +        }
 1.17968 +      } break;
 1.17969 +      case 1 : { // Nearest neighbor interpolation
 1.17970 +        cimg_forXYZ(*this,x,y,z) {
 1.17971 +          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;
 1.17972 +          cimg_get3x3(*this,x,y,z,0,I);
 1.17973 +          if (y%2) {
 1.17974 +            if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
 1.17975 +            else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
 1.17976 +          } else {
 1.17977 +            if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
 1.17978 +            else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
 1.17979 +          }
 1.17980 +          ++pR; ++pG; ++pB;
 1.17981 +        }
 1.17982 +      } break;
 1.17983 +      default : { // 0-filling interpolation
 1.17984 +        const T *ptrs = data;
 1.17985 +        res.fill(0);
 1.17986 +        cimg_forXYZ(*this,x,y,z) {
 1.17987 +          const T val = *(ptrs++);
 1.17988 +          if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
 1.17989 +          ++pR; ++pG; ++pB;
 1.17990 +        }
 1.17991 +      }
 1.17992 +      }
 1.17993 +      return res;
 1.17994 +    }
 1.17995 +
 1.17996 +    //@}
 1.17997 +    //-------------------
 1.17998 +    //
 1.17999 +    //! \name Drawing
 1.18000 +    //@{
 1.18001 +    //-------------------
 1.18002 +
 1.18003 +    // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
 1.18004 +    // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
 1.18005 +    template<typename tc>
 1.18006 +    CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
 1.18007 +                            const tc *const color, const float opacity=1,
 1.18008 +                            const float brightness=1, const bool init=false) {
 1.18009 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.18010 +      static float nopacity = 0, copacity = 0;
 1.18011 +      static unsigned int whz = 0;
 1.18012 +      static const tc *col = 0;
 1.18013 +      if (init) {
 1.18014 +        nopacity = cimg::abs(opacity);
 1.18015 +        copacity = 1 - cimg::max(opacity,0);
 1.18016 +        whz = width*height*depth;
 1.18017 +      } else {
 1.18018 +        const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
 1.18019 +        if (dx>=0) {
 1.18020 +          col = color;
 1.18021 +          const unsigned int off = whz-dx-1;
 1.18022 +          T *ptrd = ptr(nx0,y);
 1.18023 +          if (opacity>=1) { // ** Opaque drawing **
 1.18024 +            if (brightness==1) { // Brightness==1
 1.18025 +              if (sizeof(T)!=1) cimg_forV(*this,k) {
 1.18026 +                const T val = (T)*(col++);
 1.18027 +                for (int x = dx; x>=0; --x) *(ptrd++) = val;
 1.18028 +                ptrd+=off;
 1.18029 +              } else cimg_forV(*this,k) {
 1.18030 +                const T val = (T)*(col++);
 1.18031 +                cimg_std::memset(ptrd,(int)val,dx+1);
 1.18032 +                ptrd+=whz;
 1.18033 +              }
 1.18034 +            } else if (brightness<1) { // Brightness<1
 1.18035 +              if (sizeof(T)!=1) cimg_forV(*this,k) {
 1.18036 +                const T val = (T)(*(col++)*brightness);
 1.18037 +                for (int x = dx; x>=0; --x) *(ptrd++) = val;
 1.18038 +                ptrd+=off;
 1.18039 +              } else cimg_forV(*this,k) {
 1.18040 +                const T val = (T)(*(col++)*brightness);
 1.18041 +                cimg_std::memset(ptrd,(int)val,dx+1);
 1.18042 +                ptrd+=whz;
 1.18043 +              }
 1.18044 +            } else { // Brightness>1
 1.18045 +              if (sizeof(T)!=1) cimg_forV(*this,k) {
 1.18046 +                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 1.18047 +                for (int x = dx; x>=0; --x) *(ptrd++) = val;
 1.18048 +                ptrd+=off;
 1.18049 +              } else cimg_forV(*this,k) {
 1.18050 +                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 1.18051 +                cimg_std::memset(ptrd,(int)val,dx+1);
 1.18052 +                ptrd+=whz;
 1.18053 +              }
 1.18054 +            }
 1.18055 +          } else { // ** Transparent drawing **
 1.18056 +            if (brightness==1) { // Brightness==1
 1.18057 +              cimg_forV(*this,k) {
 1.18058 +                const T val = (T)*(col++);
 1.18059 +                for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 1.18060 +                ptrd+=off;
 1.18061 +              }
 1.18062 +            } else if (brightness<=1) { // Brightness<1
 1.18063 +              cimg_forV(*this,k) {
 1.18064 +                const T val = (T)(*(col++)*brightness);
 1.18065 +                for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 1.18066 +                ptrd+=off;
 1.18067 +              }
 1.18068 +            } else { // Brightness>1
 1.18069 +              cimg_forV(*this,k) {
 1.18070 +                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 1.18071 +                for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 1.18072 +                ptrd+=off;
 1.18073 +              }
 1.18074 +            }
 1.18075 +          }
 1.18076 +        }
 1.18077 +      }
 1.18078 +      return *this;
 1.18079 +    }
 1.18080 +
 1.18081 +    template<typename tc>
 1.18082 +    CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
 1.18083 +      return _draw_scanline(0,0,0,color,opacity,0,true);
 1.18084 +    }
 1.18085 +
 1.18086 +    //! Draw a 2D colored point (pixel).
 1.18087 +    /**
 1.18088 +       \param x0 X-coordinate of the point.
 1.18089 +       \param y0 Y-coordinate of the point.
 1.18090 +       \param color Pointer to \c dimv() consecutive values, defining the color values.
 1.18091 +       \param opacity Drawing opacity (optional).
 1.18092 +       \note
 1.18093 +       - Clipping is supported.
 1.18094 +       - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.
 1.18095 +       \par Example:
 1.18096 +       \code
 1.18097 +       CImg<unsigned char> img(100,100,1,3,0);
 1.18098 +       const unsigned char color[] = { 255,128,64 };
 1.18099 +       img.draw_point(50,50,color);
 1.18100 +       \endcode
 1.18101 +    **/
 1.18102 +    template<typename tc>
 1.18103 +    CImg<T>& draw_point(const int x0, const int y0,
 1.18104 +                        const tc *const color, const float opacity=1) {
 1.18105 +      return draw_point(x0,y0,0,color,opacity);
 1.18106 +    }
 1.18107 +
 1.18108 +    //! Draw a 2D colored point (pixel).
 1.18109 +    template<typename tc>
 1.18110 +    CImg<T>& draw_point(const int x0, const int y0,
 1.18111 +                        const CImg<tc>& color, const float opacity=1) {
 1.18112 +      return draw_point(x0,y0,color.data,opacity);
 1.18113 +    }
 1.18114 +
 1.18115 +    //! Draw a 3D colored point (voxel).
 1.18116 +    template<typename tc>
 1.18117 +    CImg<T>& draw_point(const int x0, const int y0, const int z0,
 1.18118 +                        const tc *const color, const float opacity=1) {
 1.18119 +      if (is_empty()) return *this;
 1.18120 +      if (!color)
 1.18121 +        throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
 1.18122 +                                    pixel_type());
 1.18123 +      if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
 1.18124 +        const unsigned int whz = width*height*depth;
 1.18125 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18126 +        T *ptrd = ptr(x0,y0,z0,0);
 1.18127 +        const tc *col = color;
 1.18128 +        if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 1.18129 +        else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
 1.18130 +      }
 1.18131 +      return *this;
 1.18132 +    }
 1.18133 +
 1.18134 +    //! Draw a 3D colored point (voxel).
 1.18135 +    template<typename tc>
 1.18136 +    CImg<T>& draw_point(const int x0, const int y0, const int z0,
 1.18137 +                        const CImg<tc>& color, const float opacity=1) {
 1.18138 +      return draw_point(x0,y0,z0,color.data,opacity);
 1.18139 +    }
 1.18140 +
 1.18141 +    // Draw a cloud of colored point (internal).
 1.18142 +    template<typename t, typename tc>
 1.18143 +    CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
 1.18144 +                         const tc *const color, const float opacity) {
 1.18145 +      if (is_empty() || !points || !W) return *this;
 1.18146 +      switch (H) {
 1.18147 +      case 0 : case 1 :
 1.18148 +        throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
 1.18149 +                                    pixel_type());
 1.18150 +      case 2 : {
 1.18151 +        for (unsigned int i = 0; i<W; ++i) {
 1.18152 +          const int x = (int)points(i,0), y = (int)points(i,1);
 1.18153 +          draw_point(x,y,color,opacity);
 1.18154 +        }
 1.18155 +      } break;
 1.18156 +      default : {
 1.18157 +        for (unsigned int i = 0; i<W; ++i) {
 1.18158 +          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 1.18159 +          draw_point(x,y,z,color,opacity);
 1.18160 +        }
 1.18161 +      }
 1.18162 +      }
 1.18163 +      return *this;
 1.18164 +    }
 1.18165 +
 1.18166 +    //! Draw a cloud of colored points.
 1.18167 +    /**
 1.18168 +       \param points Coordinates of vertices, stored as a list of vectors.
 1.18169 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.18170 +       \param opacity Drawing opacity (optional).
 1.18171 +       \note
 1.18172 +       - This function uses several call to the single CImg::draw_point() procedure,
 1.18173 +       depending on the vectors size in \p points.
 1.18174 +       \par Example:
 1.18175 +       \code
 1.18176 +       CImg<unsigned char> img(100,100,1,3,0);
 1.18177 +       const unsigned char color[] = { 255,128,64 };
 1.18178 +       CImgList<int> points;
 1.18179 +       points.insert(CImg<int>::vector(0,0)).
 1.18180 +             .insert(CImg<int>::vector(70,10)).
 1.18181 +             .insert(CImg<int>::vector(80,60)).
 1.18182 +             .insert(CImg<int>::vector(10,90));
 1.18183 +       img.draw_point(points,color);
 1.18184 +       \endcode
 1.18185 +    **/
 1.18186 +    template<typename t, typename tc>
 1.18187 +    CImg<T>& draw_point(const CImgList<t>& points,
 1.18188 +                        const tc *const color, const float opacity=1) {
 1.18189 +      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 1.18190 +      return _draw_point(points,points.size,H,color,opacity);
 1.18191 +    }
 1.18192 +
 1.18193 +    //! Draw a cloud of colored points.
 1.18194 +    template<typename t, typename tc>
 1.18195 +    CImg<T>& draw_point(const CImgList<t>& points,
 1.18196 +                        const CImg<tc>& color, const float opacity=1) {
 1.18197 +      return draw_point(points,color.data,opacity);
 1.18198 +    }
 1.18199 +
 1.18200 +    //! Draw a cloud of colored points.
 1.18201 +    /**
 1.18202 +       \note
 1.18203 +       - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
 1.18204 +       (sequence of vectors aligned along the x-axis).
 1.18205 +    **/
 1.18206 +    template<typename t, typename tc>
 1.18207 +    CImg<T>& draw_point(const CImg<t>& points,
 1.18208 +                        const tc *const color, const float opacity=1) {
 1.18209 +      return _draw_point(points,points.width,points.height,color,opacity);
 1.18210 +    }
 1.18211 +
 1.18212 +    //! Draw a cloud of colored points.
 1.18213 +    template<typename t, typename tc>
 1.18214 +    CImg<T>& draw_point(const CImg<t>& points,
 1.18215 +                        const CImg<tc>& color, const float opacity=1) {
 1.18216 +      return draw_point(points,color.data,opacity);
 1.18217 +    }
 1.18218 +
 1.18219 +    //! Draw a 2D colored line.
 1.18220 +    /**
 1.18221 +       \param x0 X-coordinate of the starting line point.
 1.18222 +       \param y0 Y-coordinate of the starting line point.
 1.18223 +       \param x1 X-coordinate of the ending line point.
 1.18224 +       \param y1 Y-coordinate of the ending line point.
 1.18225 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.18226 +       \param opacity Drawing opacity (optional).
 1.18227 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.18228 +       \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional).
 1.18229 +       \note
 1.18230 +       - Clipping is supported.
 1.18231 +       - Line routine uses Bresenham's algorithm.
 1.18232 +       - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.
 1.18233 +       \par Example:
 1.18234 +       \code
 1.18235 +       CImg<unsigned char> img(100,100,1,3,0);
 1.18236 +       const unsigned char color[] = { 255,128,64 };
 1.18237 +        img.draw_line(40,40,80,70,color);
 1.18238 +       \endcode
 1.18239 +    **/
 1.18240 +    template<typename tc>
 1.18241 +    CImg<T>& draw_line(const int x0, const int y0,
 1.18242 +                       const int x1, const int y1,
 1.18243 +                       const tc *const color, const float opacity=1,
 1.18244 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18245 +      if (is_empty()) return *this;
 1.18246 +      if (!color)
 1.18247 +        throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
 1.18248 +                                    pixel_type());
 1.18249 +      static unsigned int hatch = ~0U - (~0U>>1);
 1.18250 +      if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18251 +      const bool xdir = x0<x1, ydir = y0<y1;
 1.18252 +      int
 1.18253 +        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 1.18254 +        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 1.18255 +        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 1.18256 +        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 1.18257 +        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 1.18258 +      if (xright<0 || xleft>=dimx()) return *this;
 1.18259 +      if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
 1.18260 +      if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
 1.18261 +      if (ydown<0 || yup>=dimy()) return *this;
 1.18262 +      if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
 1.18263 +      if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
 1.18264 +      T *ptrd0 = ptr(nx0,ny0);
 1.18265 +      int dx = xright - xleft, dy = ydown - yup;
 1.18266 +      const bool steep = dy>dx;
 1.18267 +      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 1.18268 +      const int
 1.18269 +        offx = (nx0<nx1?1:-1)*(steep?width:1),
 1.18270 +        offy = (ny0<ny1?1:-1)*(steep?1:width),
 1.18271 +        wh = width*height;
 1.18272 +      if (opacity>=1) {
 1.18273 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18274 +          if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
 1.18275 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18276 +          ptrd0+=offx;
 1.18277 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18278 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18279 +          T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 1.18280 +          ptrd0+=offx;
 1.18281 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18282 +        }
 1.18283 +      } else {
 1.18284 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18285 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18286 +          if (pattern&hatch) {
 1.18287 +            T *ptrd = ptrd0; const tc* col = color;
 1.18288 +            cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 1.18289 +          }
 1.18290 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18291 +          ptrd0+=offx;
 1.18292 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18293 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18294 +          T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 1.18295 +          ptrd0+=offx;
 1.18296 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18297 +        }
 1.18298 +      }
 1.18299 +      return *this;
 1.18300 +    }
 1.18301 +
 1.18302 +    //! Draw a 2D colored line.
 1.18303 +    template<typename tc>
 1.18304 +    CImg<T>& draw_line(const int x0, const int y0,
 1.18305 +                       const int x1, const int y1,
 1.18306 +                       const CImg<tc>& color, const float opacity=1,
 1.18307 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18308 +      return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
 1.18309 +    }
 1.18310 +
 1.18311 +    //! Draw a 2D colored line, with z-buffering.
 1.18312 +    template<typename tc>
 1.18313 +    CImg<T>& draw_line(float *const zbuffer,
 1.18314 +                       const int x0, const int y0, const float z0,
 1.18315 +                       const int x1, const int y1, const float z1,
 1.18316 +                       const tc *const color, const float opacity=1,
 1.18317 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18318 +      if (!is_empty() && z0>0 && z1>0) {
 1.18319 +        if (!color)
 1.18320 +          throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
 1.18321 +                                      pixel_type());
 1.18322 +        static unsigned int hatch = ~0U - (~0U>>1);
 1.18323 +        if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18324 +        const bool xdir = x0<x1, ydir = y0<y1;
 1.18325 +        int
 1.18326 +          nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 1.18327 +          &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 1.18328 +          &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 1.18329 +          &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 1.18330 +          &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 1.18331 +        float
 1.18332 +          Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
 1.18333 +          &zleft = xdir?nz0:nz1,
 1.18334 +          &zright = xdir?nz1:nz0,
 1.18335 +          &zup = ydir?nz0:nz1,
 1.18336 +          &zdown = ydir?nz1:nz0;
 1.18337 +        if (xright<0 || xleft>=dimx()) return *this;
 1.18338 +        if (xleft<0) {
 1.18339 +          const int D = xright - xleft;
 1.18340 +          yleft-=xleft*(yright - yleft)/D;
 1.18341 +          zleft-=xleft*(zright - zleft)/D;
 1.18342 +          xleft = 0;
 1.18343 +        }
 1.18344 +        if (xright>=dimx()) {
 1.18345 +          const int d = xright - dimx(), D = xright - xleft;
 1.18346 +          yright-=d*(yright - yleft)/D;
 1.18347 +          zright-=d*(zright - zleft)/D;
 1.18348 +          xright = dimx()-1;
 1.18349 +        }
 1.18350 +        if (ydown<0 || yup>=dimy()) return *this;
 1.18351 +        if (yup<0) {
 1.18352 +          const int D = ydown - yup;
 1.18353 +          xup-=yup*(xdown - xup)/D;
 1.18354 +          zup-=yup*(zdown - zup)/D;
 1.18355 +          yup = 0;
 1.18356 +        }
 1.18357 +        if (ydown>=dimy()) {
 1.18358 +          const int d = ydown - dimy(), D = ydown - yup;
 1.18359 +          xdown-=d*(xdown - xup)/D;
 1.18360 +          zdown-=d*(zdown - zup)/D;
 1.18361 +          ydown = dimy()-1;
 1.18362 +        }
 1.18363 +        T *ptrd0 = ptr(nx0,ny0);
 1.18364 +        float *ptrz = zbuffer + nx0 + ny0*width;
 1.18365 +        int dx = xright - xleft, dy = ydown - yup;
 1.18366 +        const bool steep = dy>dx;
 1.18367 +        if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 1.18368 +        const int
 1.18369 +          offx = (nx0<nx1?1:-1)*(steep?width:1),
 1.18370 +          offy = (ny0<ny1?1:-1)*(steep?1:width),
 1.18371 +          wh = width*height,
 1.18372 +          ndx = dx>0?dx:1;
 1.18373 +        if (opacity>=1) {
 1.18374 +          if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18375 +            const float z = Z0 + x*dz/ndx;
 1.18376 +            if (z>*ptrz && pattern&hatch) {
 1.18377 +              *ptrz = z;
 1.18378 +              T *ptrd = ptrd0; const tc *col = color;
 1.18379 +              cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 1.18380 +            }
 1.18381 +            hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18382 +            ptrd0+=offx; ptrz+=offx;
 1.18383 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18384 +          } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18385 +            const float z = Z0 + x*dz/ndx;
 1.18386 +            if (z>*ptrz) {
 1.18387 +              *ptrz = z;
 1.18388 +              T *ptrd = ptrd0; const tc *col = color;
 1.18389 +              cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
 1.18390 +            }
 1.18391 +            ptrd0+=offx; ptrz+=offx;
 1.18392 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18393 +          }
 1.18394 +        } else {
 1.18395 +          const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18396 +          if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18397 +            const float z = Z0 + x*dz/ndx;
 1.18398 +            if (z>*ptrz && pattern&hatch) {
 1.18399 +              *ptrz = z;
 1.18400 +              T *ptrd = ptrd0; const tc *col = color;
 1.18401 +              cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 1.18402 +            }
 1.18403 +            hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18404 +            ptrd0+=offx; ptrz+=offx;
 1.18405 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18406 +          } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18407 +            const float z = Z0 + x*dz/ndx;
 1.18408 +            if (z>*ptrz) {
 1.18409 +              *ptrz = z;
 1.18410 +              T *ptrd = ptrd0; const tc *col = color;
 1.18411 +              cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
 1.18412 +            }
 1.18413 +            ptrd0+=offx; ptrz+=offx;
 1.18414 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18415 +          }
 1.18416 +        }
 1.18417 +      }
 1.18418 +      return *this;
 1.18419 +    }
 1.18420 +
 1.18421 +    //! Draw a 2D colored line, with z-buffering.
 1.18422 +    template<typename tc>
 1.18423 +    CImg<T>& draw_line(float *const zbuffer,
 1.18424 +                       const int x0, const int y0, const float z0,
 1.18425 +                       const int x1, const int y1, const float z1,
 1.18426 +                       const CImg<tc>& color, const float opacity=1,
 1.18427 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18428 +      return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
 1.18429 +    }
 1.18430 +
 1.18431 +    //! Draw a 3D colored line.
 1.18432 +    template<typename tc>
 1.18433 +    CImg<T>& draw_line(const int x0, const int y0, const int z0,
 1.18434 +                       const int x1, const int y1, const int z1,
 1.18435 +                       const tc *const color, const float opacity=1,
 1.18436 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18437 +      if (is_empty()) return *this;
 1.18438 +      if (!color)
 1.18439 +        throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
 1.18440 +                                    pixel_type());
 1.18441 +      static unsigned int hatch = ~0U - (~0U>>1);
 1.18442 +      if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18443 +      int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
 1.18444 +      if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 1.18445 +      if (nx1<0 || nx0>=dimx()) return *this;
 1.18446 +      if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
 1.18447 +      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; }
 1.18448 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 1.18449 +      if (ny1<0 || ny0>=dimy()) return *this;
 1.18450 +      if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
 1.18451 +      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; }
 1.18452 +      if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 1.18453 +      if (nz1<0 || nz0>=dimz()) return *this;
 1.18454 +      if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
 1.18455 +      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; }
 1.18456 +      const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
 1.18457 +      const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
 1.18458 +      float x = (float)nx0, y = (float)ny0, z = (float)nz0;
 1.18459 +      if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
 1.18460 +        if (!(~pattern) || (~pattern && pattern&hatch)) {
 1.18461 +          T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
 1.18462 +          const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 1.18463 +        }
 1.18464 +        x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
 1.18465 +      } else {
 1.18466 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18467 +        for (unsigned int t = 0; t<=dmax; ++t) {
 1.18468 +          if (!(~pattern) || (~pattern && pattern&hatch)) {
 1.18469 +            T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
 1.18470 +            const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
 1.18471 +          }
 1.18472 +          x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
 1.18473 +        }
 1.18474 +      }
 1.18475 +      return *this;
 1.18476 +    }
 1.18477 +
 1.18478 +    //! Draw a 3D colored line.
 1.18479 +    template<typename tc>
 1.18480 +    CImg<T>& draw_line(const int x0, const int y0, const int z0,
 1.18481 +                       const int x1, const int y1, const int z1,
 1.18482 +                       const CImg<tc>& color, const float opacity=1,
 1.18483 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18484 +      return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
 1.18485 +    }
 1.18486 +
 1.18487 +    //! Draw a 2D textured line.
 1.18488 +    /**
 1.18489 +       \param x0 X-coordinate of the starting line point.
 1.18490 +       \param y0 Y-coordinate of the starting line point.
 1.18491 +       \param x1 X-coordinate of the ending line point.
 1.18492 +       \param y1 Y-coordinate of the ending line point.
 1.18493 +       \param texture Texture image defining the pixel colors.
 1.18494 +       \param tx0 X-coordinate of the starting texture point.
 1.18495 +       \param ty0 Y-coordinate of the starting texture point.
 1.18496 +       \param tx1 X-coordinate of the ending texture point.
 1.18497 +       \param ty1 Y-coordinate of the ending texture point.
 1.18498 +       \param opacity Drawing opacity (optional).
 1.18499 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.18500 +       \param init_hatch Flag telling if the hash variable must be reinitialized (optional).
 1.18501 +       \note
 1.18502 +       - Clipping is supported but not for texture coordinates.
 1.18503 +       - Line routine uses the well known Bresenham's algorithm.
 1.18504 +       \par Example:
 1.18505 +       \code
 1.18506 +       CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm");
 1.18507 +       const unsigned char color[] = { 255,128,64 };
 1.18508 +       img.draw_line(40,40,80,70,texture,0,0,255,255);
 1.18509 +       \endcode
 1.18510 +    **/
 1.18511 +    template<typename tc>
 1.18512 +    CImg<T>& draw_line(const int x0, const int y0,
 1.18513 +                       const int x1, const int y1,
 1.18514 +                       const CImg<tc>& texture,
 1.18515 +                       const int tx0, const int ty0,
 1.18516 +                       const int tx1, const int ty1,
 1.18517 +                       const float opacity=1,
 1.18518 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18519 +      if (is_empty()) return *this;
 1.18520 +      if (!texture || texture.dim<dim)
 1.18521 +        throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.18522 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.18523 +      if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 1.18524 +      static unsigned int hatch = ~0U - (~0U>>1);
 1.18525 +      if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18526 +      const bool xdir = x0<x1, ydir = y0<y1;
 1.18527 +      int
 1.18528 +        dtx = tx1-tx0, dty = ty1-ty0,
 1.18529 +        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 1.18530 +        tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
 1.18531 +        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 1.18532 +        &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 1.18533 +        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
 1.18534 +        &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 1.18535 +      if (xright<0 || xleft>=dimx()) return *this;
 1.18536 +      if (xleft<0) {
 1.18537 +        const int D = xright - xleft;
 1.18538 +        yleft-=xleft*(yright - yleft)/D;
 1.18539 +        txleft-=xleft*(txright - txleft)/D;
 1.18540 +        tyleft-=xleft*(tyright - tyleft)/D;
 1.18541 +        xleft = 0;
 1.18542 +      }
 1.18543 +      if (xright>=dimx()) {
 1.18544 +        const int d = xright - dimx(), D = xright - xleft;
 1.18545 +        yright-=d*(yright - yleft)/D;
 1.18546 +        txright-=d*(txright - txleft)/D;
 1.18547 +        tyright-=d*(tyright - tyleft)/D;
 1.18548 +        xright = dimx()-1;
 1.18549 +      }
 1.18550 +      if (ydown<0 || yup>=dimy()) return *this;
 1.18551 +      if (yup<0) {
 1.18552 +        const int D = ydown - yup;
 1.18553 +        xup-=yup*(xdown - xup)/D;
 1.18554 +        txup-=yup*(txdown - txup)/D;
 1.18555 +        tyup-=yup*(tydown - tyup)/D;
 1.18556 +        yup = 0;
 1.18557 +      }
 1.18558 +      if (ydown>=dimy()) {
 1.18559 +        const int d = ydown - dimy(), D = ydown - yup;
 1.18560 +        xdown-=d*(xdown - xup)/D;
 1.18561 +        txdown-=d*(txdown - txup)/D;
 1.18562 +        tydown-=d*(tydown - tyup)/D;
 1.18563 +        ydown = dimy()-1;
 1.18564 +      }
 1.18565 +      T *ptrd0 = ptr(nx0,ny0);
 1.18566 +      int dx = xright - xleft, dy = ydown - yup;
 1.18567 +      const bool steep = dy>dx;
 1.18568 +      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 1.18569 +      const int
 1.18570 +        offx = (nx0<nx1?1:-1)*(steep?width:1),
 1.18571 +        offy = (ny0<ny1?1:-1)*(steep?1:width),
 1.18572 +        wh = width*height,
 1.18573 +        ndx = dx>0?dx:1;
 1.18574 +      if (opacity>=1) {
 1.18575 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18576 +          if (pattern&hatch) {
 1.18577 +            T *ptrd = ptrd0;
 1.18578 +            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 1.18579 +            cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
 1.18580 +          }
 1.18581 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18582 +          ptrd0+=offx;
 1.18583 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18584 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18585 +          T *ptrd = ptrd0;
 1.18586 +          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 1.18587 +          cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
 1.18588 +          ptrd0+=offx;
 1.18589 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18590 +        }
 1.18591 +      } else {
 1.18592 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18593 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18594 +          T *ptrd = ptrd0;
 1.18595 +          if (pattern&hatch) {
 1.18596 +            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 1.18597 +            cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18598 +          }
 1.18599 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18600 +          ptrd0+=offx;
 1.18601 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18602 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18603 +          T *ptrd = ptrd0;
 1.18604 +          const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
 1.18605 +          cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18606 +          ptrd0+=offx;
 1.18607 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18608 +        }
 1.18609 +      }
 1.18610 +      return *this;
 1.18611 +    }
 1.18612 +
 1.18613 +    //! Draw a 2D textured line, with perspective correction.
 1.18614 +    template<typename tc>
 1.18615 +    CImg<T>& draw_line(const int x0, const int y0, const float z0,
 1.18616 +                       const int x1, const int y1, const float z1,
 1.18617 +                       const CImg<tc>& texture,
 1.18618 +                       const int tx0, const int ty0,
 1.18619 +                       const int tx1, const int ty1,
 1.18620 +                       const float opacity=1,
 1.18621 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18622 +      if (is_empty() && z0<=0 && z1<=0) return *this;
 1.18623 +      if (!texture || texture.dim<dim)
 1.18624 +        throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.18625 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.18626 +      if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 1.18627 +      static unsigned int hatch = ~0U - (~0U>>1);
 1.18628 +      if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18629 +      const bool xdir = x0<x1, ydir = y0<y1;
 1.18630 +      int
 1.18631 +        nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 1.18632 +        &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 1.18633 +        &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 1.18634 +        &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 1.18635 +        &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 1.18636 +      float
 1.18637 +        Tx0 = tx0/z0, Tx1 = tx1/z1,
 1.18638 +        Ty0 = ty0/z0, Ty1 = ty1/z1,
 1.18639 +        Z0 = 1/z0, Z1 = 1/z1,
 1.18640 +        dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
 1.18641 +        tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
 1.18642 +        &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
 1.18643 +        &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 1.18644 +        &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
 1.18645 +        &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 1.18646 +      if (xright<0 || xleft>=dimx()) return *this;
 1.18647 +      if (xleft<0) {
 1.18648 +        const int D = xright - xleft;
 1.18649 +        yleft-=xleft*(yright - yleft)/D;
 1.18650 +        zleft-=xleft*(zright - zleft)/D;
 1.18651 +        txleft-=xleft*(txright - txleft)/D;
 1.18652 +        tyleft-=xleft*(tyright - tyleft)/D;
 1.18653 +        xleft = 0;
 1.18654 +      }
 1.18655 +      if (xright>=dimx()) {
 1.18656 +        const int d = xright - dimx(), D = xright - xleft;
 1.18657 +        yright-=d*(yright - yleft)/D;
 1.18658 +        zright-=d*(zright - zleft)/D;
 1.18659 +        txright-=d*(txright - txleft)/D;
 1.18660 +        tyright-=d*(tyright - tyleft)/D;
 1.18661 +        xright = dimx()-1;
 1.18662 +      }
 1.18663 +      if (ydown<0 || yup>=dimy()) return *this;
 1.18664 +      if (yup<0) {
 1.18665 +        const int D = ydown - yup;
 1.18666 +        xup-=yup*(xdown - xup)/D;
 1.18667 +        zup-=yup*(zdown - zup)/D;
 1.18668 +        txup-=yup*(txdown - txup)/D;
 1.18669 +        tyup-=yup*(tydown - tyup)/D;
 1.18670 +        yup = 0;
 1.18671 +      }
 1.18672 +      if (ydown>=dimy()) {
 1.18673 +        const int d = ydown - dimy(), D = ydown - yup;
 1.18674 +        xdown-=d*(xdown - xup)/D;
 1.18675 +        zdown-=d*(zdown - zup)/D;
 1.18676 +        txdown-=d*(txdown - txup)/D;
 1.18677 +        tydown-=d*(tydown - tyup)/D;
 1.18678 +        ydown = dimy()-1;
 1.18679 +      }
 1.18680 +      T *ptrd0 = ptr(nx0,ny0);
 1.18681 +      int dx = xright - xleft, dy = ydown - yup;
 1.18682 +      const bool steep = dy>dx;
 1.18683 +      if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 1.18684 +      const int
 1.18685 +        offx = (nx0<nx1?1:-1)*(steep?width:1),
 1.18686 +        offy = (ny0<ny1?1:-1)*(steep?1:width),
 1.18687 +        wh = width*height,
 1.18688 +        ndx = dx>0?dx:1;
 1.18689 +      if (opacity>=1) {
 1.18690 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18691 +          if (pattern&hatch) {
 1.18692 +            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18693 +            T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 1.18694 +          }
 1.18695 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18696 +          ptrd0+=offx;
 1.18697 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18698 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18699 +          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18700 +          T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 1.18701 +          ptrd0+=offx;
 1.18702 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18703 +        }
 1.18704 +      } else {
 1.18705 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18706 +        if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18707 +          if (pattern&hatch) {
 1.18708 +            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18709 +            T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18710 +          }
 1.18711 +          hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18712 +          ptrd0+=offx;
 1.18713 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18714 +        } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18715 +          const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18716 +          T *ptrd = ptrd0;
 1.18717 +          cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18718 +          ptrd0+=offx;
 1.18719 +          if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
 1.18720 +        }
 1.18721 +      }
 1.18722 +      return *this;
 1.18723 +    }
 1.18724 +
 1.18725 +    //! Draw a 2D textured line, with z-buffering and perspective correction.
 1.18726 +    template<typename tc>
 1.18727 +    CImg<T>& draw_line(float *const zbuffer,
 1.18728 +                       const int x0, const int y0, const float z0,
 1.18729 +                       const int x1, const int y1, const float z1,
 1.18730 +                       const CImg<tc>& texture,
 1.18731 +                       const int tx0, const int ty0,
 1.18732 +                       const int tx1, const int ty1,
 1.18733 +                       const float opacity=1,
 1.18734 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18735 +      if (!is_empty() && z0>0 && z1>0) {
 1.18736 +        if (!texture || texture.dim<dim)
 1.18737 +          throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.18738 +                                      pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.18739 +        if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
 1.18740 +        static unsigned int hatch = ~0U - (~0U>>1);
 1.18741 +        if (init_hatch) hatch = ~0U - (~0U>>1);
 1.18742 +        const bool xdir = x0<x1, ydir = y0<y1;
 1.18743 +        int
 1.18744 +          nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
 1.18745 +          &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
 1.18746 +          &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
 1.18747 +          &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
 1.18748 +          &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
 1.18749 +        float
 1.18750 +          Tx0 = tx0/z0, Tx1 = tx1/z1,
 1.18751 +          Ty0 = ty0/z0, Ty1 = ty1/z1,
 1.18752 +          Z0 = 1/z0, Z1 = 1/z1,
 1.18753 +          dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
 1.18754 +          tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
 1.18755 +          &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
 1.18756 +          &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
 1.18757 +          &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
 1.18758 +          &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
 1.18759 +        if (xright<0 || xleft>=dimx()) return *this;
 1.18760 +        if (xleft<0) {
 1.18761 +          const int D = xright - xleft;
 1.18762 +          yleft-=xleft*(yright - yleft)/D;
 1.18763 +          zleft-=xleft*(zright - zleft)/D;
 1.18764 +          txleft-=xleft*(txright - txleft)/D;
 1.18765 +          tyleft-=xleft*(tyright - tyleft)/D;
 1.18766 +          xleft = 0;
 1.18767 +        }
 1.18768 +        if (xright>=dimx()) {
 1.18769 +          const int d = xright - dimx(), D = xright - xleft;
 1.18770 +          yright-=d*(yright - yleft)/D;
 1.18771 +          zright-=d*(zright - zleft)/D;
 1.18772 +          txright-=d*(txright - txleft)/D;
 1.18773 +          tyright-=d*(tyright - tyleft)/D;
 1.18774 +          xright = dimx()-1;
 1.18775 +        }
 1.18776 +        if (ydown<0 || yup>=dimy()) return *this;
 1.18777 +        if (yup<0) {
 1.18778 +          const int D = ydown - yup;
 1.18779 +          xup-=yup*(xdown - xup)/D;
 1.18780 +          zup-=yup*(zdown - zup)/D;
 1.18781 +          txup-=yup*(txdown - txup)/D;
 1.18782 +          tyup-=yup*(tydown - tyup)/D;
 1.18783 +          yup = 0;
 1.18784 +        }
 1.18785 +        if (ydown>=dimy()) {
 1.18786 +          const int d = ydown - dimy(), D = ydown - yup;
 1.18787 +          xdown-=d*(xdown - xup)/D;
 1.18788 +          zdown-=d*(zdown - zup)/D;
 1.18789 +          txdown-=d*(txdown - txup)/D;
 1.18790 +          tydown-=d*(tydown - tyup)/D;
 1.18791 +          ydown = dimy()-1;
 1.18792 +        }
 1.18793 +        T *ptrd0 = ptr(nx0,ny0);
 1.18794 +        float *ptrz = zbuffer + nx0 + ny0*width;
 1.18795 +        int dx = xright - xleft, dy = ydown - yup;
 1.18796 +        const bool steep = dy>dx;
 1.18797 +        if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
 1.18798 +        const int
 1.18799 +          offx = (nx0<nx1?1:-1)*(steep?width:1),
 1.18800 +          offy = (ny0<ny1?1:-1)*(steep?1:width),
 1.18801 +          wh = width*height,
 1.18802 +          ndx = dx>0?dx:1;
 1.18803 +        if (opacity>=1) {
 1.18804 +          if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18805 +            if (pattern&hatch) {
 1.18806 +              const float z = Z0 + x*dz/ndx;
 1.18807 +              if (z>*ptrz) {
 1.18808 +                *ptrz = z;
 1.18809 +                const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18810 +                T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 1.18811 +              }
 1.18812 +            }
 1.18813 +            hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18814 +            ptrd0+=offx; ptrz+=offx;
 1.18815 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18816 +          } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18817 +            const float z = Z0 + x*dz/ndx;
 1.18818 +            if (z>*ptrz) {
 1.18819 +              *ptrz = z;
 1.18820 +              const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18821 +              T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
 1.18822 +            }
 1.18823 +            ptrd0+=offx; ptrz+=offx;
 1.18824 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18825 +          }
 1.18826 +        } else {
 1.18827 +          const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.18828 +          if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18829 +            if (pattern&hatch) {
 1.18830 +              const float z = Z0 + x*dz/ndx;
 1.18831 +              if (z>*ptrz) {
 1.18832 +                *ptrz = z;
 1.18833 +                const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18834 +                T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18835 +              }
 1.18836 +            }
 1.18837 +            hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
 1.18838 +            ptrd0+=offx; ptrz+=offx;
 1.18839 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
 1.18840 +          } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
 1.18841 +            const float z = Z0 + x*dz/ndx;
 1.18842 +            if (z>*ptrz) {
 1.18843 +              *ptrz = z;
 1.18844 +              const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
 1.18845 +              T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
 1.18846 +            }
 1.18847 +            ptrd0+=offx; ptrz+=offx;
 1.18848 +            if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
 1.18849 +          }
 1.18850 +        }
 1.18851 +      }
 1.18852 +      return *this;
 1.18853 +    }
 1.18854 +
 1.18855 +    // Inner routine for drawing set of consecutive lines with generic type for coordinates.
 1.18856 +    template<typename t, typename tc>
 1.18857 +    CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
 1.18858 +                        const tc *const color, const float opacity,
 1.18859 +                        const unsigned int pattern, const bool init_hatch) {
 1.18860 +      if (is_empty() || !points || W<2) return *this;
 1.18861 +      bool ninit_hatch = init_hatch;
 1.18862 +      switch (H) {
 1.18863 +      case 0 : case 1 :
 1.18864 +        throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
 1.18865 +                                    pixel_type());
 1.18866 +      case 2 : {
 1.18867 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 1.18868 +        int ox = x0, oy = y0;
 1.18869 +        for (unsigned int i = 1; i<W; ++i) {
 1.18870 +          const int x = (int)points(i,0), y = (int)points(i,1);
 1.18871 +          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
 1.18872 +          ninit_hatch = false;
 1.18873 +          ox = x; oy = y;
 1.18874 +        }
 1.18875 +      } break;
 1.18876 +      default : {
 1.18877 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 1.18878 +        int ox = x0, oy = y0, oz = z0;
 1.18879 +        for (unsigned int i = 1; i<W; ++i) {
 1.18880 +          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 1.18881 +          draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
 1.18882 +          ninit_hatch = false;
 1.18883 +          ox = x; oy = y; oz = z;
 1.18884 +        }
 1.18885 +      }
 1.18886 +      }
 1.18887 +      return *this;
 1.18888 +    }
 1.18889 +
 1.18890 +    //! Draw a set of consecutive colored lines in the instance image.
 1.18891 +    /**
 1.18892 +       \param points Coordinates of vertices, stored as a list of vectors.
 1.18893 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.18894 +       \param opacity Drawing opacity (optional).
 1.18895 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.18896 +       \param init_hatch If set to true, init hatch motif.
 1.18897 +       \note
 1.18898 +       - This function uses several call to the single CImg::draw_line() procedure,
 1.18899 +       depending on the vectors size in \p points.
 1.18900 +       \par Example:
 1.18901 +       \code
 1.18902 +       CImg<unsigned char> img(100,100,1,3,0);
 1.18903 +       const unsigned char color[] = { 255,128,64 };
 1.18904 +       CImgList<int> points;
 1.18905 +       points.insert(CImg<int>::vector(0,0)).
 1.18906 +             .insert(CImg<int>::vector(70,10)).
 1.18907 +             .insert(CImg<int>::vector(80,60)).
 1.18908 +             .insert(CImg<int>::vector(10,90));
 1.18909 +       img.draw_line(points,color);
 1.18910 +       \endcode
 1.18911 +    **/
 1.18912 +    template<typename t, typename tc>
 1.18913 +    CImg<T>& draw_line(const CImgList<t>& points,
 1.18914 +                       const tc *const color, const float opacity=1,
 1.18915 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18916 +      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 1.18917 +      return _draw_line(points,points.size,H,color,opacity,pattern,init_hatch);
 1.18918 +    }
 1.18919 +
 1.18920 +    //! Draw a set of consecutive colored lines in the instance image.
 1.18921 +    template<typename t, typename tc>
 1.18922 +    CImg<T>& draw_line(const CImgList<t>& points,
 1.18923 +                       const CImg<tc>& color, const float opacity=1,
 1.18924 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18925 +      return draw_line(points,color.data,opacity,pattern,init_hatch);
 1.18926 +    }
 1.18927 +
 1.18928 +    //! Draw a set of consecutive colored lines in the instance image.
 1.18929 +    /**
 1.18930 +       \note
 1.18931 +       - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
 1.18932 +       (sequence of vectors aligned along the x-axis).
 1.18933 +    **/
 1.18934 +    template<typename t, typename tc>
 1.18935 +    CImg<T>& draw_line(const CImg<t>& points,
 1.18936 +                       const tc *const color, const float opacity=1,
 1.18937 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18938 +      return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
 1.18939 +    }
 1.18940 +
 1.18941 +    //! Draw a set of consecutive colored lines in the instance image.
 1.18942 +    template<typename t, typename tc>
 1.18943 +    CImg<T>& draw_line(const CImg<t>& points,
 1.18944 +                       const CImg<tc>& color, const float opacity=1,
 1.18945 +                       const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.18946 +      return draw_line(points,color.data,opacity,pattern,init_hatch);
 1.18947 +    }
 1.18948 +
 1.18949 +    // Inner routine for a drawing filled polygon with generic type for coordinates.
 1.18950 +    template<typename t, typename tc>
 1.18951 +    CImg<T>& _draw_polygon(const t& points, const unsigned int N,
 1.18952 +                           const tc *const color, const float opacity) {
 1.18953 +      if (is_empty() || !points || N<3) return *this;
 1.18954 +      if (!color)
 1.18955 +        throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
 1.18956 +                                    pixel_type());
 1.18957 +      _draw_scanline(color,opacity);
 1.18958 +      int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
 1.18959 +      { for (unsigned int p = 0; p<N; ++p) {
 1.18960 +        const int x = (int)points(p,0), y = (int)points(p,1);
 1.18961 +        if (x<xmin) xmin = x;
 1.18962 +        if (x>xmax) xmax = x;
 1.18963 +        if (y<ymin) ymin = y;
 1.18964 +        if (y>ymax) ymax = y;
 1.18965 +      }}
 1.18966 +      if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
 1.18967 +      const unsigned int
 1.18968 +        nymin = ymin<0?0:(unsigned int)ymin,
 1.18969 +        nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
 1.18970 +        dy = 1 + nymax - nymin;
 1.18971 +      CImg<intT> X(1+2*N,dy,1,1,0), tmp;
 1.18972 +      int cx = (int)points(0,0), cy = (int)points(0,1);
 1.18973 +      for (unsigned int cp = 0, p = 0; p<N; ++p) {
 1.18974 +        const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
 1.18975 +        const int
 1.18976 +          nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
 1.18977 +          y0 = cy - nymin, y1 = ny - nymin;
 1.18978 +        if (y0!=y1) {
 1.18979 +          const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
 1.18980 +          for (int x = cx, y = y0, _sx = 1, _sy = 1,
 1.18981 +                 _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
 1.18982 +                 _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
 1.18983 +                 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
 1.18984 +                 _err = _dx>>1,
 1.18985 +                 _rx = _dy?(nx-cx)/_dy:0;
 1.18986 +               _counter>=countermin;
 1.18987 +               --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
 1.18988 +            if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
 1.18989 +          cp = np; cx = nx; cy = ny;
 1.18990 +        } else {
 1.18991 +          const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
 1.18992 +          if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
 1.18993 +          if (cy!=ay) { cp = np; cx = nx; cy = ny; }
 1.18994 +        }
 1.18995 +      }
 1.18996 +      for (int y = 0; y<(int)dy; ++y) {
 1.18997 +        tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
 1.18998 +        for (int i = 1; i<=X(0,y); ) {
 1.18999 +          const int xb = X(i++,y), xe = X(i++,y);
 1.19000 +          _draw_scanline(xb,xe,nymin+y,color,opacity);
 1.19001 +        }
 1.19002 +      }
 1.19003 +      return *this;
 1.19004 +    }
 1.19005 +
 1.19006 +    //! Draw a filled polygon in the instance image.
 1.19007 +    template<typename t, typename tc>
 1.19008 +    CImg<T>& draw_polygon(const CImgList<t>& points,
 1.19009 +                          const tc *const color, const float opacity=1) {
 1.19010 +      if (!points.is_sameY(2))
 1.19011 +        throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 1.19012 +                                    pixel_type());
 1.19013 +      return _draw_polygon(points,points.size,color,opacity);
 1.19014 +    }
 1.19015 +
 1.19016 +    //! Draw a filled polygon in the instance image.
 1.19017 +    template<typename t, typename tc>
 1.19018 +    CImg<T>& draw_polygon(const CImgList<t>& points,
 1.19019 +                          const CImg<tc>& color, const float opacity=1) {
 1.19020 +      return draw_polygon(points,color.data,opacity);
 1.19021 +    }
 1.19022 +
 1.19023 +    //! Draw a filled polygon in the instance image.
 1.19024 +    template<typename t, typename tc>
 1.19025 +    CImg<T>& draw_polygon(const CImg<t>& points,
 1.19026 +                          const tc *const color, const float opacity=1) {
 1.19027 +      if (points.height<2)
 1.19028 +        throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 1.19029 +                                    pixel_type());
 1.19030 +      return _draw_polygon(points,points.width,color,opacity);
 1.19031 +    }
 1.19032 +
 1.19033 +    //! Draw a filled polygon in the instance image.
 1.19034 +    template<typename t, typename tc>
 1.19035 +    CImg<T>& draw_polygon(const CImg<t>& points,
 1.19036 +                          const CImg<tc>& color, const float opacity=1) {
 1.19037 +      return draw_polygon(points,color.data,opacity);
 1.19038 +    }
 1.19039 +
 1.19040 +    // Inner routine for drawing an outlined polygon with generic point coordinates.
 1.19041 +    template<typename t, typename tc>
 1.19042 +    CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
 1.19043 +                           const tc *const color, const float opacity,
 1.19044 +                           const unsigned int pattern) {
 1.19045 +      if (is_empty() || !points || W<3) return *this;
 1.19046 +      bool ninit_hatch = true;
 1.19047 +      switch (H) {
 1.19048 +      case 0 : case 1 :
 1.19049 +        throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
 1.19050 +                                    pixel_type());
 1.19051 +      case 2 : {
 1.19052 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 1.19053 +        int ox = x0, oy = y0;
 1.19054 +        for (unsigned int i = 1; i<W; ++i) {
 1.19055 +          const int x = (int)points(i,0), y = (int)points(i,1);
 1.19056 +          draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
 1.19057 +          ninit_hatch = false;
 1.19058 +          ox = x; oy = y;
 1.19059 +        }
 1.19060 +        draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
 1.19061 +      } break;
 1.19062 +      default : {
 1.19063 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 1.19064 +        int ox = x0, oy = y0, oz = z0;
 1.19065 +        for (unsigned int i = 1; i<W; ++i) {
 1.19066 +          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 1.19067 +          draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
 1.19068 +          ninit_hatch = false;
 1.19069 +          ox = x; oy = y; oz = z;
 1.19070 +        }
 1.19071 +        draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
 1.19072 +      }
 1.19073 +      }
 1.19074 +      return *this;
 1.19075 +    }
 1.19076 +
 1.19077 +    //! Draw a polygon outline.
 1.19078 +    template<typename t, typename tc>
 1.19079 +    CImg<T>& draw_polygon(const CImgList<t>& points,
 1.19080 +                          const tc *const color, const float opacity,
 1.19081 +                          const unsigned int pattern) {
 1.19082 +      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 1.19083 +      return _draw_polygon(points,points.size,H,color,opacity,pattern);
 1.19084 +    }
 1.19085 +
 1.19086 +    //! Draw a polygon outline.
 1.19087 +    template<typename t, typename tc>
 1.19088 +    CImg<T>& draw_polygon(const CImgList<t>& points,
 1.19089 +                          const CImg<tc>& color, const float opacity,
 1.19090 +                          const unsigned int pattern) {
 1.19091 +      return draw_polygon(points,color.data,opacity,pattern);
 1.19092 +    }
 1.19093 +
 1.19094 +    //! Draw a polygon outline.
 1.19095 +    template<typename t, typename tc>
 1.19096 +    CImg<T>& draw_polygon(const CImg<t>& points,
 1.19097 +                          const tc *const color, const float opacity,
 1.19098 +                          const unsigned int pattern) {
 1.19099 +      return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
 1.19100 +    }
 1.19101 +
 1.19102 +    //! Draw a polygon outline.
 1.19103 +    template<typename t, typename tc>
 1.19104 +    CImg<T>& draw_polygon(const CImg<t>& points,
 1.19105 +                          const CImg<tc>& color, const float opacity,
 1.19106 +                          const unsigned int pattern) {
 1.19107 +      return draw_polygon(points,color.data,opacity,pattern);
 1.19108 +    }
 1.19109 +
 1.19110 +    //! Draw a cubic spline curve in the instance image.
 1.19111 +    /**
 1.19112 +       \param x0 X-coordinate of the starting curve point
 1.19113 +       \param y0 Y-coordinate of the starting curve point
 1.19114 +       \param u0 X-coordinate of the starting velocity
 1.19115 +       \param v0 Y-coordinate of the starting velocity
 1.19116 +       \param x1 X-coordinate of the ending curve point
 1.19117 +       \param y1 Y-coordinate of the ending curve point
 1.19118 +       \param u1 X-coordinate of the ending velocity
 1.19119 +       \param v1 Y-coordinate of the ending velocity
 1.19120 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.19121 +       \param precision Curve drawing precision (optional).
 1.19122 +       \param opacity Drawing opacity (optional).
 1.19123 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.19124 +       \param init_hatch If \c true, init hatch motif.
 1.19125 +       \note
 1.19126 +       - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
 1.19127 +       and corresponding velocity vectors.
 1.19128 +       - The spline is drawn as a serie of connected segments. The \p precision parameter sets the
 1.19129 +       average number of pixels in each drawn segment.
 1.19130 +       - 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) }
 1.19131 +       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
 1.19132 +       \e control points.
 1.19133 +       The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as
 1.19134 +       \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).
 1.19135 +       \par Example:
 1.19136 +       \code
 1.19137 +       CImg<unsigned char> img(100,100,1,3,0);
 1.19138 +       const unsigned char color[] = { 255,255,255 };
 1.19139 +       img.draw_spline(30,30,0,100,90,40,0,-100,color);
 1.19140 +       \endcode
 1.19141 +    **/
 1.19142 +    template<typename tc>
 1.19143 +    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 1.19144 +                         const int x1, const int y1, const float u1, const float v1,
 1.19145 +                         const tc *const color, const float opacity=1,
 1.19146 +                         const float precision=4, const unsigned int pattern=~0U,
 1.19147 +                         const bool init_hatch=true) {
 1.19148 +      if (is_empty()) return *this;
 1.19149 +      if (!color)
 1.19150 +        throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
 1.19151 +                                    pixel_type());
 1.19152 +      bool ninit_hatch = init_hatch;
 1.19153 +      const float
 1.19154 +        dx = (float)(x1 - x0),
 1.19155 +        dy = (float)(y1 - y0),
 1.19156 +        dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
 1.19157 +        ax = -2*dx + u0 + u1,
 1.19158 +        bx = 3*dx - 2*u0 - u1,
 1.19159 +        ay = -2*dy + v0 + v1,
 1.19160 +        by = 3*dy - 2*v0 - v1,
 1.19161 +        xprecision = dmax>0?precision/dmax:1.0f,
 1.19162 +        tmax = 1 + (dmax>0?xprecision:0.0f);
 1.19163 +      int ox = x0, oy = y0;
 1.19164 +      for (float t = 0; t<tmax; t+=xprecision) {
 1.19165 +        const float
 1.19166 +          t2 = t*t,
 1.19167 +          t3 = t2*t;
 1.19168 +        const int
 1.19169 +          nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
 1.19170 +          ny = (int)(ay*t3 + by*t2 + v0*t + y0);
 1.19171 +        draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
 1.19172 +        ninit_hatch = false;
 1.19173 +        ox = nx; oy = ny;
 1.19174 +      }
 1.19175 +      return *this;
 1.19176 +    }
 1.19177 +
 1.19178 +    //! Draw a cubic spline curve in the instance image.
 1.19179 +    template<typename tc>
 1.19180 +    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 1.19181 +                         const int x1, const int y1, const float u1, const float v1,
 1.19182 +                         const CImg<tc>& color, const float opacity=1,
 1.19183 +                         const float precision=4, const unsigned int pattern=~0U,
 1.19184 +                         const bool init_hatch=true) {
 1.19185 +      return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
 1.19186 +    }
 1.19187 +
 1.19188 +    //! Draw a cubic spline curve in the instance image (for volumetric images).
 1.19189 +    /**
 1.19190 +       \note
 1.19191 +       - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
 1.19192 +    **/
 1.19193 +    template<typename tc>
 1.19194 +    CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 1.19195 +                         const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 1.19196 +                         const tc *const color, const float opacity=1,
 1.19197 +                         const float precision=4, const unsigned int pattern=~0U,
 1.19198 +                         const bool init_hatch=true) {
 1.19199 +      if (is_empty()) return *this;
 1.19200 +      if (!color)
 1.19201 +        throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
 1.19202 +                                    pixel_type());
 1.19203 +      bool ninit_hatch = init_hatch;
 1.19204 +      const float
 1.19205 +        dx = (float)(x1 - x0),
 1.19206 +        dy = (float)(y1 - y0),
 1.19207 +        dz = (float)(z1 - z0),
 1.19208 +        dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
 1.19209 +        ax = -2*dx + u0 + u1,
 1.19210 +        bx = 3*dx - 2*u0 - u1,
 1.19211 +        ay = -2*dy + v0 + v1,
 1.19212 +        by = 3*dy - 2*v0 - v1,
 1.19213 +        az = -2*dz + w0 + w1,
 1.19214 +        bz = 3*dz - 2*w0 - w1,
 1.19215 +        xprecision = dmax>0?precision/dmax:1.0f,
 1.19216 +        tmax = 1 + (dmax>0?xprecision:0.0f);
 1.19217 +      int ox = x0, oy = y0, oz = z0;
 1.19218 +      for (float t = 0; t<tmax; t+=xprecision) {
 1.19219 +        const float
 1.19220 +          t2 = t*t,
 1.19221 +          t3 = t2*t;
 1.19222 +        const int
 1.19223 +          nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
 1.19224 +          ny = (int)(ay*t3 + by*t2 + v0*t + y0),
 1.19225 +          nz = (int)(az*t3 + bz*t2 + w0*t + z0);
 1.19226 +        draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
 1.19227 +        ninit_hatch = false;
 1.19228 +        ox = nx; oy = ny; oz = nz;
 1.19229 +      }
 1.19230 +      return *this;
 1.19231 +    }
 1.19232 +
 1.19233 +    //! Draw a cubic spline curve in the instance image (for volumetric images).
 1.19234 +    template<typename tc>
 1.19235 +    CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 1.19236 +                         const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 1.19237 +                         const CImg<tc>& color, const float opacity=1,
 1.19238 +                         const float precision=4, const unsigned int pattern=~0U,
 1.19239 +                         const bool init_hatch=true) {
 1.19240 +      return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
 1.19241 +    }
 1.19242 +
 1.19243 +    //! Draw a cubic spline curve in the instance image.
 1.19244 +    /**
 1.19245 +       \param x0 X-coordinate of the starting curve point
 1.19246 +       \param y0 Y-coordinate of the starting curve point
 1.19247 +       \param u0 X-coordinate of the starting velocity
 1.19248 +       \param v0 Y-coordinate of the starting velocity
 1.19249 +       \param x1 X-coordinate of the ending curve point
 1.19250 +       \param y1 Y-coordinate of the ending curve point
 1.19251 +       \param u1 X-coordinate of the ending velocity
 1.19252 +       \param v1 Y-coordinate of the ending velocity
 1.19253 +       \param texture Texture image defining line pixel colors.
 1.19254 +       \param tx0 X-coordinate of the starting texture point.
 1.19255 +       \param ty0 Y-coordinate of the starting texture point.
 1.19256 +       \param tx1 X-coordinate of the ending texture point.
 1.19257 +       \param ty1 Y-coordinate of the ending texture point.
 1.19258 +       \param precision Curve drawing precision (optional).
 1.19259 +       \param opacity Drawing opacity (optional).
 1.19260 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.19261 +       \param init_hatch if \c true, reinit hatch motif.
 1.19262 +    **/
 1.19263 +    template<typename t>
 1.19264 +    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 1.19265 +                         const int x1, const int y1, const float u1, const float v1,
 1.19266 +                         const CImg<t>& texture,
 1.19267 +                         const int tx0, const int ty0, const int tx1, const int ty1,
 1.19268 +                         const float opacity=1,
 1.19269 +                         const float precision=4, const unsigned int pattern=~0U,
 1.19270 +                         const bool init_hatch=true) {
 1.19271 +      if (is_empty()) return *this;
 1.19272 +      if (!texture || texture.dim<dim)
 1.19273 +        throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.19274 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.19275 +      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);
 1.19276 +      bool ninit_hatch = true;
 1.19277 +      const float
 1.19278 +        dx = (float)(x1 - x0),
 1.19279 +        dy = (float)(y1 - y0),
 1.19280 +        dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
 1.19281 +        ax = -2*dx + u0 + u1,
 1.19282 +        bx = 3*dx - 2*u0 - u1,
 1.19283 +        ay = -2*dy + v0 + v1,
 1.19284 +        by = 3*dy - 2*v0 - v1,
 1.19285 +        xprecision = dmax>0?precision/dmax:1.0f,
 1.19286 +        tmax = 1 + (dmax>0?xprecision:0.0f);
 1.19287 +      int ox = x0, oy = y0, otx = tx0, oty = ty0;
 1.19288 +      for (float t1 = 0; t1<tmax; t1+=xprecision) {
 1.19289 +        const float
 1.19290 +          t2 = t1*t1,
 1.19291 +          t3 = t2*t1;
 1.19292 +        const int
 1.19293 +          nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
 1.19294 +          ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
 1.19295 +          ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
 1.19296 +          nty = ty0 + (int)((ty1-ty0)*t1/tmax);
 1.19297 +        draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
 1.19298 +        ninit_hatch = false;
 1.19299 +        ox = nx; oy = ny; otx = ntx; oty = nty;
 1.19300 +      }
 1.19301 +      return *this;
 1.19302 +    }
 1.19303 +
 1.19304 +    // Draw a set of connected spline curves in the instance image (internal).
 1.19305 +    template<typename tp, typename tt, typename tc>
 1.19306 +    CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
 1.19307 +                          const tc *const color, const float opacity,
 1.19308 +                          const bool close_set, const float precision,
 1.19309 +                          const unsigned int pattern, const bool init_hatch) {
 1.19310 +      if (is_empty() || !points || !tangents || W<2) return *this;
 1.19311 +      bool ninit_hatch = init_hatch;
 1.19312 +      switch (H) {
 1.19313 +      case 0 : case 1 :
 1.19314 +        throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
 1.19315 +                                    pixel_type());
 1.19316 +      case 2 : {
 1.19317 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1);
 1.19318 +        const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
 1.19319 +        int ox = x0, oy = y0;
 1.19320 +        float ou = u0, ov = v0;
 1.19321 +        for (unsigned int i = 1; i<W; ++i) {
 1.19322 +          const int x = (int)points(i,0), y = (int)points(i,1);
 1.19323 +          const float u = (float)tangents(i,0), v = (float)tangents(i,1);
 1.19324 +          draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
 1.19325 +          ninit_hatch = false;
 1.19326 +          ox = x; oy = y; ou = u; ov = v;
 1.19327 +        }
 1.19328 +        if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
 1.19329 +      } break;
 1.19330 +      default : {
 1.19331 +        const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
 1.19332 +        const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
 1.19333 +        int ox = x0, oy = y0, oz = z0;
 1.19334 +        float ou = u0, ov = v0, ow = w0;
 1.19335 +        for (unsigned int i = 1; i<W; ++i) {
 1.19336 +          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 1.19337 +          const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
 1.19338 +          draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
 1.19339 +          ninit_hatch = false;
 1.19340 +          ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
 1.19341 +        }
 1.19342 +        if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
 1.19343 +      }
 1.19344 +      }
 1.19345 +      return *this;
 1.19346 +    }
 1.19347 +
 1.19348 +    // Draw a set of connected spline curves in the instance image (internal).
 1.19349 +    template<typename tp, typename tc>
 1.19350 +    CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
 1.19351 +                          const tc *const color, const float opacity,
 1.19352 +                          const bool close_set, const float precision,
 1.19353 +                          const unsigned int pattern, const bool init_hatch) {
 1.19354 +      if (is_empty() || !points || W<2) return *this;
 1.19355 +      CImg<Tfloat> tangents;
 1.19356 +      switch (H) {
 1.19357 +      case 0 : case 1 :
 1.19358 +        throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
 1.19359 +                                    pixel_type());
 1.19360 +      case 2 : {
 1.19361 +        tangents.assign(W,H);
 1.19362 +        for (unsigned int p = 0; p<W; ++p) {
 1.19363 +          const unsigned int
 1.19364 +            p0 = close_set?(p+W-1)%W:(p?p-1:0),
 1.19365 +            p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
 1.19366 +          const float
 1.19367 +            x = (float)points(p,0),
 1.19368 +            y = (float)points(p,1),
 1.19369 +            x0 = (float)points(p0,0),
 1.19370 +            y0 = (float)points(p0,1),
 1.19371 +            x1 = (float)points(p1,0),
 1.19372 +            y1 = (float)points(p1,1),
 1.19373 +            u0 = x - x0,
 1.19374 +            v0 = y - y0,
 1.19375 +            n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0),
 1.19376 +            u1 = x1 - x,
 1.19377 +            v1 = y1 - y,
 1.19378 +            n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1),
 1.19379 +            u = u0/n0 + u1/n1,
 1.19380 +            v = v0/n0 + v1/n1,
 1.19381 +            n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v),
 1.19382 +            fact = 0.5f*(n0 + n1);
 1.19383 +          tangents(p,0) = (Tfloat)(fact*u/n);
 1.19384 +          tangents(p,1) = (Tfloat)(fact*v/n);
 1.19385 +        }
 1.19386 +      } break;
 1.19387 +      default : {
 1.19388 +        tangents.assign(W,H);
 1.19389 +        for (unsigned int p = 0; p<W; ++p) {
 1.19390 +          const unsigned int
 1.19391 +            p0 = close_set?(p+W-1)%W:(p?p-1:0),
 1.19392 +            p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
 1.19393 +          const float
 1.19394 +            x = (float)points(p,0),
 1.19395 +            y = (float)points(p,1),
 1.19396 +            z = (float)points(p,2),
 1.19397 +            x0 = (float)points(p0,0),
 1.19398 +            y0 = (float)points(p0,1),
 1.19399 +            z0 = (float)points(p0,2),
 1.19400 +            x1 = (float)points(p1,0),
 1.19401 +            y1 = (float)points(p1,1),
 1.19402 +            z1 = (float)points(p1,2),
 1.19403 +            u0 = x - x0,
 1.19404 +            v0 = y - y0,
 1.19405 +            w0 = z - z0,
 1.19406 +            n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0 + w0*w0),
 1.19407 +            u1 = x1 - x,
 1.19408 +            v1 = y1 - y,
 1.19409 +            w1 = z1 - z,
 1.19410 +            n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1 + w1*w1),
 1.19411 +            u = u0/n0 + u1/n1,
 1.19412 +            v = v0/n0 + v1/n1,
 1.19413 +            w = w0/n0 + w1/n1,
 1.19414 +            n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v + w*w),
 1.19415 +            fact = 0.5f*(n0 + n1);
 1.19416 +          tangents(p,0) = (Tfloat)(fact*u/n);
 1.19417 +          tangents(p,1) = (Tfloat)(fact*v/n);
 1.19418 +          tangents(p,2) = (Tfloat)(fact*w/n);
 1.19419 +        }
 1.19420 +      }
 1.19421 +      }
 1.19422 +      return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
 1.19423 +    }
 1.19424 +
 1.19425 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19426 +    template<typename tp, typename tt, typename tc>
 1.19427 +    CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 1.19428 +                         const tc *const color, const float opacity=1,
 1.19429 +                         const bool close_set=false, const float precision=4,
 1.19430 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19431 +      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
 1.19432 +      return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
 1.19433 +    }
 1.19434 +
 1.19435 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19436 +    template<typename tp, typename tt, typename tc>
 1.19437 +    CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 1.19438 +                         const CImg<tc>& color, const float opacity=1,
 1.19439 +                         const bool close_set=false, const float precision=4,
 1.19440 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19441 +      return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
 1.19442 +    }
 1.19443 +
 1.19444 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19445 +    template<typename tp, typename tt, typename tc>
 1.19446 +    CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 1.19447 +                         const tc *const color, const float opacity=1,
 1.19448 +                         const bool close_set=false, const float precision=4,
 1.19449 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19450 +      return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
 1.19451 +    }
 1.19452 +
 1.19453 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19454 +    template<typename tp, typename tt, typename tc>
 1.19455 +    CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 1.19456 +                         const CImg<tc>& color, const float opacity=1,
 1.19457 +                         const bool close_set=false, const float precision=4,
 1.19458 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19459 +      return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
 1.19460 +    }
 1.19461 +
 1.19462 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19463 +    template<typename t, typename tc>
 1.19464 +    CImg<T>& draw_spline(const CImgList<t>& points,
 1.19465 +                         const tc *const color, const float opacity=1,
 1.19466 +                         const bool close_set=false, const float precision=4,
 1.19467 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19468 +      unsigned int H = ~0U;
 1.19469 +      cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
 1.19470 +      return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
 1.19471 +    }
 1.19472 +
 1.19473 +    //! Draw a set of consecutive colored splines in the instance image.
 1.19474 +    template<typename t, typename tc>
 1.19475 +    CImg<T>& draw_spline(const CImgList<t>& points,
 1.19476 +                         CImg<tc>& color, const float opacity=1,
 1.19477 +                         const bool close_set=false, const float precision=4,
 1.19478 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19479 +      return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
 1.19480 +    }
 1.19481 +
 1.19482 +    //! Draw a set of consecutive colored lines in the instance image.
 1.19483 +    template<typename t, typename tc>
 1.19484 +    CImg<T>& draw_spline(const CImg<t>& points,
 1.19485 +                         const tc *const color, const float opacity=1,
 1.19486 +                         const bool close_set=false, const float precision=4,
 1.19487 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19488 +      return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
 1.19489 +    }
 1.19490 +
 1.19491 +    //! Draw a set of consecutive colored lines in the instance image.
 1.19492 +    template<typename t, typename tc>
 1.19493 +    CImg<T>& draw_spline(const CImg<t>& points,
 1.19494 +                         const CImg<tc>& color, const float opacity=1,
 1.19495 +                         const bool close_set=false, const float precision=4,
 1.19496 +                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 1.19497 +      return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
 1.19498 +    }
 1.19499 +
 1.19500 +    //! Draw a colored arrow in the instance image.
 1.19501 +    /**
 1.19502 +       \param x0 X-coordinate of the starting arrow point (tail).
 1.19503 +       \param y0 Y-coordinate of the starting arrow point (tail).
 1.19504 +       \param x1 X-coordinate of the ending arrow point (head).
 1.19505 +       \param y1 Y-coordinate of the ending arrow point (head).
 1.19506 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.19507 +       \param angle Aperture angle of the arrow head (optional).
 1.19508 +       \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional).
 1.19509 +       \param opacity Drawing opacity (optional).
 1.19510 +       \param pattern An integer whose bits describe the line pattern (optional).
 1.19511 +       \note
 1.19512 +       - Clipping is supported.
 1.19513 +    **/
 1.19514 +    template<typename tc>
 1.19515 +    CImg<T>& draw_arrow(const int x0, const int y0,
 1.19516 +                        const int x1, const int y1,
 1.19517 +                        const tc *const color, const float opacity=1,
 1.19518 +                        const float angle=30, const float length=-10,
 1.19519 +                        const unsigned int pattern=~0U) {
 1.19520 +      if (is_empty()) return *this;
 1.19521 +      const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
 1.19522 +        deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)cimg_std::atan2(v,u):0.0f,
 1.19523 +        l = (length>=0)?length:-length*(float)cimg_std::sqrt(sq)/100;
 1.19524 +      if (sq>0) {
 1.19525 +        const float
 1.19526 +            cl = (float)cimg_std::cos(ang - deg), sl = (float)cimg_std::sin(ang - deg),
 1.19527 +            cr = (float)cimg_std::cos(ang + deg), sr = (float)cimg_std::sin(ang + deg);
 1.19528 +        const int
 1.19529 +          xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
 1.19530 +          xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
 1.19531 +          xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
 1.19532 +        draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
 1.19533 +      } else draw_point(x0,y0,color,opacity);
 1.19534 +      return *this;
 1.19535 +    }
 1.19536 +
 1.19537 +    //! Draw a colored arrow in the instance image.
 1.19538 +    template<typename tc>
 1.19539 +    CImg<T>& draw_arrow(const int x0, const int y0,
 1.19540 +                        const int x1, const int y1,
 1.19541 +                        const CImg<tc>& color, const float opacity=1,
 1.19542 +                        const float angle=30, const float length=-10,
 1.19543 +                        const unsigned int pattern=~0U) {
 1.19544 +      return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
 1.19545 +    }
 1.19546 +
 1.19547 +    //! Draw an image.
 1.19548 +    /**
 1.19549 +       \param sprite Sprite image.
 1.19550 +       \param x0 X-coordinate of the sprite position.
 1.19551 +       \param y0 Y-coordinate of the sprite position.
 1.19552 +       \param z0 Z-coordinate of the sprite position.
 1.19553 +       \param v0 V-coordinate of the sprite position.
 1.19554 +       \param opacity Drawing opacity (optional).
 1.19555 +       \note
 1.19556 +       - Clipping is supported.
 1.19557 +    **/
 1.19558 +    template<typename t>
 1.19559 +    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 1.19560 +                        const CImg<t>& sprite, const float opacity=1) {
 1.19561 +      if (is_empty()) return *this;
 1.19562 +      if (!sprite)
 1.19563 +        throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 1.19564 +                                    pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 1.19565 +      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
 1.19566 +      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 1.19567 +      const int
 1.19568 +        lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 1.19569 +        lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 1.19570 +        lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 1.19571 +        lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 1.19572 +      const t
 1.19573 +        *ptrs = sprite.data -
 1.19574 +        (bx?x0:0) -
 1.19575 +        (by?y0*sprite.dimx():0) -
 1.19576 +        (bz?z0*sprite.dimx()*sprite.dimy():0) -
 1.19577 +        (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
 1.19578 +      const unsigned int
 1.19579 +        offX = width - lX,                soffX = sprite.width - lX,
 1.19580 +        offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 1.19581 +        offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
 1.19582 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.19583 +      if (lX>0 && lY>0 && lZ>0 && lV>0) {
 1.19584 +        T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 1.19585 +        for (int v = 0; v<lV; ++v) {
 1.19586 +          for (int z = 0; z<lZ; ++z) {
 1.19587 +            for (int y = 0; y<lY; ++y) {
 1.19588 +              if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
 1.19589 +              else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
 1.19590 +              ptrd+=offX; ptrs+=soffX;
 1.19591 +            }
 1.19592 +            ptrd+=offY; ptrs+=soffY;
 1.19593 +          }
 1.19594 +          ptrd+=offZ; ptrs+=soffZ;
 1.19595 +        }
 1.19596 +      }
 1.19597 +      return *this;
 1.19598 +    }
 1.19599 +
 1.19600 +#ifndef cimg_use_visualcpp6
 1.19601 +    // Otimized version (internal).
 1.19602 +    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 1.19603 +                        const CImg<T>& sprite, const float opacity=1) {
 1.19604 +      if (is_empty()) return *this;
 1.19605 +      if (!sprite)
 1.19606 +        throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 1.19607 +                                    pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 1.19608 +      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
 1.19609 +      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 1.19610 +      const int
 1.19611 +        lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 1.19612 +        lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 1.19613 +        lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 1.19614 +        lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 1.19615 +      const T
 1.19616 +        *ptrs = sprite.data -
 1.19617 +        (bx?x0:0) -
 1.19618 +        (by?y0*sprite.dimx():0) -
 1.19619 +        (bz?z0*sprite.dimx()*sprite.dimy():0) -
 1.19620 +        (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
 1.19621 +      const unsigned int
 1.19622 +        offX = width - lX,                soffX = sprite.width - lX,
 1.19623 +        offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 1.19624 +        offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
 1.19625 +        slX = lX*sizeof(T);
 1.19626 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.19627 +      if (lX>0 && lY>0 && lZ>0 && lV>0) {
 1.19628 +        T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 1.19629 +        for (int v = 0; v<lV; ++v) {
 1.19630 +          for (int z = 0; z<lZ; ++z) {
 1.19631 +            if (opacity>=1) for (int y = 0; y<lY; ++y) { cimg_std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
 1.19632 +            else for (int y = 0; y<lY; ++y) {
 1.19633 +              for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
 1.19634 +              ptrd+=offX; ptrs+=soffX;
 1.19635 +            }
 1.19636 +            ptrd+=offY; ptrs+=soffY;
 1.19637 +          }
 1.19638 +          ptrd+=offZ; ptrs+=soffZ;
 1.19639 +        }
 1.19640 +      }
 1.19641 +      return *this;
 1.19642 +    }
 1.19643 +#endif
 1.19644 +
 1.19645 +    //! Draw an image.
 1.19646 +    template<typename t>
 1.19647 +    CImg<T>& draw_image(const int x0, const int y0, const int z0,
 1.19648 +                        const CImg<t>& sprite, const float opacity=1) {
 1.19649 +      return draw_image(x0,y0,z0,0,sprite,opacity);
 1.19650 +    }
 1.19651 +
 1.19652 +    //! Draw an image.
 1.19653 +    template<typename t>
 1.19654 +    CImg<T>& draw_image(const int x0, const int y0,
 1.19655 +                        const CImg<t>& sprite, const float opacity=1) {
 1.19656 +      return draw_image(x0,y0,0,sprite,opacity);
 1.19657 +    }
 1.19658 +
 1.19659 +    //! Draw an image.
 1.19660 +    template<typename t>
 1.19661 +    CImg<T>& draw_image(const int x0,
 1.19662 +                        const CImg<t>& sprite, const float opacity=1) {
 1.19663 +      return draw_image(x0,0,sprite,opacity);
 1.19664 +    }
 1.19665 +
 1.19666 +    //! Draw an image.
 1.19667 +    template<typename t>
 1.19668 +    CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
 1.19669 +      return draw_image(0,sprite,opacity);
 1.19670 +    }
 1.19671 +
 1.19672 +    //! Draw a sprite image in the instance image (masked version).
 1.19673 +    /**
 1.19674 +       \param sprite Sprite image.
 1.19675 +       \param mask Mask image.
 1.19676 +       \param x0 X-coordinate of the sprite position in the instance image.
 1.19677 +       \param y0 Y-coordinate of the sprite position in the instance image.
 1.19678 +       \param z0 Z-coordinate of the sprite position in the instance image.
 1.19679 +       \param v0 V-coordinate of the sprite position in the instance image.
 1.19680 +       \param mask_valmax Maximum pixel value of the mask image \c mask (optional).
 1.19681 +       \param opacity Drawing opacity.
 1.19682 +       \note
 1.19683 +       - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
 1.19684 +       - Clipping is supported.
 1.19685 +       - Dimensions along x,y and z of \p sprite and \p mask must be the same.
 1.19686 +    **/
 1.19687 +    template<typename ti, typename tm>
 1.19688 +    CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
 1.19689 +                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 1.19690 +                        const float mask_valmax=1) {
 1.19691 +      if (is_empty()) return *this;
 1.19692 +      if (!sprite)
 1.19693 +        throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
 1.19694 +                                    pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 1.19695 +      if (!mask)
 1.19696 +        throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
 1.19697 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 1.19698 +      if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
 1.19699 +      if (is_overlapped(mask))   return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
 1.19700 +      if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
 1.19701 +        throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
 1.19702 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
 1.19703 +      const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
 1.19704 +      const int
 1.19705 +        lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
 1.19706 +        lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
 1.19707 +        lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
 1.19708 +        lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
 1.19709 +      const int
 1.19710 +        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),
 1.19711 +        ssize = mask.dimx()*mask.dimy()*mask.dimz();
 1.19712 +      const ti *ptrs = sprite.data + coff;
 1.19713 +      const tm *ptrm = mask.data   + coff;
 1.19714 +      const unsigned int
 1.19715 +        offX = width - lX,                soffX = sprite.width - lX,
 1.19716 +        offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
 1.19717 +        offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
 1.19718 +      if (lX>0 && lY>0 && lZ>0 && lV>0) {
 1.19719 +        T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
 1.19720 +        for (int v = 0; v<lV; ++v) {
 1.19721 +          ptrm = mask.data + (ptrm - mask.data)%ssize;
 1.19722 +          for (int z = 0; z<lZ; ++z) {
 1.19723 +            for (int y = 0; y<lY; ++y) {
 1.19724 +              for (int x=0; x<lX; ++x) {
 1.19725 +                const float mopacity = (float)(*(ptrm++)*opacity),
 1.19726 +                  nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
 1.19727 +                *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
 1.19728 +                ++ptrd;
 1.19729 +              }
 1.19730 +              ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
 1.19731 +            }
 1.19732 +            ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
 1.19733 +          }
 1.19734 +          ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
 1.19735 +        }
 1.19736 +      }
 1.19737 +      return *this;
 1.19738 +    }
 1.19739 +
 1.19740 +    //! Draw an image.
 1.19741 +    template<typename ti, typename tm>
 1.19742 +    CImg<T>& draw_image(const int x0, const int y0, const int z0,
 1.19743 +                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 1.19744 +                        const float mask_valmax=1) {
 1.19745 +      return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
 1.19746 +    }
 1.19747 +
 1.19748 +    //! Draw an image.
 1.19749 +    template<typename ti, typename tm>
 1.19750 +    CImg<T>& draw_image(const int x0, const int y0,
 1.19751 +                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 1.19752 +                        const float mask_valmax=1) {
 1.19753 +      return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
 1.19754 +    }
 1.19755 +
 1.19756 +    //! Draw an image.
 1.19757 +    template<typename ti, typename tm>
 1.19758 +    CImg<T>& draw_image(const int x0,
 1.19759 +                        const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 1.19760 +                        const float mask_valmax=1) {
 1.19761 +      return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
 1.19762 +    }
 1.19763 +
 1.19764 +    //! Draw an image.
 1.19765 +    template<typename ti, typename tm>
 1.19766 +    CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
 1.19767 +                        const float mask_valmax=1) {
 1.19768 +      return draw_image(0,sprite,mask,opacity,mask_valmax);
 1.19769 +    }
 1.19770 +
 1.19771 +    //! 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).
 1.19772 +    /**
 1.19773 +       \param x0 X-coordinate of the upper-left rectangle corner.
 1.19774 +       \param y0 Y-coordinate of the upper-left rectangle corner.
 1.19775 +       \param z0 Z-coordinate of the upper-left rectangle corner.
 1.19776 +       \param v0 V-coordinate of the upper-left rectangle corner.
 1.19777 +       \param x1 X-coordinate of the lower-right rectangle corner.
 1.19778 +       \param y1 Y-coordinate of the lower-right rectangle corner.
 1.19779 +       \param z1 Z-coordinate of the lower-right rectangle corner.
 1.19780 +       \param v1 V-coordinate of the lower-right rectangle corner.
 1.19781 +       \param val Scalar value used to fill the rectangle area.
 1.19782 +       \param opacity Drawing opacity (optional).
 1.19783 +       \note
 1.19784 +       - Clipping is supported.
 1.19785 +    **/
 1.19786 +    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
 1.19787 +                            const int x1, const int y1, const int z1, const int v1,
 1.19788 +                            const T val, const float opacity=1) {
 1.19789 +      if (is_empty()) return *this;
 1.19790 +      const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
 1.19791 +      const int
 1.19792 +        nx0 = bx?x0:x1, nx1 = bx?x1:x0,
 1.19793 +        ny0 = by?y0:y1, ny1 = by?y1:y0,
 1.19794 +        nz0 = bz?z0:z1, nz1 = bz?z1:z0,
 1.19795 +        nv0 = bv?v0:v1, nv1 = bv?v1:v0;
 1.19796 +      const int
 1.19797 +        lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
 1.19798 +        lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
 1.19799 +        lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
 1.19800 +        lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
 1.19801 +      const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
 1.19802 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.19803 +      T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
 1.19804 +      if (lX>0 && lY>0 && lZ>0 && lV>0)
 1.19805 +        for (int v = 0; v<lV; ++v) {
 1.19806 +          for (int z = 0; z<lZ; ++z) {
 1.19807 +            for (int y = 0; y<lY; ++y) {
 1.19808 +              if (opacity>=1) {
 1.19809 +                if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
 1.19810 +                else { cimg_std::memset(ptrd,(int)val,lX); ptrd+=width; }
 1.19811 +              } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
 1.19812 +            }
 1.19813 +            ptrd+=offY;
 1.19814 +          }
 1.19815 +          ptrd+=offZ;
 1.19816 +        }
 1.19817 +      return *this;
 1.19818 +    }
 1.19819 +
 1.19820 +    //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
 1.19821 +    /**
 1.19822 +       \param x0 X-coordinate of the upper-left rectangle corner.
 1.19823 +       \param y0 Y-coordinate of the upper-left rectangle corner.
 1.19824 +       \param z0 Z-coordinate of the upper-left rectangle corner.
 1.19825 +       \param x1 X-coordinate of the lower-right rectangle corner.
 1.19826 +       \param y1 Y-coordinate of the lower-right rectangle corner.
 1.19827 +       \param z1 Z-coordinate of the lower-right rectangle corner.
 1.19828 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.19829 +       \param opacity Drawing opacity (optional).
 1.19830 +       \note
 1.19831 +       - Clipping is supported.
 1.19832 +    **/
 1.19833 +    template<typename tc>
 1.19834 +    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 1.19835 +                            const int x1, const int y1, const int z1,
 1.19836 +                            const tc *const color, const float opacity=1) {
 1.19837 +      if (!color)
 1.19838 +        throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
 1.19839 +                                    pixel_type());
 1.19840 +      cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
 1.19841 +      return *this;
 1.19842 +    }
 1.19843 +
 1.19844 +    //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
 1.19845 +    template<typename tc>
 1.19846 +    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 1.19847 +                            const int x1, const int y1, const int z1,
 1.19848 +                            const CImg<tc>& color, const float opacity=1) {
 1.19849 +      return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
 1.19850 +    }
 1.19851 +
 1.19852 +    //! Draw a 3D outlined colored rectangle in the instance image.
 1.19853 +    template<typename tc>
 1.19854 +    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 1.19855 +                            const int x1, const int y1, const int z1,
 1.19856 +                            const tc *const color, const float opacity,
 1.19857 +                            const unsigned int pattern) {
 1.19858 +      return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
 1.19859 +        draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
 1.19860 +        draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
 1.19861 +        draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
 1.19862 +        draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
 1.19863 +        draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
 1.19864 +        draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
 1.19865 +        draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
 1.19866 +        draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
 1.19867 +        draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
 1.19868 +        draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
 1.19869 +        draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
 1.19870 +    }
 1.19871 +
 1.19872 +    //! Draw a 3D outlined colored rectangle in the instance image.
 1.19873 +    template<typename tc>
 1.19874 +    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 1.19875 +                            const int x1, const int y1, const int z1,
 1.19876 +                            const CImg<tc>& color, const float opacity,
 1.19877 +                            const unsigned int pattern) {
 1.19878 +      return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
 1.19879 +    }
 1.19880 +
 1.19881 +    //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
 1.19882 +    /**
 1.19883 +       \param x0 X-coordinate of the upper-left rectangle corner.
 1.19884 +       \param y0 Y-coordinate of the upper-left rectangle corner.
 1.19885 +       \param x1 X-coordinate of the lower-right rectangle corner.
 1.19886 +       \param y1 Y-coordinate of the lower-right rectangle corner.
 1.19887 +       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 1.19888 +       \param opacity Drawing opacity (optional).
 1.19889 +       \note
 1.19890 +       - Clipping is supported.
 1.19891 +    **/
 1.19892 +    template<typename tc>
 1.19893 +    CImg<T>& draw_rectangle(const int x0, const int y0,
 1.19894 +                            const int x1, const int y1,
 1.19895 +                            const tc *const color, const float opacity=1) {
 1.19896 +      return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
 1.19897 +    }
 1.19898 +
 1.19899 +    //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
 1.19900 +    template<typename tc>
 1.19901 +    CImg<T>& draw_rectangle(const int x0, const int y0,
 1.19902 +                            const int x1, const int y1,
 1.19903 +                            const CImg<tc>& color, const float opacity=1) {
 1.19904 +      return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
 1.19905 +    }
 1.19906 +
 1.19907 +    //! Draw a 2D outlined colored rectangle.
 1.19908 +    template<typename tc>
 1.19909 +    CImg<T>& draw_rectangle(const int x0, const int y0,
 1.19910 +                            const int x1, const int y1,
 1.19911 +                            const tc *const color, const float opacity,
 1.19912 +                            const unsigned int pattern) {
 1.19913 +      if (is_empty()) return *this;
 1.19914 +      if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
 1.19915 +      if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
 1.19916 +      const bool bx = (x0<x1), by = (y0<y1);
 1.19917 +      const int
 1.19918 +        nx0 = bx?x0:x1, nx1 = bx?x1:x0,
 1.19919 +        ny0 = by?y0:y1, ny1 = by?y1:y0;
 1.19920 +      if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
 1.19921 +                      draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
 1.19922 +      return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
 1.19923 +        draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
 1.19924 +        draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
 1.19925 +        draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
 1.19926 +    }
 1.19927 +
 1.19928 +    //! Draw a 2D outlined colored rectangle.
 1.19929 +    template<typename tc>
 1.19930 +    CImg<T>& draw_rectangle(const int x0, const int y0,
 1.19931 +                            const int x1, const int y1,
 1.19932 +                            const CImg<tc>& color, const float opacity,
 1.19933 +                            const unsigned int pattern) {
 1.19934 +      return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
 1.19935 +    }
 1.19936 +
 1.19937 +    // Inner macro for drawing triangles.
 1.19938 +#define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
 1.19939 +        for (int y = y0<0?0:y0, \
 1.19940 +               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 1.19941 +               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 1.19942 +               _sxn=1, \
 1.19943 +               _sxr=1, \
 1.19944 +               _sxl=1, \
 1.19945 +               _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 1.19946 +               _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 1.19947 +               _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 1.19948 +               _dyn = y2-y1, \
 1.19949 +               _dyr = y2-y0, \
 1.19950 +               _dyl = y1-y0, \
 1.19951 +               _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 1.19952 +                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 1.19953 +                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 1.19954 +                           cimg::min((int)(img).height-y-1,y2-y)), \
 1.19955 +               _errn = _dyn/2, \
 1.19956 +               _errr = _dyr/2, \
 1.19957 +               _errl = _dyl/2, \
 1.19958 +               _rxn = _dyn?(x2-x1)/_dyn:0, \
 1.19959 +               _rxr = _dyr?(x2-x0)/_dyr:0, \
 1.19960 +               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 1.19961 +                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
 1.19962 +             _counter>=0; --_counter, ++y, \
 1.19963 +               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 1.19964 +               xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
 1.19965 +                           (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 1.19966 +
 1.19967 +#define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
 1.19968 +        for (int y = y0<0?0:y0, \
 1.19969 +               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 1.19970 +               cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
 1.19971 +               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 1.19972 +               cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
 1.19973 +               _sxn=1, _scn=1, \
 1.19974 +               _sxr=1, _scr=1, \
 1.19975 +               _sxl=1, _scl=1, \
 1.19976 +               _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 1.19977 +               _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 1.19978 +               _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 1.19979 +               _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
 1.19980 +               _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
 1.19981 +               _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
 1.19982 +               _dyn = y2-y1, \
 1.19983 +               _dyr = y2-y0, \
 1.19984 +               _dyl = y1-y0, \
 1.19985 +               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 1.19986 +                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 1.19987 +                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 1.19988 +                          _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
 1.19989 +                          _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
 1.19990 +                          _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
 1.19991 +                          cimg::min((int)(img).height-y-1,y2-y)), \
 1.19992 +               _errn = _dyn/2, _errcn = _errn, \
 1.19993 +               _errr = _dyr/2, _errcr = _errr, \
 1.19994 +               _errl = _dyl/2, _errcl = _errl, \
 1.19995 +               _rxn = _dyn?(x2-x1)/_dyn:0, \
 1.19996 +               _rcn = _dyn?(c2-c1)/_dyn:0, \
 1.19997 +               _rxr = _dyr?(x2-x0)/_dyr:0, \
 1.19998 +               _rcr = _dyr?(c2-c0)/_dyr:0, \
 1.19999 +               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 1.20000 +                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 1.20001 +               _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
 1.20002 +                                       (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
 1.20003 +             _counter>=0; --_counter, ++y, \
 1.20004 +               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 1.20005 +               cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
 1.20006 +               xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
 1.20007 +                           _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 1.20008 +               (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
 1.20009 +                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 1.20010 +
 1.20011 +#define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
 1.20012 +        for (int y = y0<0?0:y0, \
 1.20013 +               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 1.20014 +               txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 1.20015 +               tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 1.20016 +               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 1.20017 +               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 1.20018 +               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 1.20019 +               _sxn=1, _stxn=1, _styn=1, \
 1.20020 +               _sxr=1, _stxr=1, _styr=1, \
 1.20021 +               _sxl=1, _stxl=1, _styl=1, \
 1.20022 +               _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 1.20023 +               _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 1.20024 +               _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 1.20025 +               _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 1.20026 +               _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 1.20027 +               _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 1.20028 +               _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 1.20029 +               _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 1.20030 +               _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 1.20031 +               _dyn = y2-y1, \
 1.20032 +               _dyr = y2-y0, \
 1.20033 +               _dyl = y1-y0, \
 1.20034 +               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 1.20035 +                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 1.20036 +                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 1.20037 +                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 1.20038 +                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 1.20039 +                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 1.20040 +                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 1.20041 +                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 1.20042 +                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 1.20043 +                          cimg::min((int)(img).height-y-1,y2-y)), \
 1.20044 +               _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
 1.20045 +               _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
 1.20046 +               _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
 1.20047 +               _rxn = _dyn?(x2-x1)/_dyn:0, \
 1.20048 +               _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 1.20049 +               _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 1.20050 +               _rxr = _dyr?(x2-x0)/_dyr:0, \
 1.20051 +               _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 1.20052 +               _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 1.20053 +               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 1.20054 +                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 1.20055 +               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 1.20056 +                                       (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 1.20057 +               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 1.20058 +                                       (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
 1.20059 +             _counter>=0; --_counter, ++y, \
 1.20060 +               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 1.20061 +               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 1.20062 +               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 1.20063 +               xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 1.20064 +                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 1.20065 +                           _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 1.20066 +               (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 1.20067 +                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
 1.20068 +                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 1.20069 +
 1.20070 +#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) \
 1.20071 +        for (int y = y0<0?0:y0, \
 1.20072 +               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 1.20073 +               cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
 1.20074 +               txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 1.20075 +               tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 1.20076 +               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 1.20077 +               cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
 1.20078 +               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 1.20079 +               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 1.20080 +               _sxn=1, _scn=1, _stxn=1, _styn=1, \
 1.20081 +               _sxr=1, _scr=1, _stxr=1, _styr=1, \
 1.20082 +               _sxl=1, _scl=1, _stxl=1, _styl=1, \
 1.20083 +               _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
 1.20084 +               _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
 1.20085 +               _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
 1.20086 +               _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
 1.20087 +               _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
 1.20088 +               _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
 1.20089 +               _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 1.20090 +               _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 1.20091 +               _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 1.20092 +               _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 1.20093 +               _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 1.20094 +               _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 1.20095 +               _dyn = y2-y1, \
 1.20096 +               _dyr = y2-y0, \
 1.20097 +               _dyl = y1-y0, \
 1.20098 +               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 1.20099 +                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 1.20100 +                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 1.20101 +                          _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
 1.20102 +                          _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
 1.20103 +                          _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
 1.20104 +                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 1.20105 +                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 1.20106 +                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 1.20107 +                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 1.20108 +                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 1.20109 +                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 1.20110 +                          cimg::min((int)(img).height-y-1,y2-y)), \
 1.20111 +               _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
 1.20112 +               _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
 1.20113 +               _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
 1.20114 +               _rxn = _dyn?(x2-x1)/_dyn:0, \
 1.20115 +               _rcn = _dyn?(c2-c1)/_dyn:0, \
 1.20116 +               _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 1.20117 +               _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 1.20118 +               _rxr = _dyr?(x2-x0)/_dyr:0, \
 1.20119 +               _rcr = _dyr?(c2-c0)/_dyr:0, \
 1.20120 +               _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 1.20121 +               _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 1.20122 +               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 1.20123 +                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 1.20124 +               _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
 1.20125 +                                       (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
 1.20126 +               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 1.20127 +                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 1.20128 +               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 1.20129 +                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
 1.20130 +             _counter>=0; --_counter, ++y, \
 1.20131 +               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 1.20132 +               cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
 1.20133 +               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 1.20134 +               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 1.20135 +               xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
 1.20136 +                            txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 1.20137 +                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 1.20138 +                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 1.20139 +               (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
 1.20140 +                _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 1.20141 +                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
 1.20142 +                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 1.20143 +
 1.20144 +#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) \
 1.20145 +        for (int y = y0<0?0:y0, \
 1.20146 +               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
 1.20147 +               txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
 1.20148 +               tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
 1.20149 +               lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
 1.20150 +               lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
 1.20151 +               xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
 1.20152 +               txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
 1.20153 +               tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
 1.20154 +               lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
 1.20155 +               lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
 1.20156 +               _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
 1.20157 +               _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
 1.20158 +               _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
 1.20159 +               _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
 1.20160 +               _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
 1.20161 +               _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
 1.20162 +               _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
 1.20163 +               _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
 1.20164 +               _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
 1.20165 +               _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
 1.20166 +               _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
 1.20167 +               _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
 1.20168 +               _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
 1.20169 +               _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
 1.20170 +               _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
 1.20171 +               _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
 1.20172 +               _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
 1.20173 +               _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
 1.20174 +               _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
 1.20175 +                          _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
 1.20176 +                          _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
 1.20177 +                          _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
 1.20178 +                          _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
 1.20179 +                          _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
 1.20180 +                          _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
 1.20181 +                          _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
 1.20182 +                          _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
 1.20183 +                          _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
 1.20184 +                          _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
 1.20185 +                          _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
 1.20186 +                          _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
 1.20187 +                          _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
 1.20188 +                          _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
 1.20189 +                          cimg::min((int)(img).height-y-1,y2-y)), \
 1.20190 +               _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
 1.20191 +               _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
 1.20192 +               _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
 1.20193 +               _rxn = _dyn?(x2-x1)/_dyn:0, \
 1.20194 +               _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
 1.20195 +               _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
 1.20196 +               _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
 1.20197 +               _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
 1.20198 +               _rxr = _dyr?(x2-x0)/_dyr:0, \
 1.20199 +               _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
 1.20200 +               _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
 1.20201 +               _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
 1.20202 +               _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
 1.20203 +               _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
 1.20204 +                                       (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
 1.20205 +               _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
 1.20206 +                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
 1.20207 +               _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
 1.20208 +                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
 1.20209 +               _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
 1.20210 +                                        (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
 1.20211 +               _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
 1.20212 +                                        (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
 1.20213 +             _counter>=0; --_counter, ++y, \
 1.20214 +               xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
 1.20215 +               txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
 1.20216 +               tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
 1.20217 +               lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
 1.20218 +               lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
 1.20219 +               xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
 1.20220 +                            tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
 1.20221 +                            lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
 1.20222 +                            lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
 1.20223 +                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
 1.20224 +               (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
 1.20225 +                _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
 1.20226 +                _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
 1.20227 +                _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
 1.20228 +                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
 1.20229 +
 1.20230 +    // Draw a colored triangle (inner routine, uses bresenham's algorithm).
 1.20231 +    template<typename tc>
 1.20232 +    CImg<T>& _draw_triangle(const int x0, const int y0,
 1.20233 +                            const int x1, const int y1,
 1.20234 +                            const int x2, const int y2,
 1.20235 +                            const tc *const color, const float opacity,
 1.20236 +                            const float brightness) {
 1.20237 +      _draw_scanline(color,opacity);
 1.20238 +      const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
 1.20239 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 1.20240 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
 1.20241 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
 1.20242 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
 1.20243 +      if (ny0<dimy() && ny2>=0) {
 1.20244 +        if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
 1.20245 +          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
 1.20246 +        else
 1.20247 +          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
 1.20248 +      }
 1.20249 +      return *this;
 1.20250 +    }
 1.20251 +
 1.20252 +    //! Draw a 2D filled colored triangle.
 1.20253 +    template<typename tc>
 1.20254 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20255 +                           const int x1, const int y1,
 1.20256 +                           const int x2, const int y2,
 1.20257 +                           const tc *const color, const float opacity=1) {
 1.20258 +      if (is_empty()) return *this;
 1.20259 +      if (!color)
 1.20260 +        throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 1.20261 +                                    pixel_type());
 1.20262 +      _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
 1.20263 +      return *this;
 1.20264 +    }
 1.20265 +
 1.20266 +    //! Draw a 2D filled colored triangle.
 1.20267 +    template<typename tc>
 1.20268 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20269 +                           const int x1, const int y1,
 1.20270 +                           const int x2, const int y2,
 1.20271 +                           const CImg<tc>& color, const float opacity=1) {
 1.20272 +      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
 1.20273 +    }
 1.20274 +
 1.20275 +    //! Draw a 2D outlined colored triangle.
 1.20276 +    template<typename tc>
 1.20277 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20278 +                           const int x1, const int y1,
 1.20279 +                           const int x2, const int y2,
 1.20280 +                           const tc *const color, const float opacity,
 1.20281 +                           const unsigned int pattern) {
 1.20282 +      if (is_empty()) return *this;
 1.20283 +      if (!color)
 1.20284 +        throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 1.20285 +                                    pixel_type());
 1.20286 +      draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
 1.20287 +        draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
 1.20288 +        draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
 1.20289 +      return *this;
 1.20290 +    }
 1.20291 +
 1.20292 +    //! Draw a 2D outlined colored triangle.
 1.20293 +    template<typename tc>
 1.20294 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20295 +                           const int x1, const int y1,
 1.20296 +                           const int x2, const int y2,
 1.20297 +                           const CImg<tc>& color, const float opacity,
 1.20298 +                           const unsigned int pattern) {
 1.20299 +      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
 1.20300 +    }
 1.20301 +
 1.20302 +    //! Draw a 2D filled colored triangle, with z-buffering.
 1.20303 +    template<typename tc>
 1.20304 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.20305 +                           const int x0, const int y0, const float z0,
 1.20306 +                           const int x1, const int y1, const float z1,
 1.20307 +                           const int x2, const int y2, const float z2,
 1.20308 +                           const tc *const color, const float opacity=1,
 1.20309 +                           const float brightness=1) {
 1.20310 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.20311 +      if (!color)
 1.20312 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 1.20313 +                                    pixel_type());
 1.20314 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20315 +      const float
 1.20316 +        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 1.20317 +        nbrightness = brightness<0?0:(brightness>2?2:brightness);
 1.20318 +      const int whz = width*height*depth, offx = dim*whz;
 1.20319 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 1.20320 +      float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.20321 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
 1.20322 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
 1.20323 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
 1.20324 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20325 +      float
 1.20326 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.20327 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.20328 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.20329 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.20330 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 1.20331 +      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 1.20332 +        if (y==ny1) { zl = nz1; pzl = pzn; }
 1.20333 +        int xleft = xleft0, xright = xright0;
 1.20334 +        float zleft = zl, zright = zr;
 1.20335 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
 1.20336 +        const int dx = xright - xleft;
 1.20337 +        const float pentez = (zright - zleft)/dx;
 1.20338 +        if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
 1.20339 +        if (xleft<0) xleft = 0;
 1.20340 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20341 +        T* ptrd = ptr(xleft,y,0,0);
 1.20342 +        float *ptrz = zbuffer + xleft + y*width;
 1.20343 +        if (opacity>=1) {
 1.20344 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20345 +            if (zleft>*ptrz) {
 1.20346 +              *ptrz = zleft;
 1.20347 +              const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
 1.20348 +              ptrd-=offx;
 1.20349 +            }
 1.20350 +            zleft+=pentez;
 1.20351 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20352 +            if (zleft>*ptrz) {
 1.20353 +              *ptrz = zleft;
 1.20354 +              const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
 1.20355 +              ptrd-=offx;
 1.20356 +            }
 1.20357 +            zleft+=pentez;
 1.20358 +          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20359 +            if (zleft>*ptrz) {
 1.20360 +              *ptrz = zleft;
 1.20361 +              const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
 1.20362 +              ptrd-=offx;
 1.20363 +            }
 1.20364 +            zleft+=pentez;
 1.20365 +          }
 1.20366 +        } else {
 1.20367 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20368 +            if (zleft>*ptrz) {
 1.20369 +              *ptrz = zleft;
 1.20370 +              const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
 1.20371 +              ptrd-=offx;
 1.20372 +            }
 1.20373 +            zleft+=pentez;
 1.20374 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20375 +            if (zleft>*ptrz) {
 1.20376 +              *ptrz = zleft;
 1.20377 +              const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
 1.20378 +              ptrd-=offx;
 1.20379 +            }
 1.20380 +            zleft+=pentez;
 1.20381 +          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20382 +            if (zleft>*ptrz) {
 1.20383 +              *ptrz = zleft;
 1.20384 +              const tc *col = color;
 1.20385 +              cimg_forV(*this,k) {
 1.20386 +                const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 1.20387 +                *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.20388 +                ptrd+=whz;
 1.20389 +              }
 1.20390 +              ptrd-=offx;
 1.20391 +            }
 1.20392 +            zleft+=pentez;
 1.20393 +          }
 1.20394 +        }
 1.20395 +        zr+=pzr; zl+=pzl;
 1.20396 +      }
 1.20397 +      return *this;
 1.20398 +    }
 1.20399 +
 1.20400 +    //! Draw a 2D filled colored triangle, with z-buffering.
 1.20401 +    template<typename tc>
 1.20402 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.20403 +                           const int x0, const int y0, const float z0,
 1.20404 +                           const int x1, const int y1, const float z1,
 1.20405 +                           const int x2, const int y2, const float z2,
 1.20406 +                           const CImg<tc>& color, const float opacity=1,
 1.20407 +                           const float brightness=1) {
 1.20408 +      return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
 1.20409 +    }
 1.20410 +
 1.20411 +    //! Draw a 2D Gouraud-shaded colored triangle.
 1.20412 +    /**
 1.20413 +       \param x0 = X-coordinate of the first corner in the instance image.
 1.20414 +       \param y0 = Y-coordinate of the first corner in the instance image.
 1.20415 +       \param x1 = X-coordinate of the second corner in the instance image.
 1.20416 +       \param y1 = Y-coordinate of the second corner in the instance image.
 1.20417 +       \param x2 = X-coordinate of the third corner in the instance image.
 1.20418 +       \param y2 = Y-coordinate of the third corner in the instance image.
 1.20419 +       \param color = array of dimv() values of type \c T, defining the global drawing color.
 1.20420 +       \param brightness0 = brightness of the first corner (in [0,2]).
 1.20421 +       \param brightness1 = brightness of the second corner (in [0,2]).
 1.20422 +       \param brightness2 = brightness of the third corner (in [0,2]).
 1.20423 +       \param opacity = opacity of the drawing.
 1.20424 +       \note Clipping is supported.
 1.20425 +    **/
 1.20426 +    template<typename tc>
 1.20427 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20428 +                           const int x1, const int y1,
 1.20429 +                           const int x2, const int y2,
 1.20430 +                           const tc *const color,
 1.20431 +                           const float brightness0,
 1.20432 +                           const float brightness1,
 1.20433 +                           const float brightness2,
 1.20434 +                           const float opacity=1) {
 1.20435 +      if (is_empty()) return *this;
 1.20436 +      if (!color)
 1.20437 +        throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 1.20438 +                                    pixel_type());
 1.20439 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20440 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.20441 +      const int whz = width*height*depth, offx = dim*whz-1;
 1.20442 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.20443 +        nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 1.20444 +        nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 1.20445 +        nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 1.20446 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
 1.20447 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
 1.20448 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
 1.20449 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20450 +      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 1.20451 +        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
 1.20452 +        if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
 1.20453 +        const int
 1.20454 +          dx = xright - xleft,
 1.20455 +          dc = cright>cleft?cright - cleft:cleft - cright,
 1.20456 +          rc = dx?(cright - cleft)/dx:0,
 1.20457 +          sc = cright>cleft?1:-1,
 1.20458 +          ndc = dc-(dx?dx*(dc/dx):0);
 1.20459 +        int errc = dx>>1;
 1.20460 +        if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
 1.20461 +        if (xleft<0) xleft = 0;
 1.20462 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20463 +        T* ptrd = ptr(xleft,y);
 1.20464 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.20465 +          const tc *col = color;
 1.20466 +          cimg_forV(*this,k) {
 1.20467 +            *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 1.20468 +            ptrd+=whz;
 1.20469 +          }
 1.20470 +          ptrd-=offx;
 1.20471 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.20472 +        } else for (int x = xleft; x<=xright; ++x) {
 1.20473 +          const tc *col = color;
 1.20474 +          cimg_forV(*this,k) {
 1.20475 +            const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 1.20476 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.20477 +            ptrd+=whz;
 1.20478 +          }
 1.20479 +          ptrd-=offx;
 1.20480 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.20481 +        }
 1.20482 +      }
 1.20483 +      return *this;
 1.20484 +    }
 1.20485 +
 1.20486 +    //! Draw a 2D Gouraud-shaded colored triangle.
 1.20487 +    template<typename tc>
 1.20488 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20489 +                           const int x1, const int y1,
 1.20490 +                           const int x2, const int y2,
 1.20491 +                           const CImg<tc>& color,
 1.20492 +                           const float brightness0,
 1.20493 +                           const float brightness1,
 1.20494 +                           const float brightness2,
 1.20495 +                           const float opacity=1) {
 1.20496 +      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
 1.20497 +    }
 1.20498 +
 1.20499 +    //! Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
 1.20500 +    template<typename tc>
 1.20501 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.20502 +                           const int x0, const int y0, const float z0,
 1.20503 +                           const int x1, const int y1, const float z1,
 1.20504 +                           const int x2, const int y2, const float z2,
 1.20505 +                           const tc *const color,
 1.20506 +                           const float brightness0,
 1.20507 +                           const float brightness1,
 1.20508 +                           const float brightness2,
 1.20509 +                           const float opacity=1) {
 1.20510 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.20511 +      if (!color)
 1.20512 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 1.20513 +                                    pixel_type());
 1.20514 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20515 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.20516 +      const int whz = width*height*depth, offx = dim*whz;
 1.20517 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.20518 +        nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 1.20519 +        nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 1.20520 +        nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 1.20521 +      float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.20522 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
 1.20523 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
 1.20524 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
 1.20525 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20526 +      float
 1.20527 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.20528 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.20529 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.20530 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.20531 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 1.20532 +      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 1.20533 +        if (y==ny1) { zl = nz1; pzl = pzn; }
 1.20534 +        int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
 1.20535 +        float zleft = zl, zright = zr;
 1.20536 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
 1.20537 +        const int
 1.20538 +          dx = xright - xleft,
 1.20539 +          dc = cright>cleft?cright - cleft:cleft - cright,
 1.20540 +          rc = dx?(cright-cleft)/dx:0,
 1.20541 +          sc = cright>cleft?1:-1,
 1.20542 +          ndc = dc-(dx?dx*(dc/dx):0);
 1.20543 +        const float pentez = (zright - zleft)/dx;
 1.20544 +        int errc = dx>>1;
 1.20545 +        if (xleft<0 && dx) {
 1.20546 +          cleft-=xleft*(cright - cleft)/dx;
 1.20547 +          zleft-=xleft*(zright - zleft)/dx;
 1.20548 +        }
 1.20549 +        if (xleft<0) xleft = 0;
 1.20550 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20551 +        T *ptrd = ptr(xleft,y);
 1.20552 +        float *ptrz = zbuffer + xleft + y*width;
 1.20553 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 1.20554 +          if (zleft>*ptrz) {
 1.20555 +            *ptrz = zleft;
 1.20556 +            const tc *col = color;
 1.20557 +            cimg_forV(*this,k) {
 1.20558 +              *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 1.20559 +              ptrd+=whz;
 1.20560 +            }
 1.20561 +            ptrd-=offx;
 1.20562 +          }
 1.20563 +          zleft+=pentez;
 1.20564 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.20565 +        } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 1.20566 +          if (zleft>*ptrz) {
 1.20567 +            *ptrz = zleft;
 1.20568 +            const tc *col = color;
 1.20569 +            cimg_forV(*this,k) {
 1.20570 +              const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 1.20571 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.20572 +              ptrd+=whz;
 1.20573 +            }
 1.20574 +            ptrd-=offx;
 1.20575 +          }
 1.20576 +          zleft+=pentez;
 1.20577 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.20578 +        }
 1.20579 +        zr+=pzr; zl+=pzl;
 1.20580 +      }
 1.20581 +      return *this;
 1.20582 +    }
 1.20583 +
 1.20584 +    //! Draw a Gouraud triangle with z-buffer consideration.
 1.20585 +    template<typename tc>
 1.20586 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.20587 +                           const int x0, const int y0, const float z0,
 1.20588 +                           const int x1, const int y1, const float z1,
 1.20589 +                           const int x2, const int y2, const float z2,
 1.20590 +                           const CImg<tc>& color,
 1.20591 +                           const float brightness0,
 1.20592 +                           const float brightness1,
 1.20593 +                           const float brightness2,
 1.20594 +                           const float opacity=1) {
 1.20595 +      return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
 1.20596 +    }
 1.20597 +
 1.20598 +    //! Draw a 2D textured triangle.
 1.20599 +    /**
 1.20600 +       \param x0 = X-coordinate of the first corner in the instance image.
 1.20601 +       \param y0 = Y-coordinate of the first corner in the instance image.
 1.20602 +       \param x1 = X-coordinate of the second corner in the instance image.
 1.20603 +       \param y1 = Y-coordinate of the second corner in the instance image.
 1.20604 +       \param x2 = X-coordinate of the third corner in the instance image.
 1.20605 +       \param y2 = Y-coordinate of the third corner in the instance image.
 1.20606 +       \param texture = texture image used to fill the triangle.
 1.20607 +       \param tx0 = X-coordinate of the first corner in the texture image.
 1.20608 +       \param ty0 = Y-coordinate of the first corner in the texture image.
 1.20609 +       \param tx1 = X-coordinate of the second corner in the texture image.
 1.20610 +       \param ty1 = Y-coordinate of the second corner in the texture image.
 1.20611 +       \param tx2 = X-coordinate of the third corner in the texture image.
 1.20612 +       \param ty2 = Y-coordinate of the third corner in the texture image.
 1.20613 +       \param opacity = opacity of the drawing.
 1.20614 +       \param brightness = brightness of the drawing (in [0,2]).
 1.20615 +       \note Clipping is supported, but texture coordinates do not support clipping.
 1.20616 +    **/
 1.20617 +    template<typename tc>
 1.20618 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.20619 +                           const int x1, const int y1,
 1.20620 +                           const int x2, const int y2,
 1.20621 +                           const CImg<tc>& texture,
 1.20622 +                           const int tx0, const int ty0,
 1.20623 +                           const int tx1, const int ty1,
 1.20624 +                           const int tx2, const int ty2,
 1.20625 +                           const float opacity=1,
 1.20626 +                           const float brightness=1) {
 1.20627 +      if (is_empty()) return *this;
 1.20628 +      if (!texture || texture.dim<dim)
 1.20629 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.20630 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.20631 +      if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 1.20632 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20633 +      const float
 1.20634 +        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 1.20635 +        nbrightness = brightness<0?0:(brightness>2?2:brightness);
 1.20636 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.20637 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.20638 +        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
 1.20639 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
 1.20640 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
 1.20641 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
 1.20642 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20643 +      _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
 1.20644 +                          nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
 1.20645 +        int
 1.20646 +          xleft = xleft0, xright = xright0,
 1.20647 +          txleft = txleft0, txright = txright0,
 1.20648 +          tyleft = tyleft0, tyright = tyright0;
 1.20649 +        if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
 1.20650 +        const int
 1.20651 +          dx = xright - xleft,
 1.20652 +          dtx = txright>txleft?txright - txleft:txleft - txright,
 1.20653 +          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 1.20654 +          rtx = dx?(txright - txleft)/dx:0,
 1.20655 +          rty = dx?(tyright - tyleft)/dx:0,
 1.20656 +          stx = txright>txleft?1:-1,
 1.20657 +          sty = tyright>tyleft?1:-1,
 1.20658 +          ndtx = dtx - (dx?dx*(dtx/dx):0),
 1.20659 +          ndty = dty - (dx?dx*(dty/dx):0);
 1.20660 +        int errtx = dx>>1, errty = errtx;
 1.20661 +        if (xleft<0 && dx) {
 1.20662 +          txleft-=xleft*(txright - txleft)/dx;
 1.20663 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.20664 +        }
 1.20665 +        if (xleft<0) xleft = 0;
 1.20666 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20667 +        T* ptrd = ptr(xleft,y,0,0);
 1.20668 +        if (opacity>=1) {
 1.20669 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 1.20670 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20671 +            cimg_forV(*this,k) {
 1.20672 +              *ptrd = (T)*col;
 1.20673 +              ptrd+=whz; col+=twhz;
 1.20674 +            }
 1.20675 +            ptrd-=offx;
 1.20676 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20677 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20678 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 1.20679 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20680 +            cimg_forV(*this,k) {
 1.20681 +              *ptrd = (T)(nbrightness**col);
 1.20682 +              ptrd+=whz; col+=twhz;
 1.20683 +            }
 1.20684 +            ptrd-=offx;
 1.20685 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20686 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20687 +          } else for (int x = xleft; x<=xright; ++x) {
 1.20688 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20689 +            cimg_forV(*this,k) {
 1.20690 +              *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 1.20691 +              ptrd+=whz; col+=twhz;
 1.20692 +            }
 1.20693 +            ptrd-=offx;
 1.20694 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20695 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20696 +          }
 1.20697 +        } else {
 1.20698 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 1.20699 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20700 +            cimg_forV(*this,k) {
 1.20701 +              *ptrd = (T)(nopacity**col + *ptrd*copacity);
 1.20702 +              ptrd+=whz; col+=twhz;
 1.20703 +            }
 1.20704 +            ptrd-=offx;
 1.20705 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20706 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20707 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 1.20708 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20709 +            cimg_forV(*this,k) {
 1.20710 +              *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 1.20711 +              ptrd+=whz; col+=twhz;
 1.20712 +            }
 1.20713 +            ptrd-=offx;
 1.20714 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20715 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20716 +          } else for (int x = xleft; x<=xright; ++x) {
 1.20717 +            const tc *col = texture.ptr(txleft,tyleft);
 1.20718 +            cimg_forV(*this,k) {
 1.20719 +              const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 1.20720 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.20721 +              ptrd+=whz; col+=twhz;
 1.20722 +            }
 1.20723 +            ptrd-=offx;
 1.20724 +            txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.20725 +            tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.20726 +          }
 1.20727 +        }
 1.20728 +      }
 1.20729 +      return *this;
 1.20730 +    }
 1.20731 +
 1.20732 +    //! Draw a 2D textured triangle, with perspective correction.
 1.20733 +    template<typename tc>
 1.20734 +    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 1.20735 +                           const int x1, const int y1, const float z1,
 1.20736 +                           const int x2, const int y2, const float z2,
 1.20737 +                           const CImg<tc>& texture,
 1.20738 +                           const int tx0, const int ty0,
 1.20739 +                           const int tx1, const int ty1,
 1.20740 +                           const int tx2, const int ty2,
 1.20741 +                           const float opacity=1,
 1.20742 +                           const float brightness=1) {
 1.20743 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.20744 +      if (!texture || texture.dim<dim)
 1.20745 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.20746 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.20747 +      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);
 1.20748 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20749 +      const float
 1.20750 +        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 1.20751 +        nbrightness = brightness<0?0:(brightness>2?2:brightness);
 1.20752 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.20753 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 1.20754 +      float
 1.20755 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.20756 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.20757 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.20758 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.20759 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
 1.20760 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
 1.20761 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
 1.20762 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20763 +      float
 1.20764 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.20765 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.20766 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.20767 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.20768 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.20769 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.20770 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.20771 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.20772 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.20773 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.20774 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.20775 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.20776 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.20777 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.20778 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.20779 +      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 1.20780 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.20781 +        int xleft = xleft0, xright = xright0;
 1.20782 +        float
 1.20783 +          zleft = zl, zright = zr,
 1.20784 +          txleft = txl, txright = txr,
 1.20785 +          tyleft = tyl, tyright = tyr;
 1.20786 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
 1.20787 +        const int dx = xright - xleft;
 1.20788 +        const float
 1.20789 +          pentez = (zright - zleft)/dx,
 1.20790 +          pentetx = (txright - txleft)/dx,
 1.20791 +          pentety = (tyright - tyleft)/dx;
 1.20792 +        if (xleft<0 && dx) {
 1.20793 +          zleft-=xleft*(zright - zleft)/dx;
 1.20794 +          txleft-=xleft*(txright - txleft)/dx;
 1.20795 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.20796 +        }
 1.20797 +        if (xleft<0) xleft = 0;
 1.20798 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20799 +        T* ptrd = ptr(xleft,y,0,0);
 1.20800 +        if (opacity>=1) {
 1.20801 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 1.20802 +            const float invz = 1/zleft;
 1.20803 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20804 +            cimg_forV(*this,k) {
 1.20805 +              *ptrd = (T)*col;
 1.20806 +              ptrd+=whz; col+=twhz;
 1.20807 +            }
 1.20808 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20809 +          } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 1.20810 +            const float invz = 1/zleft;
 1.20811 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20812 +            cimg_forV(*this,k) {
 1.20813 +              *ptrd = (T)(nbrightness**col);
 1.20814 +              ptrd+=whz; col+=twhz;
 1.20815 +            }
 1.20816 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20817 +          } else for (int x = xleft; x<=xright; ++x) {
 1.20818 +            const float invz = 1/zleft;
 1.20819 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20820 +            cimg_forV(*this,k) {
 1.20821 +              *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 1.20822 +              ptrd+=whz; col+=twhz;
 1.20823 +            }
 1.20824 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20825 +          }
 1.20826 +        } else {
 1.20827 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
 1.20828 +            const float invz = 1/zleft;
 1.20829 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20830 +            cimg_forV(*this,k) {
 1.20831 +              *ptrd = (T)(nopacity**col + *ptrd*copacity);
 1.20832 +              ptrd+=whz; col+=twhz;
 1.20833 +            }
 1.20834 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20835 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
 1.20836 +            const float invz = 1/zleft;
 1.20837 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20838 +            cimg_forV(*this,k) {
 1.20839 +              *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 1.20840 +              ptrd+=whz; col+=twhz;
 1.20841 +            }
 1.20842 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20843 +          } else for (int x = xleft; x<=xright; ++x) {
 1.20844 +            const float invz = 1/zleft;
 1.20845 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20846 +            cimg_forV(*this,k) {
 1.20847 +              const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 1.20848 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.20849 +              ptrd+=whz; col+=twhz;
 1.20850 +            }
 1.20851 +            ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20852 +          }
 1.20853 +        }
 1.20854 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.20855 +      }
 1.20856 +      return *this;
 1.20857 +    }
 1.20858 +
 1.20859 +    //! Draw a 2D textured triangle, with z-buffering and perspective correction.
 1.20860 +    template<typename tc>
 1.20861 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.20862 +                           const int x0, const int y0, const float z0,
 1.20863 +                           const int x1, const int y1, const float z1,
 1.20864 +                           const int x2, const int y2, const float z2,
 1.20865 +                           const CImg<tc>& texture,
 1.20866 +                           const int tx0, const int ty0,
 1.20867 +                           const int tx1, const int ty1,
 1.20868 +                           const int tx2, const int ty2,
 1.20869 +                           const float opacity=1,
 1.20870 +                           const float brightness=1) {
 1.20871 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.20872 +      if (!texture || texture.dim<dim)
 1.20873 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.20874 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.20875 +      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);
 1.20876 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.20877 +      const float
 1.20878 +        nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
 1.20879 +        nbrightness = brightness<0?0:(brightness>2?2:brightness);
 1.20880 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 1.20881 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
 1.20882 +      float
 1.20883 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.20884 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.20885 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.20886 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.20887 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
 1.20888 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
 1.20889 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
 1.20890 +      if (ny0>=dimy() || ny2<0) return *this;
 1.20891 +      float
 1.20892 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.20893 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.20894 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.20895 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.20896 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.20897 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.20898 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.20899 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.20900 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.20901 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.20902 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.20903 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.20904 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.20905 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.20906 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.20907 +      _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
 1.20908 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.20909 +        int xleft = xleft0, xright = xright0;
 1.20910 +        float
 1.20911 +          zleft = zl, zright = zr,
 1.20912 +          txleft = txl, txright = txr,
 1.20913 +          tyleft = tyl, tyright = tyr;
 1.20914 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
 1.20915 +        const int dx = xright - xleft;
 1.20916 +        const float
 1.20917 +          pentez = (zright - zleft)/dx,
 1.20918 +          pentetx = (txright - txleft)/dx,
 1.20919 +          pentety = (tyright - tyleft)/dx;
 1.20920 +        if (xleft<0 && dx) {
 1.20921 +          zleft-=xleft*(zright - zleft)/dx;
 1.20922 +          txleft-=xleft*(txright - txleft)/dx;
 1.20923 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.20924 +        }
 1.20925 +        if (xleft<0) xleft = 0;
 1.20926 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.20927 +        T *ptrd = ptr(xleft,y,0,0);
 1.20928 +        float *ptrz = zbuffer + xleft + y*width;
 1.20929 +        if (opacity>=1) {
 1.20930 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20931 +            if (zleft>*ptrz) {
 1.20932 +              *ptrz = zleft;
 1.20933 +              const float invz = 1/zleft;
 1.20934 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20935 +              cimg_forV(*this,k) {
 1.20936 +                *ptrd = (T)*col;
 1.20937 +                ptrd+=whz; col+=twhz;
 1.20938 +              }
 1.20939 +              ptrd-=offx;
 1.20940 +            }
 1.20941 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20942 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20943 +            if (zleft>*ptrz) {
 1.20944 +              *ptrz = zleft;
 1.20945 +              const float invz = 1/zleft;
 1.20946 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20947 +              cimg_forV(*this,k) {
 1.20948 +                *ptrd = (T)(nbrightness**col);
 1.20949 +                ptrd+=whz; col+=twhz;
 1.20950 +              }
 1.20951 +              ptrd-=offx;
 1.20952 +            }
 1.20953 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20954 +          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20955 +            if (zleft>*ptrz) {
 1.20956 +              *ptrz = zleft;
 1.20957 +              const float invz = 1/zleft;
 1.20958 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20959 +              cimg_forV(*this,k) {
 1.20960 +                *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 1.20961 +                ptrd+=whz; col+=twhz;
 1.20962 +              }
 1.20963 +              ptrd-=offx;
 1.20964 +            }
 1.20965 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20966 +          }
 1.20967 +        } else {
 1.20968 +          if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20969 +            if (zleft>*ptrz) {
 1.20970 +              *ptrz = zleft;
 1.20971 +              const float invz = 1/zleft;
 1.20972 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20973 +              cimg_forV(*this,k) {
 1.20974 +                *ptrd = (T)(nopacity**col + *ptrd*copacity);
 1.20975 +                ptrd+=whz; col+=twhz;
 1.20976 +              }
 1.20977 +              ptrd-=offx;
 1.20978 +            }
 1.20979 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20980 +          } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20981 +            if (zleft>*ptrz) {
 1.20982 +              *ptrz = zleft;
 1.20983 +              const float invz = 1/zleft;
 1.20984 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20985 +              cimg_forV(*this,k) {
 1.20986 +                *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
 1.20987 +                ptrd+=whz; col+=twhz;
 1.20988 +              }
 1.20989 +              ptrd-=offx;
 1.20990 +            }
 1.20991 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.20992 +          } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.20993 +            if (zleft>*ptrz) {
 1.20994 +              *ptrz = zleft;
 1.20995 +              const float invz = 1/zleft;
 1.20996 +              const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.20997 +              cimg_forV(*this,k) {
 1.20998 +                const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
 1.20999 +                *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21000 +                ptrd+=whz; col+=twhz;
 1.21001 +              }
 1.21002 +              ptrd-=offx;
 1.21003 +            }
 1.21004 +            zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21005 +          }
 1.21006 +        }
 1.21007 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.21008 +      }
 1.21009 +      return *this;
 1.21010 +    }
 1.21011 +
 1.21012 +    //! Draw a 2D Pseudo-Phong-shaded triangle.
 1.21013 +    /**
 1.21014 +       \param x0 = X-coordinate of the first corner in the instance image.
 1.21015 +       \param y0 = Y-coordinate of the first corner in the instance image.
 1.21016 +       \param x1 = X-coordinate of the second corner in the instance image.
 1.21017 +       \param y1 = Y-coordinate of the second corner in the instance image.
 1.21018 +       \param x2 = X-coordinate of the third corner in the instance image.
 1.21019 +       \param y2 = Y-coordinate of the third corner in the instance image.
 1.21020 +       \param color = array of dimv() values of type \c T, defining the global drawing color.
 1.21021 +       \param light = light image.
 1.21022 +       \param lx0 = X-coordinate of the first corner in the light image.
 1.21023 +       \param ly0 = Y-coordinate of the first corner in the light image.
 1.21024 +       \param lx1 = X-coordinate of the second corner in the light image.
 1.21025 +       \param ly1 = Y-coordinate of the second corner in the light image.
 1.21026 +       \param lx2 = X-coordinate of the third corner in the light image.
 1.21027 +       \param ly2 = Y-coordinate of the third corner in the light image.
 1.21028 +       \param opacity = opacity of the drawing.
 1.21029 +       \note Clipping is supported, but texture coordinates do not support clipping.
 1.21030 +    **/
 1.21031 +    template<typename tc, typename tl>
 1.21032 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.21033 +                           const int x1, const int y1,
 1.21034 +                           const int x2, const int y2,
 1.21035 +                           const tc *const color,
 1.21036 +                           const CImg<tl>& light,
 1.21037 +                           const int lx0, const int ly0,
 1.21038 +                           const int lx1, const int ly1,
 1.21039 +                           const int lx2, const int ly2,
 1.21040 +                           const float opacity=1) {
 1.21041 +      if (is_empty()) return *this;
 1.21042 +      if (!color)
 1.21043 +        throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
 1.21044 +                                    pixel_type());
 1.21045 +      if (!light)
 1.21046 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 1.21047 +                                    pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 1.21048 +      if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21049 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21050 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21051 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21052 +        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 1.21053 +      const int whz = width*height*depth, offx = dim*whz-1;
 1.21054 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
 1.21055 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
 1.21056 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
 1.21057 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21058 +      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 1.21059 +                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 1.21060 +        int
 1.21061 +          xleft = xleft0, xright = xright0,
 1.21062 +          lxleft = lxleft0, lxright = lxright0,
 1.21063 +          lyleft = lyleft0, lyright = lyright0;
 1.21064 +        if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
 1.21065 +        const int
 1.21066 +          dx = xright - xleft,
 1.21067 +          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 1.21068 +          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 1.21069 +          rlx = dx?(lxright - lxleft)/dx:0,
 1.21070 +          rly = dx?(lyright - lyleft)/dx:0,
 1.21071 +          slx = lxright>lxleft?1:-1,
 1.21072 +          sly = lyright>lyleft?1:-1,
 1.21073 +          ndlx = dlx - (dx?dx*(dlx/dx):0),
 1.21074 +          ndly = dly - (dx?dx*(dly/dx):0);
 1.21075 +        int errlx = dx>>1, errly = errlx;
 1.21076 +        if (xleft<0 && dx) {
 1.21077 +          lxleft-=xleft*(lxright - lxleft)/dx;
 1.21078 +          lyleft-=xleft*(lyright - lyleft)/dx;
 1.21079 +        }
 1.21080 +        if (xleft<0) xleft = 0;
 1.21081 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21082 +        T* ptrd = ptr(xleft,y,0,0);
 1.21083 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.21084 +          const tl l = light(lxleft,lyleft);
 1.21085 +          const tc *col = color;
 1.21086 +          cimg_forV(*this,k) {
 1.21087 +            *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
 1.21088 +            ptrd+=whz;
 1.21089 +          }
 1.21090 +          ptrd-=offx;
 1.21091 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21092 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21093 +        } else  for (int x = xleft; x<=xright; ++x) {
 1.21094 +          const tl l = light(lxleft,lyleft);
 1.21095 +          const tc *col = color;
 1.21096 +          cimg_forV(*this,k) {
 1.21097 +            const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
 1.21098 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21099 +            ptrd+=whz;
 1.21100 +          }
 1.21101 +          ptrd-=offx;
 1.21102 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21103 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21104 +        }
 1.21105 +      }
 1.21106 +      return *this;
 1.21107 +    }
 1.21108 +
 1.21109 +    //! Draw a 2D Pseudo-Phong-shaded triangle.
 1.21110 +    template<typename tc, typename tl>
 1.21111 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.21112 +                           const int x1, const int y1,
 1.21113 +                           const int x2, const int y2,
 1.21114 +                           const CImg<tc>& color,
 1.21115 +                           const CImg<tl>& light,
 1.21116 +                           const int lx0, const int ly0,
 1.21117 +                           const int lx1, const int ly1,
 1.21118 +                           const int lx2, const int ly2,
 1.21119 +                           const float opacity=1) {
 1.21120 +      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21121 +    }
 1.21122 +
 1.21123 +    //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
 1.21124 +    template<typename tc, typename tl>
 1.21125 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.21126 +                           const int x0, const int y0, const float z0,
 1.21127 +                           const int x1, const int y1, const float z1,
 1.21128 +                           const int x2, const int y2, const float z2,
 1.21129 +                           const tc *const color,
 1.21130 +                           const CImg<tl>& light,
 1.21131 +                           const int lx0, const int ly0,
 1.21132 +                           const int lx1, const int ly1,
 1.21133 +                           const int lx2, const int ly2,
 1.21134 +                           const float opacity=1) {
 1.21135 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.21136 +      if (!color)
 1.21137 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
 1.21138 +                                    pixel_type());
 1.21139 +      if (!light)
 1.21140 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 1.21141 +                                    pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 1.21142 +      if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
 1.21143 +                                                     +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21144 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21145 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21146 +      const int whz = width*height*depth, offx = dim*whz;
 1.21147 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21148 +        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 1.21149 +      float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.21150 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 1.21151 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 1.21152 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 1.21153 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21154 +      float
 1.21155 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.21156 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.21157 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.21158 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.21159 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
 1.21160 +      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 1.21161 +                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 1.21162 +        if (y==ny1) { zl = nz1; pzl = pzn; }
 1.21163 +        int
 1.21164 +          xleft = xleft0, xright = xright0,
 1.21165 +          lxleft = lxleft0, lxright = lxright0,
 1.21166 +          lyleft = lyleft0, lyright = lyright0;
 1.21167 +        float zleft = zl, zright = zr;
 1.21168 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
 1.21169 +        const int
 1.21170 +          dx = xright - xleft,
 1.21171 +          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 1.21172 +          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 1.21173 +          rlx = dx?(lxright - lxleft)/dx:0,
 1.21174 +          rly = dx?(lyright - lyleft)/dx:0,
 1.21175 +          slx = lxright>lxleft?1:-1,
 1.21176 +          sly = lyright>lyleft?1:-1,
 1.21177 +          ndlx = dlx - (dx?dx*(dlx/dx):0),
 1.21178 +          ndly = dly - (dx?dx*(dly/dx):0);
 1.21179 +        const float pentez = (zright - zleft)/dx;
 1.21180 +        int errlx = dx>>1, errly = errlx;
 1.21181 +        if (xleft<0 && dx) {
 1.21182 +          zleft-=xleft*(zright - zleft)/dx;
 1.21183 +          lxleft-=xleft*(lxright - lxleft)/dx;
 1.21184 +          lyleft-=xleft*(lyright - lyleft)/dx;
 1.21185 +        }
 1.21186 +        if (xleft<0) xleft = 0;
 1.21187 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21188 +        T *ptrd = ptr(xleft,y,0,0);
 1.21189 +        float *ptrz = zbuffer + xleft + y*width;
 1.21190 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.21191 +          if (zleft>*ptrz) {
 1.21192 +            *ptrz = zleft;
 1.21193 +            const tl l = light(lxleft,lyleft);
 1.21194 +            const tc *col = color;
 1.21195 +            cimg_forV(*this,k) {
 1.21196 +              const tc cval = *(col++);
 1.21197 +              *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
 1.21198 +              ptrd+=whz;
 1.21199 +            }
 1.21200 +            ptrd-=offx;
 1.21201 +          }
 1.21202 +          zleft+=pentez;
 1.21203 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21204 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21205 +        } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.21206 +          if (zleft>*ptrz) {
 1.21207 +            *ptrz = zleft;
 1.21208 +            const tl l = light(lxleft,lyleft);
 1.21209 +            const tc *col = color;
 1.21210 +            cimg_forV(*this,k) {
 1.21211 +              const tc cval = *(col++);
 1.21212 +              const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
 1.21213 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21214 +              ptrd+=whz;
 1.21215 +            }
 1.21216 +            ptrd-=offx;
 1.21217 +          }
 1.21218 +          zleft+=pentez;
 1.21219 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21220 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21221 +        }
 1.21222 +        zr+=pzr; zl+=pzl;
 1.21223 +      }
 1.21224 +      return *this;
 1.21225 +    }
 1.21226 +
 1.21227 +    //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
 1.21228 +    template<typename tc, typename tl>
 1.21229 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.21230 +                           const int x0, const int y0, const float z0,
 1.21231 +                           const int x1, const int y1, const float z1,
 1.21232 +                           const int x2, const int y2, const float z2,
 1.21233 +                           const CImg<tc>& color,
 1.21234 +                           const CImg<tl>& light,
 1.21235 +                           const int lx0, const int ly0,
 1.21236 +                           const int lx1, const int ly1,
 1.21237 +                           const int lx2, const int ly2,
 1.21238 +                           const float opacity=1) {
 1.21239 +      return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21240 +    }
 1.21241 +
 1.21242 +    //! Draw a 2D Gouraud-shaded textured triangle.
 1.21243 +    /**
 1.21244 +       \param x0 = X-coordinate of the first corner in the instance image.
 1.21245 +       \param y0 = Y-coordinate of the first corner in the instance image.
 1.21246 +       \param x1 = X-coordinate of the second corner in the instance image.
 1.21247 +       \param y1 = Y-coordinate of the second corner in the instance image.
 1.21248 +       \param x2 = X-coordinate of the third corner in the instance image.
 1.21249 +       \param y2 = Y-coordinate of the third corner in the instance image.
 1.21250 +       \param texture = texture image used to fill the triangle.
 1.21251 +       \param tx0 = X-coordinate of the first corner in the texture image.
 1.21252 +       \param ty0 = Y-coordinate of the first corner in the texture image.
 1.21253 +       \param tx1 = X-coordinate of the second corner in the texture image.
 1.21254 +       \param ty1 = Y-coordinate of the second corner in the texture image.
 1.21255 +       \param tx2 = X-coordinate of the third corner in the texture image.
 1.21256 +       \param ty2 = Y-coordinate of the third corner in the texture image.
 1.21257 +       \param brightness0 = brightness value of the first corner.
 1.21258 +       \param brightness1 = brightness value of the second corner.
 1.21259 +       \param brightness2 = brightness value of the third corner.
 1.21260 +       \param opacity = opacity of the drawing.
 1.21261 +       \note Clipping is supported, but texture coordinates do not support clipping.
 1.21262 +    **/
 1.21263 +    template<typename tc>
 1.21264 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.21265 +                           const int x1, const int y1,
 1.21266 +                           const int x2, const int y2,
 1.21267 +                           const CImg<tc>& texture,
 1.21268 +                           const int tx0, const int ty0,
 1.21269 +                           const int tx1, const int ty1,
 1.21270 +                           const int tx2, const int ty2,
 1.21271 +                           const float brightness0,
 1.21272 +                           const float brightness1,
 1.21273 +                           const float brightness2,
 1.21274 +                           const float opacity=1) {
 1.21275 +      if (is_empty()) return *this;
 1.21276 +      if (!texture || texture.dim<dim)
 1.21277 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21278 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21279 +      if (is_overlapped(texture))
 1.21280 +        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
 1.21281 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21282 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21283 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.21284 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21285 +        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
 1.21286 +        nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 1.21287 +        nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 1.21288 +        nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 1.21289 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
 1.21290 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
 1.21291 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
 1.21292 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21293 +      _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
 1.21294 +                          nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
 1.21295 +        int
 1.21296 +          xleft = xleft0, xright = xright0,
 1.21297 +          cleft = cleft0, cright = cright0,
 1.21298 +          txleft = txleft0, txright = txright0,
 1.21299 +          tyleft = tyleft0, tyright = tyright0;
 1.21300 +        if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
 1.21301 +        const int
 1.21302 +          dx = xright - xleft,
 1.21303 +          dc = cright>cleft?cright - cleft:cleft - cright,
 1.21304 +          dtx = txright>txleft?txright - txleft:txleft - txright,
 1.21305 +          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 1.21306 +          rc = dx?(cright - cleft)/dx:0,
 1.21307 +          rtx = dx?(txright - txleft)/dx:0,
 1.21308 +          rty = dx?(tyright - tyleft)/dx:0,
 1.21309 +          sc = cright>cleft?1:-1,
 1.21310 +          stx = txright>txleft?1:-1,
 1.21311 +          sty = tyright>tyleft?1:-1,
 1.21312 +          ndc = dc - (dx?dx*(dc/dx):0),
 1.21313 +          ndtx = dtx - (dx?dx*(dtx/dx):0),
 1.21314 +          ndty = dty - (dx?dx*(dty/dx):0);
 1.21315 +        int errc = dx>>1, errtx = errc, errty = errc;
 1.21316 +        if (xleft<0 && dx) {
 1.21317 +          cleft-=xleft*(cright - cleft)/dx;
 1.21318 +          txleft-=xleft*(txright - txleft)/dx;
 1.21319 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21320 +        }
 1.21321 +        if (xleft<0) xleft = 0;
 1.21322 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21323 +        T* ptrd = ptr(xleft,y,0,0);
 1.21324 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.21325 +          const tc *col = texture.ptr(txleft,tyleft);
 1.21326 +          cimg_forV(*this,k) {
 1.21327 +            *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21328 +            ptrd+=whz; col+=twhz;
 1.21329 +          }
 1.21330 +          ptrd-=offx;
 1.21331 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21332 +          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.21333 +          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.21334 +        } else for (int x = xleft; x<=xright; ++x) {
 1.21335 +          const tc *col = texture.ptr(txleft,tyleft);
 1.21336 +          cimg_forV(*this,k) {
 1.21337 +            const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21338 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21339 +            ptrd+=whz; col+=twhz;
 1.21340 +          }
 1.21341 +          ptrd-=offx;
 1.21342 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21343 +          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.21344 +          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.21345 +        }
 1.21346 +      }
 1.21347 +      return *this;
 1.21348 +    }
 1.21349 +
 1.21350 +    //! Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
 1.21351 +    template<typename tc>
 1.21352 +    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 1.21353 +                           const int x1, const int y1, const float z1,
 1.21354 +                           const int x2, const int y2, const float z2,
 1.21355 +                           const CImg<tc>& texture,
 1.21356 +                           const int tx0, const int ty0,
 1.21357 +                           const int tx1, const int ty1,
 1.21358 +                           const int tx2, const int ty2,
 1.21359 +                           const float brightness0,
 1.21360 +                           const float brightness1,
 1.21361 +                           const float brightness2,
 1.21362 +                           const float opacity=1) {
 1.21363 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.21364 +      if (!texture || texture.dim<dim)
 1.21365 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21366 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21367 +      if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
 1.21368 +                                                       brightness0,brightness1,brightness2,opacity);
 1.21369 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21370 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21371 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.21372 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21373 +        nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 1.21374 +        nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 1.21375 +        nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 1.21376 +      float
 1.21377 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.21378 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.21379 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.21380 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.21381 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
 1.21382 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
 1.21383 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
 1.21384 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21385 +      float
 1.21386 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.21387 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.21388 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.21389 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.21390 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.21391 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.21392 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.21393 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.21394 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.21395 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.21396 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.21397 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.21398 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.21399 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.21400 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.21401 +      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 1.21402 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.21403 +        int
 1.21404 +          xleft = xleft0, xright = xright0,
 1.21405 +          cleft = cleft0, cright = cright0;
 1.21406 +        float
 1.21407 +          zleft = zl, zright = zr,
 1.21408 +          txleft = txl, txright = txr,
 1.21409 +          tyleft = tyl, tyright = tyr;
 1.21410 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
 1.21411 +        const int
 1.21412 +          dx = xright - xleft,
 1.21413 +          dc = cright>cleft?cright - cleft:cleft - cright,
 1.21414 +          rc = dx?(cright - cleft)/dx:0,
 1.21415 +          sc = cright>cleft?1:-1,
 1.21416 +          ndc = dc - (dx?dx*(dc/dx):0);
 1.21417 +        const float
 1.21418 +          pentez = (zright - zleft)/dx,
 1.21419 +          pentetx = (txright - txleft)/dx,
 1.21420 +          pentety = (tyright - tyleft)/dx;
 1.21421 +        int errc = dx>>1;
 1.21422 +        if (xleft<0 && dx) {
 1.21423 +          cleft-=xleft*(cright - cleft)/dx;
 1.21424 +          zleft-=xleft*(zright - zleft)/dx;
 1.21425 +          txleft-=xleft*(txright - txleft)/dx;
 1.21426 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21427 +        }
 1.21428 +        if (xleft<0) xleft = 0;
 1.21429 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21430 +        T* ptrd = ptr(xleft,y,0,0);
 1.21431 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.21432 +          const float invz = 1/zleft;
 1.21433 +          const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21434 +          cimg_forV(*this,k) {
 1.21435 +            *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21436 +            ptrd+=whz; col+=twhz;
 1.21437 +          }
 1.21438 +          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21439 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21440 +        } else for (int x = xleft; x<=xright; ++x) {
 1.21441 +          const float invz = 1/zleft;
 1.21442 +          const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21443 +          cimg_forV(*this,k) {
 1.21444 +            const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21445 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21446 +            ptrd+=whz; col+=twhz;
 1.21447 +          }
 1.21448 +          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21449 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21450 +        }
 1.21451 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.21452 +      }
 1.21453 +      return *this;
 1.21454 +    }
 1.21455 +
 1.21456 +    //! Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
 1.21457 +    template<typename tc>
 1.21458 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.21459 +                           const int x0, const int y0, const float z0,
 1.21460 +                           const int x1, const int y1, const float z1,
 1.21461 +                           const int x2, const int y2, const float z2,
 1.21462 +                           const CImg<tc>& texture,
 1.21463 +                           const int tx0, const int ty0,
 1.21464 +                           const int tx1, const int ty1,
 1.21465 +                           const int tx2, const int ty2,
 1.21466 +                           const float brightness0,
 1.21467 +                           const float brightness1,
 1.21468 +                           const float brightness2,
 1.21469 +                           const float opacity=1) {
 1.21470 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.21471 +      if (!texture || texture.dim<dim)
 1.21472 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21473 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21474 +      if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
 1.21475 +                                                       brightness0,brightness1,brightness2,opacity);
 1.21476 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21477 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21478 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 1.21479 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21480 +        nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 1.21481 +        nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 1.21482 +        nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
 1.21483 +      float
 1.21484 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.21485 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.21486 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.21487 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.21488 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
 1.21489 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
 1.21490 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
 1.21491 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21492 +      float
 1.21493 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.21494 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.21495 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.21496 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.21497 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.21498 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.21499 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.21500 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.21501 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.21502 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.21503 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.21504 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.21505 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.21506 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.21507 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.21508 +      _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
 1.21509 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.21510 +        int
 1.21511 +          xleft = xleft0, xright = xright0,
 1.21512 +          cleft = cleft0, cright = cright0;
 1.21513 +        float
 1.21514 +          zleft = zl, zright = zr,
 1.21515 +          txleft = txl, txright = txr,
 1.21516 +          tyleft = tyl, tyright = tyr;
 1.21517 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
 1.21518 +        const int
 1.21519 +          dx = xright - xleft,
 1.21520 +          dc = cright>cleft?cright - cleft:cleft - cright,
 1.21521 +          rc = dx?(cright - cleft)/dx:0,
 1.21522 +          sc = cright>cleft?1:-1,
 1.21523 +          ndc = dc - (dx?dx*(dc/dx):0);
 1.21524 +        const float
 1.21525 +          pentez = (zright - zleft)/dx,
 1.21526 +          pentetx = (txright - txleft)/dx,
 1.21527 +          pentety = (tyright - tyleft)/dx;
 1.21528 +        int errc = dx>>1;
 1.21529 +        if (xleft<0 && dx) {
 1.21530 +          cleft-=xleft*(cright - cleft)/dx;
 1.21531 +          zleft-=xleft*(zright - zleft)/dx;
 1.21532 +          txleft-=xleft*(txright - txleft)/dx;
 1.21533 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21534 +        }
 1.21535 +        if (xleft<0) xleft = 0;
 1.21536 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21537 +        T* ptrd = ptr(xleft,y);
 1.21538 +        float *ptrz = zbuffer + xleft + y*width;
 1.21539 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 1.21540 +          if (zleft>*ptrz) {
 1.21541 +            *ptrz = zleft;
 1.21542 +            const float invz = 1/zleft;
 1.21543 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21544 +            cimg_forV(*this,k) {
 1.21545 +              *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21546 +              ptrd+=whz; col+=twhz;
 1.21547 +            }
 1.21548 +            ptrd-=offx;
 1.21549 +          }
 1.21550 +          zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21551 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21552 +        } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
 1.21553 +          if (zleft>*ptrz) {
 1.21554 +            *ptrz = zleft;
 1.21555 +            const float invz = 1/zleft;
 1.21556 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21557 +            cimg_forV(*this,k) {
 1.21558 +              const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 1.21559 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21560 +              ptrd+=whz; col+=twhz;
 1.21561 +            }
 1.21562 +            ptrd-=offx;
 1.21563 +          }
 1.21564 +          zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21565 +          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
 1.21566 +        }
 1.21567 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.21568 +      }
 1.21569 +      return *this;
 1.21570 +    }
 1.21571 +
 1.21572 +    //! Draw a 2D Pseudo-Phong-shaded textured triangle.
 1.21573 +    /**
 1.21574 +       \param x0 = X-coordinate of the first corner in the instance image.
 1.21575 +       \param y0 = Y-coordinate of the first corner in the instance image.
 1.21576 +       \param x1 = X-coordinate of the second corner in the instance image.
 1.21577 +       \param y1 = Y-coordinate of the second corner in the instance image.
 1.21578 +       \param x2 = X-coordinate of the third corner in the instance image.
 1.21579 +       \param y2 = Y-coordinate of the third corner in the instance image.
 1.21580 +       \param texture = texture image used to fill the triangle.
 1.21581 +       \param tx0 = X-coordinate of the first corner in the texture image.
 1.21582 +       \param ty0 = Y-coordinate of the first corner in the texture image.
 1.21583 +       \param tx1 = X-coordinate of the second corner in the texture image.
 1.21584 +       \param ty1 = Y-coordinate of the second corner in the texture image.
 1.21585 +       \param tx2 = X-coordinate of the third corner in the texture image.
 1.21586 +       \param ty2 = Y-coordinate of the third corner in the texture image.
 1.21587 +       \param light = light image.
 1.21588 +       \param lx0 = X-coordinate of the first corner in the light image.
 1.21589 +       \param ly0 = Y-coordinate of the first corner in the light image.
 1.21590 +       \param lx1 = X-coordinate of the second corner in the light image.
 1.21591 +       \param ly1 = Y-coordinate of the second corner in the light image.
 1.21592 +       \param lx2 = X-coordinate of the third corner in the light image.
 1.21593 +       \param ly2 = Y-coordinate of the third corner in the light image.
 1.21594 +       \param opacity = opacity of the drawing.
 1.21595 +       \note Clipping is supported, but texture coordinates do not support clipping.
 1.21596 +    **/
 1.21597 +    template<typename tc, typename tl>
 1.21598 +    CImg<T>& draw_triangle(const int x0, const int y0,
 1.21599 +                           const int x1, const int y1,
 1.21600 +                           const int x2, const int y2,
 1.21601 +                           const CImg<tc>& texture,
 1.21602 +                           const int tx0, const int ty0,
 1.21603 +                           const int tx1, const int ty1,
 1.21604 +                           const int tx2, const int ty2,
 1.21605 +                           const CImg<tl>& light,
 1.21606 +                           const int lx0, const int ly0,
 1.21607 +                           const int lx1, const int ly1,
 1.21608 +                           const int lx2, const int ly2,
 1.21609 +                           const float opacity=1) {
 1.21610 +      if (is_empty()) return *this;
 1.21611 +      if (!texture || texture.dim<dim)
 1.21612 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21613 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21614 +      if (!light)
 1.21615 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 1.21616 +                                    pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 1.21617 +      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);
 1.21618 +      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);
 1.21619 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21620 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21621 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.21622 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21623 +        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
 1.21624 +        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 1.21625 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
 1.21626 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
 1.21627 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
 1.21628 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21629 +      _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
 1.21630 +                          nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
 1.21631 +        int
 1.21632 +          xleft = xleft0, xright = xright0,
 1.21633 +          lxleft = lxleft0, lxright = lxright0,
 1.21634 +          lyleft = lyleft0, lyright = lyright0,
 1.21635 +          txleft = txleft0, txright = txright0,
 1.21636 +          tyleft = tyleft0, tyright = tyright0;
 1.21637 +        if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
 1.21638 +        const int
 1.21639 +          dx = xright - xleft,
 1.21640 +          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 1.21641 +          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 1.21642 +          dtx = txright>txleft?txright - txleft:txleft - txright,
 1.21643 +          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
 1.21644 +          rlx = dx?(lxright - lxleft)/dx:0,
 1.21645 +          rly = dx?(lyright - lyleft)/dx:0,
 1.21646 +          rtx = dx?(txright - txleft)/dx:0,
 1.21647 +          rty = dx?(tyright - tyleft)/dx:0,
 1.21648 +          slx = lxright>lxleft?1:-1,
 1.21649 +          sly = lyright>lyleft?1:-1,
 1.21650 +          stx = txright>txleft?1:-1,
 1.21651 +          sty = tyright>tyleft?1:-1,
 1.21652 +          ndlx = dlx - (dx?dx*(dlx/dx):0),
 1.21653 +          ndly = dly - (dx?dx*(dly/dx):0),
 1.21654 +          ndtx = dtx - (dx?dx*(dtx/dx):0),
 1.21655 +          ndty = dty - (dx?dx*(dty/dx):0);
 1.21656 +        int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
 1.21657 +        if (xleft<0 && dx) {
 1.21658 +          lxleft-=xleft*(lxright - lxleft)/dx;
 1.21659 +          lyleft-=xleft*(lyright - lyleft)/dx;
 1.21660 +          txleft-=xleft*(txright - txleft)/dx;
 1.21661 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21662 +        }
 1.21663 +        if (xleft<0) xleft = 0;
 1.21664 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21665 +        T* ptrd = ptr(xleft,y,0,0);
 1.21666 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.21667 +          const tl l = light(lxleft,lyleft);
 1.21668 +          const tc *col = texture.ptr(txleft,tyleft);
 1.21669 +          cimg_forV(*this,k) {
 1.21670 +            *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21671 +            ptrd+=whz; col+=twhz;
 1.21672 +          }
 1.21673 +          ptrd-=offx;
 1.21674 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21675 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21676 +          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.21677 +          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.21678 +        } else for (int x = xleft; x<=xright; ++x) {
 1.21679 +          const tl l = light(lxleft,lyleft);
 1.21680 +          const tc *col = texture.ptr(txleft,tyleft);
 1.21681 +          cimg_forV(*this,k) {
 1.21682 +            const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21683 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21684 +            ptrd+=whz; col+=twhz;
 1.21685 +          }
 1.21686 +          ptrd-=offx;
 1.21687 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21688 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21689 +          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 1.21690 +          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 1.21691 +        }
 1.21692 +      }
 1.21693 +      return *this;
 1.21694 +    }
 1.21695 +
 1.21696 +    //! Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
 1.21697 +    template<typename tc, typename tl>
 1.21698 +    CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 1.21699 +                           const int x1, const int y1, const float z1,
 1.21700 +                           const int x2, const int y2, const float z2,
 1.21701 +                           const CImg<tc>& texture,
 1.21702 +                           const int tx0, const int ty0,
 1.21703 +                           const int tx1, const int ty1,
 1.21704 +                           const int tx2, const int ty2,
 1.21705 +                           const CImg<tl>& light,
 1.21706 +                           const int lx0, const int ly0,
 1.21707 +                           const int lx1, const int ly1,
 1.21708 +                           const int lx2, const int ly2,
 1.21709 +                           const float opacity=1) {
 1.21710 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.21711 +      if (!texture || texture.dim<dim)
 1.21712 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21713 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21714 +      if (!light)
 1.21715 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 1.21716 +                                    pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 1.21717 +      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);
 1.21718 +      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);
 1.21719 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21720 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21721 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
 1.21722 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21723 +        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 1.21724 +      float
 1.21725 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.21726 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.21727 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.21728 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.21729 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 1.21730 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 1.21731 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 1.21732 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21733 +      float
 1.21734 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.21735 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.21736 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.21737 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.21738 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.21739 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.21740 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.21741 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.21742 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.21743 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.21744 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.21745 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.21746 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.21747 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.21748 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.21749 +      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 1.21750 +                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 1.21751 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.21752 +        int
 1.21753 +          xleft = xleft0, xright = xright0,
 1.21754 +          lxleft = lxleft0, lxright = lxright0,
 1.21755 +          lyleft = lyleft0, lyright = lyright0;
 1.21756 +        float
 1.21757 +          zleft = zl, zright = zr,
 1.21758 +          txleft = txl, txright = txr,
 1.21759 +          tyleft = tyl, tyright = tyr;
 1.21760 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
 1.21761 +        const int
 1.21762 +          dx = xright - xleft,
 1.21763 +          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 1.21764 +          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 1.21765 +          rlx = dx?(lxright - lxleft)/dx:0,
 1.21766 +          rly = dx?(lyright - lyleft)/dx:0,
 1.21767 +          slx = lxright>lxleft?1:-1,
 1.21768 +          sly = lyright>lyleft?1:-1,
 1.21769 +          ndlx = dlx - (dx?dx*(dlx/dx):0),
 1.21770 +          ndly = dly - (dx?dx*(dly/dx):0);
 1.21771 +        const float
 1.21772 +          pentez = (zright - zleft)/dx,
 1.21773 +          pentetx = (txright - txleft)/dx,
 1.21774 +          pentety = (tyright - tyleft)/dx;
 1.21775 +        int errlx = dx>>1, errly = errlx;
 1.21776 +        if (xleft<0 && dx) {
 1.21777 +          zleft-=xleft*(zright - zleft)/dx;
 1.21778 +          lxleft-=xleft*(lxright - lxleft)/dx;
 1.21779 +          lyleft-=xleft*(lyright - lyleft)/dx;
 1.21780 +          txleft-=xleft*(txright - txleft)/dx;
 1.21781 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21782 +        }
 1.21783 +        if (xleft<0) xleft = 0;
 1.21784 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21785 +        T* ptrd = ptr(xleft,y,0,0);
 1.21786 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
 1.21787 +          const float invz = 1/zleft;
 1.21788 +          const tl l = light(lxleft,lyleft);
 1.21789 +          const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21790 +          cimg_forV(*this,k) {
 1.21791 +            *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21792 +            ptrd+=whz; col+=twhz;
 1.21793 +          }
 1.21794 +          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21795 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21796 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21797 +        } else for (int x = xleft; x<=xright; ++x) {
 1.21798 +          const float invz = 1/zleft;
 1.21799 +          const tl l = light(lxleft,lyleft);
 1.21800 +          const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21801 +          cimg_forV(*this,k) {
 1.21802 +            const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21803 +            *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21804 +            ptrd+=whz; col+=twhz;
 1.21805 +          }
 1.21806 +          ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21807 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21808 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21809 +        }
 1.21810 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.21811 +      }
 1.21812 +      return *this;
 1.21813 +    }
 1.21814 +
 1.21815 +    //! Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction.
 1.21816 +    template<typename tc, typename tl>
 1.21817 +    CImg<T>& draw_triangle(float *const zbuffer,
 1.21818 +                           const int x0, const int y0, const float z0,
 1.21819 +                           const int x1, const int y1, const float z1,
 1.21820 +                           const int x2, const int y2, const float z2,
 1.21821 +                           const CImg<tc>& texture,
 1.21822 +                           const int tx0, const int ty0,
 1.21823 +                           const int tx1, const int ty1,
 1.21824 +                           const int tx2, const int ty2,
 1.21825 +                           const CImg<tl>& light,
 1.21826 +                           const int lx0, const int ly0,
 1.21827 +                           const int lx1, const int ly1,
 1.21828 +                           const int lx2, const int ly2,
 1.21829 +                           const float opacity=1) {
 1.21830 +      if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
 1.21831 +      if (!texture || texture.dim<dim)
 1.21832 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 1.21833 +                                    pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 1.21834 +      if (!light)
 1.21835 +        throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 1.21836 +                                    pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 1.21837 +      if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
 1.21838 +                                                       +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21839 +      if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
 1.21840 +                                                     texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 1.21841 +      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
 1.21842 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.21843 +      const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
 1.21844 +      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
 1.21845 +        nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
 1.21846 +      float
 1.21847 +        ntx0 = tx0/z0, nty0 = ty0/z0,
 1.21848 +        ntx1 = tx1/z1, nty1 = ty1/z1,
 1.21849 +        ntx2 = tx2/z2, nty2 = ty2/z2,
 1.21850 +        nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
 1.21851 +      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
 1.21852 +      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
 1.21853 +      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
 1.21854 +      if (ny0>=dimy() || ny2<0) return *this;
 1.21855 +      float
 1.21856 +        ptxl = (ntx1 - ntx0)/(ny1 - ny0),
 1.21857 +        ptxr = (ntx2 - ntx0)/(ny2 - ny0),
 1.21858 +        ptxn = (ntx2 - ntx1)/(ny2 - ny1),
 1.21859 +        ptyl = (nty1 - nty0)/(ny1 - ny0),
 1.21860 +        ptyr = (nty2 - nty0)/(ny2 - ny0),
 1.21861 +        ptyn = (nty2 - nty1)/(ny2 - ny1),
 1.21862 +        pzl = (nz1 - nz0)/(ny1 - ny0),
 1.21863 +        pzr = (nz2 - nz0)/(ny2 - ny0),
 1.21864 +        pzn = (nz2 - nz1)/(ny2 - ny1),
 1.21865 +        zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
 1.21866 +        txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
 1.21867 +        tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
 1.21868 +        zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
 1.21869 +        txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
 1.21870 +        tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
 1.21871 +      _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
 1.21872 +                          nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
 1.21873 +        if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
 1.21874 +        int
 1.21875 +          xleft = xleft0, xright = xright0,
 1.21876 +          lxleft = lxleft0, lxright = lxright0,
 1.21877 +          lyleft = lyleft0, lyright = lyright0;
 1.21878 +        float
 1.21879 +          zleft = zl, zright = zr,
 1.21880 +          txleft = txl, txright = txr,
 1.21881 +          tyleft = tyl, tyright = tyr;
 1.21882 +        if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
 1.21883 +        const int
 1.21884 +          dx = xright - xleft,
 1.21885 +          dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
 1.21886 +          dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
 1.21887 +          rlx = dx?(lxright - lxleft)/dx:0,
 1.21888 +          rly = dx?(lyright - lyleft)/dx:0,
 1.21889 +          slx = lxright>lxleft?1:-1,
 1.21890 +          sly = lyright>lyleft?1:-1,
 1.21891 +          ndlx = dlx - (dx?dx*(dlx/dx):0),
 1.21892 +          ndly = dly - (dx?dx*(dly/dx):0);
 1.21893 +        const float
 1.21894 +          pentez = (zright - zleft)/dx,
 1.21895 +          pentetx = (txright - txleft)/dx,
 1.21896 +          pentety = (tyright - tyleft)/dx;
 1.21897 +        int errlx = dx>>1, errly = errlx;
 1.21898 +        if (xleft<0 && dx) {
 1.21899 +          zleft-=xleft*(zright - zleft)/dx;
 1.21900 +          lxleft-=xleft*(lxright - lxleft)/dx;
 1.21901 +          lyleft-=xleft*(lyright - lyleft)/dx;
 1.21902 +          txleft-=xleft*(txright - txleft)/dx;
 1.21903 +          tyleft-=xleft*(tyright - tyleft)/dx;
 1.21904 +        }
 1.21905 +        if (xleft<0) xleft = 0;
 1.21906 +        if (xright>=dimx()-1) xright = dimx()-1;
 1.21907 +        T* ptrd = ptr(xleft,y);
 1.21908 +        float *ptrz = zbuffer + xleft + y*width;
 1.21909 +        if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.21910 +          if (zleft>*ptrz) {
 1.21911 +            *ptrz = zleft;
 1.21912 +            const float invz = 1/zleft;
 1.21913 +            const tl l = light(lxleft,lyleft);
 1.21914 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21915 +            cimg_forV(*this,k) {
 1.21916 +              *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21917 +              ptrd+=whz; col+=twhz;
 1.21918 +            }
 1.21919 +            ptrd-=offx;
 1.21920 +          }
 1.21921 +          zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21922 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21923 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21924 +        } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
 1.21925 +          if (zleft>*ptrz) {
 1.21926 +            *ptrz = zleft;
 1.21927 +            const float invz = 1/zleft;
 1.21928 +            const tl l = light(lxleft,lyleft);
 1.21929 +            const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 1.21930 +            cimg_forV(*this,k) {
 1.21931 +              const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 1.21932 +              *ptrd = (T)(nopacity*val + *ptrd*copacity);
 1.21933 +              ptrd+=whz; col+=twhz;
 1.21934 +            }
 1.21935 +            ptrd-=offx;
 1.21936 +          }
 1.21937 +          zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 1.21938 +          lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
 1.21939 +          lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
 1.21940 +        }
 1.21941 +        zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
 1.21942 +      }
 1.21943 +      return *this;
 1.21944 +    }
 1.21945 +
 1.21946 +    // Draw a 2D ellipse (inner routine).
 1.21947 +    template<typename tc>
 1.21948 +    CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 1.21949 +                           const tc *const color, const float opacity,
 1.21950 +                           const unsigned int pattern) {
 1.21951 +      if (is_empty()) return *this;
 1.21952 +      if (!color)
 1.21953 +        throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
 1.21954 +                                    pixel_type());
 1.21955 +      _draw_scanline(color,opacity);
 1.21956 +      const float
 1.21957 +        nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
 1.21958 +        norm = (float)cimg_std::sqrt(ru*ru+rv*rv),
 1.21959 +        u = norm>0?ru/norm:1,
 1.21960 +        v = norm>0?rv/norm:0,
 1.21961 +        rmax = cimg::max(nr1,nr2),
 1.21962 +        l1 = (float)cimg_std::pow(rmax/(nr1>0?nr1:1e-6),2),
 1.21963 +        l2 = (float)cimg_std::pow(rmax/(nr2>0?nr2:1e-6),2),
 1.21964 +        a = l1*u*u + l2*v*v,
 1.21965 +        b = u*v*(l1-l2),
 1.21966 +        c = l1*v*v + l2*u*u;
 1.21967 +      const int
 1.21968 +        yb = (int)cimg_std::sqrt(a*rmax*rmax/(a*c-b*b)),
 1.21969 +        tymin = y0 - yb - 1,
 1.21970 +        tymax = y0 + yb + 1,
 1.21971 +        ymin = tymin<0?0:tymin,
 1.21972 +        ymax = tymax>=dimy()?height-1:tymax;
 1.21973 +      int oxmin = 0, oxmax = 0;
 1.21974 +      bool first_line = true;
 1.21975 +      for (int y = ymin; y<=ymax; ++y) {
 1.21976 +        const float
 1.21977 +          Y = y-y0 + (y<y0?0.5f:-0.5f),
 1.21978 +          delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
 1.21979 +          sdelta = delta>0?(float)cimg_std::sqrt(delta)/a:0.0f,
 1.21980 +          bY = b*Y/a,
 1.21981 +          fxmin = x0-0.5f-bY-sdelta,
 1.21982 +          fxmax = x0+0.5f-bY+sdelta;
 1.21983 +        const int xmin = (int)fxmin, xmax = (int)fxmax;
 1.21984 +        if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
 1.21985 +        else {
 1.21986 +          if (first_line) {
 1.21987 +            if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
 1.21988 +            else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
 1.21989 +            first_line = false;
 1.21990 +          } else {
 1.21991 +            if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
 1.21992 +            else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
 1.21993 +            if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
 1.21994 +            else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
 1.21995 +            if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
 1.21996 +          }
 1.21997 +        }
 1.21998 +        oxmin = xmin; oxmax = xmax;
 1.21999 +      }
 1.22000 +      return *this;
 1.22001 +    }
 1.22002 +
 1.22003 +    //! Draw a filled ellipse.
 1.22004 +    /**
 1.22005 +       \param x0 = X-coordinate of the ellipse center.
 1.22006 +       \param y0 = Y-coordinate of the ellipse center.
 1.22007 +       \param r1 = First radius of the ellipse.
 1.22008 +       \param r2 = Second radius of the ellipse.
 1.22009 +       \param ru = X-coordinate of the orientation vector related to the first radius.
 1.22010 +       \param rv = Y-coordinate of the orientation vector related to the first radius.
 1.22011 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.22012 +       \param opacity = opacity of the drawing.
 1.22013 +    **/
 1.22014 +    template<typename tc>
 1.22015 +    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 1.22016 +                          const tc *const color, const float opacity=1) {
 1.22017 +      return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
 1.22018 +    }
 1.22019 +
 1.22020 +    //! Draw a filled ellipse.
 1.22021 +    template<typename tc>
 1.22022 +    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 1.22023 +                          const CImg<tc>& color, const float opacity=1) {
 1.22024 +      return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
 1.22025 +    }
 1.22026 +
 1.22027 +    //! Draw a filled ellipse.
 1.22028 +    /**
 1.22029 +       \param x0 = X-coordinate of the ellipse center.
 1.22030 +       \param y0 = Y-coordinate of the ellipse center.
 1.22031 +       \param tensor = Diffusion tensor describing the ellipse.
 1.22032 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.22033 +       \param opacity = opacity of the drawing.
 1.22034 +    **/
 1.22035 +    template<typename t, typename tc>
 1.22036 +    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 1.22037 +                          const tc *const color, const float opacity=1) {
 1.22038 +      CImgList<t> eig = tensor.get_symmetric_eigen();
 1.22039 +      const CImg<t> &val = eig[0], &vec = eig[1];
 1.22040 +      return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
 1.22041 +    }
 1.22042 +
 1.22043 +    //! Draw a filled ellipse.
 1.22044 +    template<typename t, typename tc>
 1.22045 +    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 1.22046 +                          const CImg<tc>& color, const float opacity=1) {
 1.22047 +      return draw_ellipse(x0,y0,tensor,color.data,opacity);
 1.22048 +    }
 1.22049 +
 1.22050 +    //! Draw an outlined ellipse.
 1.22051 +    /**
 1.22052 +       \param x0 = X-coordinate of the ellipse center.
 1.22053 +       \param y0 = Y-coordinate of the ellipse center.
 1.22054 +       \param r1 = First radius of the ellipse.
 1.22055 +       \param r2 = Second radius of the ellipse.
 1.22056 +       \param ru = X-coordinate of the orientation vector related to the first radius.
 1.22057 +       \param rv = Y-coordinate of the orientation vector related to the first radius.
 1.22058 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.22059 +       \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
 1.22060 +       \param opacity = opacity of the drawing.
 1.22061 +    **/
 1.22062 +    template<typename tc>
 1.22063 +    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 1.22064 +                          const tc *const color, const float opacity,
 1.22065 +                          const unsigned int pattern) {
 1.22066 +      if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
 1.22067 +      return *this;
 1.22068 +    }
 1.22069 +
 1.22070 +    //! Draw an outlined ellipse.
 1.22071 +    template<typename tc>
 1.22072 +    CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 1.22073 +                          const CImg<tc>& color, const float opacity,
 1.22074 +                          const unsigned int pattern) {
 1.22075 +      return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
 1.22076 +    }
 1.22077 +
 1.22078 +    //! Draw an outlined ellipse.
 1.22079 +    /**
 1.22080 +       \param x0 = X-coordinate of the ellipse center.
 1.22081 +       \param y0 = Y-coordinate of the ellipse center.
 1.22082 +       \param tensor = Diffusion tensor describing the ellipse.
 1.22083 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.22084 +       \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
 1.22085 +       \param opacity = opacity of the drawing.
 1.22086 +    **/
 1.22087 +    template<typename t, typename tc>
 1.22088 +    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 1.22089 +                          const tc *const color, const float opacity,
 1.22090 +                          const unsigned int pattern) {
 1.22091 +      CImgList<t> eig = tensor.get_symmetric_eigen();
 1.22092 +      const CImg<t> &val = eig[0], &vec = eig[1];
 1.22093 +      return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
 1.22094 +    }
 1.22095 +
 1.22096 +    //! Draw an outlined ellipse.
 1.22097 +    template<typename t, typename tc>
 1.22098 +    CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 1.22099 +                          const CImg<tc>& color, const float opacity,
 1.22100 +                          const unsigned int pattern) {
 1.22101 +      return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
 1.22102 +    }
 1.22103 +
 1.22104 +    //! Draw a filled circle.
 1.22105 +    /**
 1.22106 +       \param x0 X-coordinate of the circle center.
 1.22107 +       \param y0 Y-coordinate of the circle center.
 1.22108 +       \param radius  Circle radius.
 1.22109 +       \param color Array of dimv() values of type \c T, defining the drawing color.
 1.22110 +       \param opacity Drawing opacity.
 1.22111 +       \note
 1.22112 +       - Circle version of the Bresenham's algorithm is used.
 1.22113 +    **/
 1.22114 +    template<typename tc>
 1.22115 +    CImg<T>& draw_circle(const int x0, const int y0, int radius,
 1.22116 +                         const tc *const color, const float opacity=1) {
 1.22117 +      if (!is_empty()) {
 1.22118 +        if (!color)
 1.22119 +          throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
 1.22120 +                                      pixel_type());
 1.22121 +        _draw_scanline(color,opacity);
 1.22122 +        if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
 1.22123 +        if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
 1.22124 +        for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
 1.22125 +          if (f>=0) {
 1.22126 +            const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
 1.22127 +            if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 1.22128 +            if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
 1.22129 +            f+=(ddFy+=2); --y;
 1.22130 +          }
 1.22131 +          const bool no_diag = y!=(x++);
 1.22132 +          ++(f+=(ddFx+=2));
 1.22133 +          const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
 1.22134 +          if (no_diag) {
 1.22135 +            if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 1.22136 +            if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
 1.22137 +          }
 1.22138 +        }
 1.22139 +      }
 1.22140 +      return *this;
 1.22141 +    }
 1.22142 +
 1.22143 +    //! Draw a filled circle.
 1.22144 +    template<typename tc>
 1.22145 +    CImg<T>& draw_circle(const int x0, const int y0, int radius,
 1.22146 +                         const CImg<tc>& color, const float opacity=1) {
 1.22147 +      return draw_circle(x0,y0,radius,color.data,opacity);
 1.22148 +    }
 1.22149 +
 1.22150 +    //! Draw an outlined circle.
 1.22151 +    /**
 1.22152 +       \param x0 X-coordinate of the circle center.
 1.22153 +       \param y0 Y-coordinate of the circle center.
 1.22154 +       \param radius Circle radius.
 1.22155 +       \param color Array of dimv() values of type \c T, defining the drawing color.
 1.22156 +       \param opacity Drawing opacity.
 1.22157 +    **/
 1.22158 +    template<typename tc>
 1.22159 +    CImg<T>& draw_circle(const int x0, const int y0, int radius,
 1.22160 +                         const tc *const color, const float opacity,
 1.22161 +                         const unsigned int) {
 1.22162 +      if (!is_empty()) {
 1.22163 +        if (!color)
 1.22164 +          throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
 1.22165 +                                      pixel_type());
 1.22166 +        if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
 1.22167 +        if (!radius) return draw_point(x0,y0,color,opacity);
 1.22168 +        draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
 1.22169 +          draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
 1.22170 +        if (radius==1) return *this;
 1.22171 +        for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
 1.22172 +          if (f>=0) { f+=(ddFy+=2); --y; }
 1.22173 +          ++x; ++(f+=(ddFx+=2));
 1.22174 +          if (x!=y+1) {
 1.22175 +            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;
 1.22176 +            draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
 1.22177 +              draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
 1.22178 +            if (x!=y)
 1.22179 +              draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
 1.22180 +                draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
 1.22181 +          }
 1.22182 +        }
 1.22183 +      }
 1.22184 +      return *this;
 1.22185 +    }
 1.22186 +
 1.22187 +    //! Draw an outlined circle.
 1.22188 +    template<typename tc>
 1.22189 +    CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
 1.22190 +                         const float opacity,
 1.22191 +                         const unsigned int pattern) {
 1.22192 +      return draw_circle(x0,y0,radius,color.data,opacity,pattern);
 1.22193 +    }
 1.22194 +
 1.22195 +    // Draw a text (internal).
 1.22196 +    template<typename tc1, typename tc2, typename t>
 1.22197 +    CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
 1.22198 +                        const tc1 *const foreground_color, const tc2 *const background_color,
 1.22199 +                        const float opacity, const CImgList<t>& font) {
 1.22200 +      if (!text) return *this;
 1.22201 +      if (!font)
 1.22202 +        throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
 1.22203 +                                    pixel_type(),font.size,font.data);
 1.22204 +      const int text_length = cimg::strlen(text);
 1.22205 +
 1.22206 +      if (is_empty()) {
 1.22207 +        // If needed, pre-compute necessary size of the image
 1.22208 +        int x = 0, y = 0, w = 0;
 1.22209 +        unsigned char c = 0;
 1.22210 +        for (int i = 0; i<text_length; ++i) {
 1.22211 +          c = text[i];
 1.22212 +          switch (c) {
 1.22213 +          case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
 1.22214 +          case '\t' : x+=4*font[' '].width; break;
 1.22215 +          default : if (c<font.size) x+=font[c].width;
 1.22216 +          }
 1.22217 +        }
 1.22218 +        if (x!=0 || c=='\n') {
 1.22219 +          if (x>w) w=x;
 1.22220 +          y+=font[' '].height;
 1.22221 +        }
 1.22222 +        assign(x0+w,y0+y,1,font[' '].dim,0);
 1.22223 +        if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
 1.22224 +      }
 1.22225 +
 1.22226 +      int x = x0, y = y0;
 1.22227 +      CImg<T> letter;
 1.22228 +      for (int i = 0; i<text_length; ++i) {
 1.22229 +        const unsigned char c = text[i];
 1.22230 +        switch (c) {
 1.22231 +        case '\n' : y+=font[' '].height; x = x0; break;
 1.22232 +        case '\t' : x+=4*font[' '].width; break;
 1.22233 +        default : if (c<font.size) {
 1.22234 +          letter = font[c];
 1.22235 +          const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
 1.22236 +          if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
 1.22237 +            if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
 1.22238 +          if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
 1.22239 +            if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
 1.22240 +          if (!background_color && font.size>=512) draw_image(x,y,letter,mask,opacity,(T)1);
 1.22241 +          else draw_image(x,y,letter,opacity);
 1.22242 +          x+=letter.width;
 1.22243 +        }
 1.22244 +        }
 1.22245 +      }
 1.22246 +      return *this;
 1.22247 +    }
 1.22248 +
 1.22249 +    //! Draw a text.
 1.22250 +    /**
 1.22251 +       \param x0 X-coordinate of the text in the instance image.
 1.22252 +       \param y0 Y-coordinate of the text in the instance image.
 1.22253 +       \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 1.22254 +       \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 1.22255 +       \param font Font used for drawing text.
 1.22256 +       \param opacity Drawing opacity.
 1.22257 +       \param format 'printf'-style format string, followed by arguments.
 1.22258 +       \note Clipping is supported.
 1.22259 +    **/
 1.22260 +    template<typename tc1, typename tc2, typename t>
 1.22261 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22262 +                       const tc1 *const foreground_color, const tc2 *const background_color,
 1.22263 +                       const float opacity, const CImgList<t>& font, ...) {
 1.22264 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 1.22265 +      cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22266 +      return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 1.22267 +    }
 1.22268 +
 1.22269 +    //! Draw a text.
 1.22270 +    template<typename tc1, typename tc2, typename t>
 1.22271 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22272 +                       const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 1.22273 +                       const float opacity, const CImgList<t>& font, ...) {
 1.22274 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 1.22275 +      cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22276 +      return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 1.22277 +    }
 1.22278 +
 1.22279 +    //! Draw a text.
 1.22280 +    template<typename tc, typename t>
 1.22281 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22282 +                       const tc *const foreground_color, const int background_color,
 1.22283 +                       const float opacity, const CImgList<t>& font, ...) {
 1.22284 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 1.22285 +      cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22286 +      return _draw_text(x0,y0,tmp,foreground_color,(tc*)background_color,opacity,font);
 1.22287 +    }
 1.22288 +
 1.22289 +    //! Draw a text.
 1.22290 +    template<typename tc, typename t>
 1.22291 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22292 +                       const int foreground_color, const tc *const background_color,
 1.22293 +                       const float opacity, const CImgList<t>& font, ...) {
 1.22294 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
 1.22295 +      cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22296 +      return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
 1.22297 +    }
 1.22298 +
 1.22299 +    //! Draw a text.
 1.22300 +    /**
 1.22301 +       \param x0 X-coordinate of the text in the instance image.
 1.22302 +       \param y0 Y-coordinate of the text in the instance image.
 1.22303 +       \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 1.22304 +       \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 1.22305 +       \param font_size Size of the font (nearest match).
 1.22306 +       \param opacity Drawing opacity.
 1.22307 +       \param format 'printf'-style format string, followed by arguments.
 1.22308 +       \note Clipping is supported.
 1.22309 +    **/
 1.22310 +    template<typename tc1, typename tc2>
 1.22311 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22312 +                       const tc1 *const foreground_color, const tc2 *const background_color,
 1.22313 +                       const float opacity=1, const unsigned int font_size=11, ...) {
 1.22314 +      static CImgList<T> font;
 1.22315 +      static unsigned int fsize = 0;
 1.22316 +      if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 1.22317 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22318 +      return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
 1.22319 +    }
 1.22320 +
 1.22321 +    //! Draw a text.
 1.22322 +    template<typename tc1, typename tc2>
 1.22323 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22324 +                       const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 1.22325 +                       const float opacity=1, const unsigned int font_size=11, ...) {
 1.22326 +      static CImgList<T> font;
 1.22327 +      static unsigned int fsize = 0;
 1.22328 +      if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 1.22329 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22330 +      return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
 1.22331 +    }
 1.22332 +
 1.22333 +    //! Draw a text.
 1.22334 +    template<typename tc>
 1.22335 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22336 +                       const tc *const foreground_color, const int background_color=0,
 1.22337 +                       const float opacity=1, const unsigned int font_size=11, ...) {
 1.22338 +      static CImgList<T> font;
 1.22339 +      static unsigned int fsize = 0;
 1.22340 +      if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 1.22341 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22342 +      return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
 1.22343 +    }
 1.22344 +
 1.22345 +    //! Draw a text.
 1.22346 +    template<typename tc>
 1.22347 +    CImg<T>& draw_text(const int x0, const int y0, const char *const text,
 1.22348 +                       const int foreground_color, const tc *const background_color,
 1.22349 +                       const float opacity=1, const unsigned int font_size=11, ...) {
 1.22350 +      static CImgList<T> font;
 1.22351 +      static unsigned int fsize = 0;
 1.22352 +      if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
 1.22353 +      char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
 1.22354 +      return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
 1.22355 +    }
 1.22356 +
 1.22357 +    //! Draw a vector field in the instance image, using a colormap.
 1.22358 +    /**
 1.22359 +       \param flow Image of 2d vectors used as input data.
 1.22360 +       \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 1.22361 +       \param sampling Length (in pixels) between each arrow.
 1.22362 +       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 1.22363 +       \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 1.22364 +       \param opacity Opacity of the drawing.
 1.22365 +       \param pattern Used pattern to draw lines.
 1.22366 +       \note Clipping is supported.
 1.22367 +    **/
 1.22368 +    template<typename t1, typename t2>
 1.22369 +    CImg<T>& draw_quiver(const CImg<t1>& flow,
 1.22370 +                         const t2 *const color, const float opacity=1,
 1.22371 +                         const unsigned int sampling=25, const float factor=-20,
 1.22372 +                         const int quiver_type=0, const unsigned int pattern=~0U) {
 1.22373 +      return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,quiver_type,pattern);
 1.22374 +    }
 1.22375 +
 1.22376 +    //! Draw a vector field in the instance image, using a colormap.
 1.22377 +    /**
 1.22378 +       \param flow Image of 2d vectors used as input data.
 1.22379 +       \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 1.22380 +       \param sampling Length (in pixels) between each arrow.
 1.22381 +       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 1.22382 +       \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 1.22383 +       \param opacity Opacity of the drawing.
 1.22384 +       \param pattern Used pattern to draw lines.
 1.22385 +       \note Clipping is supported.
 1.22386 +    **/
 1.22387 +    template<typename t1, typename t2>
 1.22388 +    CImg<T>& draw_quiver(const CImg<t1>& flow,
 1.22389 +                         const CImg<t2>& color, const float opacity=1,
 1.22390 +                         const unsigned int sampling=25, const float factor=-20,
 1.22391 +                         const int quiver_type=0, const unsigned int pattern=~0U) {
 1.22392 +      if (!is_empty()) {
 1.22393 +        if (!flow || flow.dim!=2)
 1.22394 +          throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
 1.22395 +                                      pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
 1.22396 +        if (sampling<=0)
 1.22397 +          throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
 1.22398 +                                      pixel_type(),sampling);
 1.22399 +        const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
 1.22400 +        if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,quiver_type,pattern);
 1.22401 +
 1.22402 +        float vmax,fact;
 1.22403 +        if (factor<=0) {
 1.22404 +          float m, M = (float)flow.get_pointwise_norm(2).maxmin(m);
 1.22405 +          vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
 1.22406 +          fact = -factor;
 1.22407 +        } else { fact = factor; vmax = 1; }
 1.22408 +
 1.22409 +        for (unsigned int y=sampling/2; y<height; y+=sampling)
 1.22410 +          for (unsigned int x=sampling/2; x<width; x+=sampling) {
 1.22411 +            const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
 1.22412 +            float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
 1.22413 +            if (!quiver_type) {
 1.22414 +              const int xx = x+(int)u, yy = y+(int)v;
 1.22415 +              if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
 1.22416 +              else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
 1.22417 +            } else {
 1.22418 +              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);
 1.22419 +              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);
 1.22420 +            }
 1.22421 +          }
 1.22422 +      }
 1.22423 +      return *this;
 1.22424 +    }
 1.22425 +
 1.22426 +    //! Draw a 1D graph on the instance image.
 1.22427 +    /**
 1.22428 +       \param data Image containing the graph values I = f(x).
 1.22429 +       \param color Array of dimv() values of type \c T, defining the drawing color.
 1.22430 +       \param gtype Define the type of the plot :
 1.22431 +                      - 0 = Plot using points clouds.
 1.22432 +                      - 1 = Plot using linear interpolation (segments).
 1.22433 +                      - 2 = Plot with bars.
 1.22434 +                      - 3 = Plot using cubic interpolation (3-polynomials).
 1.22435 +                      - 4 = Plot using cross clouds.
 1.22436 +       \param ymin Lower bound of the y-range.
 1.22437 +       \param ymax Upper bound of the y-range.
 1.22438 +       \param opacity Drawing opacity.
 1.22439 +       \param pattern Drawing pattern.
 1.22440 +       \note
 1.22441 +         - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
 1.22442 +    **/
 1.22443 +    template<typename t, typename tc>
 1.22444 +    CImg<T>& draw_graph(const CImg<t>& data,
 1.22445 +                        const tc *const color, const float opacity=1,
 1.22446 +                        const unsigned int plot_type=1, const unsigned int vertex_type=1,
 1.22447 +                        const double ymin=0, const double ymax=0,
 1.22448 +                        const unsigned int pattern=~0U) {
 1.22449 +      if (is_empty() || height<=1) return *this;;
 1.22450 +      const unsigned long siz = data.size();
 1.22451 +      if (!color)
 1.22452 +        throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
 1.22453 +                                    pixel_type());
 1.22454 +      tc *color1 = 0, *color2 = 0;
 1.22455 +      if (plot_type==3) {
 1.22456 +        color1 = new tc[dim]; color2 = new tc[dim];
 1.22457 +        cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
 1.22458 +      }
 1.22459 +
 1.22460 +      double m = ymin, M = ymax;
 1.22461 +      if (ymin==ymax) m = (double)data.maxmin(M);
 1.22462 +      if (m==M) { --m; ++M; }
 1.22463 +      const float ca = (float)(M-m)/(height-1);
 1.22464 +      bool init_hatch = true;
 1.22465 +
 1.22466 +      // Draw graph edges
 1.22467 +      switch (plot_type%4) {
 1.22468 +      case 1 : { // Segments
 1.22469 +        int oX = 0, oY = (int)((data[0]-m)/ca);
 1.22470 +        for (unsigned long off = 1; off<siz; ++off) {
 1.22471 +          const int
 1.22472 +            X = (int)(off*width/siz),
 1.22473 +            Y = (int)((data[off]-m)/ca);
 1.22474 +          draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
 1.22475 +          oX = X; oY = Y;
 1.22476 +          init_hatch = false;
 1.22477 +        }
 1.22478 +      } break;
 1.22479 +      case 2 : { // Spline
 1.22480 +        const CImg<t> ndata = data.get_shared_points(0,siz-1);
 1.22481 +        int oY = (int)((data[0]-m)/ca);
 1.22482 +        cimg_forX(*this,x) {
 1.22483 +          const int Y = (int)((ndata._cubic_atX((float)x*ndata.width/width)-m)/ca);
 1.22484 +          if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
 1.22485 +          init_hatch = false;
 1.22486 +          oY = Y;
 1.22487 +        }
 1.22488 +      } break;
 1.22489 +      case 3 : { // Bars
 1.22490 +        const int Y0 = (int)(-m/ca);
 1.22491 +        int oX = 0;
 1.22492 +        cimg_foroff(data,off) {
 1.22493 +          const int
 1.22494 +            X = (off+1)*width/siz-1,
 1.22495 +            Y = (int)((data[off]-m)/ca);
 1.22496 +          draw_rectangle(oX,Y0,X,Y,color1,opacity).
 1.22497 +            draw_line(oX,Y,oX,Y0,color2,opacity).
 1.22498 +            draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
 1.22499 +            draw_line(X,Y,X,Y0,color,opacity).
 1.22500 +            draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
 1.22501 +          oX = X+1;
 1.22502 +        }
 1.22503 +      } break;
 1.22504 +      default : break; // No edges
 1.22505 +      }
 1.22506 +
 1.22507 +      // Draw graph points
 1.22508 +      switch (vertex_type%8) {
 1.22509 +      case 1 : { // Point
 1.22510 +        cimg_foroff(data,off) {
 1.22511 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22512 +          draw_point(X,Y,color,opacity);
 1.22513 +        }
 1.22514 +      } break;
 1.22515 +      case 2 : { // Standard Cross
 1.22516 +        cimg_foroff(data,off) {
 1.22517 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22518 +          draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
 1.22519 +        }
 1.22520 +      } break;
 1.22521 +      case 3 : { // Rotated Cross
 1.22522 +        cimg_foroff(data,off) {
 1.22523 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22524 +          draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
 1.22525 +        }
 1.22526 +      } break;
 1.22527 +      case 4 : { // Filled Circle
 1.22528 +        cimg_foroff(data,off) {
 1.22529 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22530 +          draw_circle(X,Y,3,color,opacity);
 1.22531 +        }
 1.22532 +      } break;
 1.22533 +      case 5 : { // Outlined circle
 1.22534 +        cimg_foroff(data,off) {
 1.22535 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22536 +          draw_circle(X,Y,3,color,opacity,0U);
 1.22537 +        }
 1.22538 +      } break;
 1.22539 +      case 6 : { // Square
 1.22540 +        cimg_foroff(data,off) {
 1.22541 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22542 +          draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
 1.22543 +        }
 1.22544 +      } break;
 1.22545 +      case 7 : { // Diamond
 1.22546 +        cimg_foroff(data,off) {
 1.22547 +          const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
 1.22548 +          draw_line(X,Y-4,X+4,Y,color,opacity).
 1.22549 +            draw_line(X+4,Y,X,Y+4,color,opacity).
 1.22550 +            draw_line(X,Y+4,X-4,Y,color,opacity).
 1.22551 +            draw_line(X-4,Y,X,Y-4,color,opacity);
 1.22552 +        }
 1.22553 +      } break;
 1.22554 +      default : break; // No vertices
 1.22555 +      }
 1.22556 +
 1.22557 +      if (color1) delete[] color1; if (color2) delete[] color2;
 1.22558 +      return *this;
 1.22559 +    }
 1.22560 +
 1.22561 +    //! Draw a 1D graph on the instance image.
 1.22562 +    template<typename t, typename tc>
 1.22563 +    CImg<T>& draw_graph(const CImg<t>& data,
 1.22564 +                        const CImg<tc>& color, const float opacity=1,
 1.22565 +                        const unsigned int plot_type=1, const unsigned int vertex_type=1,
 1.22566 +                        const double ymin=0, const double ymax=0,
 1.22567 +                        const unsigned int pattern=~0U) {
 1.22568 +      return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,pattern);
 1.22569 +    }
 1.22570 +
 1.22571 +    //! Draw a labeled horizontal axis on the instance image.
 1.22572 +    /**
 1.22573 +       \param xvalues Lower bound of the x-range.
 1.22574 +       \param y Y-coordinate of the horizontal axis in the instance image.
 1.22575 +       \param color Array of dimv() values of type \c T, defining the drawing color.
 1.22576 +       \param opacity Drawing opacity.
 1.22577 +       \param pattern Drawing pattern.
 1.22578 +       \param opacity_out Drawing opacity of 'outside' axes.
 1.22579 +       \note if \c precision==0, precision of the labels is automatically computed.
 1.22580 +    **/
 1.22581 +    template<typename t, typename tc>
 1.22582 +    CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 1.22583 +                       const tc *const color, const float opacity=1,
 1.22584 +                       const unsigned int pattern=~0U) {
 1.22585 +      if (!is_empty()) {
 1.22586 +        int siz = (int)xvalues.size()-1;
 1.22587 +        if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
 1.22588 +        else {
 1.22589 +          if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
 1.22590 +          else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
 1.22591 +          const int yt = (y+14)<dimy()?(y+3):(y-14);
 1.22592 +          char txt[32];
 1.22593 +          cimg_foroff(xvalues,x) {
 1.22594 +            cimg_std::sprintf(txt,"%g",(double)xvalues(x));
 1.22595 +            const int xi = (int)(x*(width-1)/siz), xt = xi-(int)cimg::strlen(txt)*3;
 1.22596 +            draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
 1.22597 +              draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
 1.22598 +          }
 1.22599 +        }
 1.22600 +      }
 1.22601 +      return *this;
 1.22602 +    }
 1.22603 +
 1.22604 +    //! Draw a labeled horizontal axis on the instance image.
 1.22605 +    template<typename t, typename tc>
 1.22606 +    CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 1.22607 +                       const CImg<tc>& color, const float opacity=1,
 1.22608 +                       const unsigned int pattern=~0U) {
 1.22609 +      return draw_axis(xvalues,y,color.data,opacity,pattern);
 1.22610 +    }
 1.22611 +
 1.22612 +    //! Draw a labeled vertical axis on the instance image.
 1.22613 +    template<typename t, typename tc>
 1.22614 +    CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 1.22615 +                       const tc *const color, const float opacity=1,
 1.22616 +                       const unsigned int pattern=~0U) {
 1.22617 +      if (!is_empty()) {
 1.22618 +        int siz = (int)yvalues.size()-1;
 1.22619 +        if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
 1.22620 +        else {
 1.22621 +          if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
 1.22622 +          else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
 1.22623 +          char txt[32];
 1.22624 +          cimg_foroff(yvalues,y) {
 1.22625 +            cimg_std::sprintf(txt,"%g",(double)yvalues(y));
 1.22626 +            const int
 1.22627 +              yi = (int)(y*(height-1)/siz),
 1.22628 +              tmp = yi-5,
 1.22629 +              nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
 1.22630 +              xt = x-(int)cimg::strlen(txt)*7;
 1.22631 +            draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
 1.22632 +            if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
 1.22633 +            else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
 1.22634 +          }
 1.22635 +        }
 1.22636 +      }
 1.22637 +      return *this;
 1.22638 +    }
 1.22639 +
 1.22640 +    //! Draw a labeled vertical axis on the instance image.
 1.22641 +    template<typename t, typename tc>
 1.22642 +    CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 1.22643 +                       const CImg<tc>& color, const float opacity=1,
 1.22644 +                       const unsigned int pattern=~0U) {
 1.22645 +      return draw_axis(x,yvalues,color.data,opacity,pattern);
 1.22646 +    }
 1.22647 +
 1.22648 +    //! Draw a labeled horizontal+vertical axis on the instance image.
 1.22649 +    template<typename tx, typename ty, typename tc>
 1.22650 +      CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 1.22651 +                         const tc *const color, const float opacity=1,
 1.22652 +                         const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22653 +      if (!is_empty()) {
 1.22654 +        const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
 1.22655 +        const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
 1.22656 +        if (sizx>0) {
 1.22657 +          float ox = (float)nxvalues[0];
 1.22658 +          for (unsigned int x = 1; x<width; ++x) {
 1.22659 +            const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
 1.22660 +            if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
 1.22661 +            ox = nx;
 1.22662 +          }
 1.22663 +        }
 1.22664 +        const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
 1.22665 +        const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
 1.22666 +        if (sizy>0) {
 1.22667 +          float oy = (float)nyvalues[0];
 1.22668 +          for (unsigned int y = 1; y<height; ++y) {
 1.22669 +            const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
 1.22670 +            if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
 1.22671 +            oy = ny;
 1.22672 +          }
 1.22673 +        }
 1.22674 +      }
 1.22675 +      return *this;
 1.22676 +    }
 1.22677 +
 1.22678 +    //! Draw a labeled horizontal+vertical axis on the instance image.
 1.22679 +    template<typename tx, typename ty, typename tc>
 1.22680 +    CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 1.22681 +                       const CImg<tc>& color, const float opacity=1,
 1.22682 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22683 +      return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
 1.22684 +    }
 1.22685 +
 1.22686 +    //! Draw a labeled horizontal+vertical axis on the instance image.
 1.22687 +    template<typename tc>
 1.22688 +    CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 1.22689 +                       const tc *const color, const float opacity=1,
 1.22690 +                       const int subdivisionx=-60, const int subdivisiony=-60,
 1.22691 +                       const float precisionx=0, const float precisiony=0,
 1.22692 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22693 +      if (!is_empty()) {
 1.22694 +        const float
 1.22695 +          dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
 1.22696 +          px = (precisionx==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0):precisionx,
 1.22697 +          py = (precisiony==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0):precisiony;
 1.22698 +        draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
 1.22699 +                  CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
 1.22700 +                  color,opacity,patternx,patterny);
 1.22701 +      }
 1.22702 +      return *this;
 1.22703 +    }
 1.22704 +
 1.22705 +    //! Draw a labeled horizontal+vertical axis on the instance image.
 1.22706 +    template<typename tc>
 1.22707 +    CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 1.22708 +                       const CImg<tc>& color, const float opacity=1,
 1.22709 +                       const int subdivisionx=-60, const int subdivisiony=-60,
 1.22710 +                       const float precisionx=0, const float precisiony=0,
 1.22711 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22712 +      return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
 1.22713 +    }
 1.22714 +
 1.22715 +    //! Draw grid.
 1.22716 +    template<typename tx, typename ty, typename tc>
 1.22717 +    CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 1.22718 +                       const tc *const color, const float opacity=1,
 1.22719 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22720 +      if (!is_empty()) {
 1.22721 +        if (xvalues) cimg_foroff(xvalues,x) {
 1.22722 +          const int xi = (int)xvalues[x];
 1.22723 +          if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
 1.22724 +        }
 1.22725 +        if (yvalues) cimg_foroff(yvalues,y) {
 1.22726 +          const int yi = (int)yvalues[y];
 1.22727 +          if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
 1.22728 +        }
 1.22729 +      }
 1.22730 +      return *this;
 1.22731 +    }
 1.22732 +
 1.22733 +    //! Draw grid.
 1.22734 +    template<typename tx, typename ty, typename tc>
 1.22735 +    CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 1.22736 +                       const CImg<tc>& color, const float opacity=1,
 1.22737 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22738 +      return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
 1.22739 +    }
 1.22740 +
 1.22741 +    //! Draw grid.
 1.22742 +    template<typename tc>
 1.22743 +    CImg<T>& draw_grid(const float deltax,  const float deltay,
 1.22744 +                       const float offsetx, const float offsety,
 1.22745 +                       const bool invertx, const bool inverty,
 1.22746 +                       const tc *const color, const float opacity=1,
 1.22747 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22748 +      CImg<uintT> seqx, seqy;
 1.22749 +      if (deltax!=0) {
 1.22750 +        const float dx = deltax>0?deltax:width*-deltax/100;
 1.22751 +        const unsigned int nx = (unsigned int)(width/dx);
 1.22752 +        seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
 1.22753 +        if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
 1.22754 +        if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
 1.22755 +      }
 1.22756 +
 1.22757 +      if (deltay!=0) {
 1.22758 +        const float dy = deltay>0?deltay:height*-deltay/100;
 1.22759 +        const unsigned int ny = (unsigned int)(height/dy);
 1.22760 +        seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
 1.22761 +        if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
 1.22762 +        if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
 1.22763 +     }
 1.22764 +      return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
 1.22765 +    }
 1.22766 +
 1.22767 +    //! Draw grid.
 1.22768 +    template<typename tc>
 1.22769 +    CImg<T>& draw_grid(const float deltax,  const float deltay,
 1.22770 +                       const float offsetx, const float offsety,
 1.22771 +                       const bool invertx, const bool inverty,
 1.22772 +                       const CImg<tc>& color, const float opacity=1,
 1.22773 +                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 1.22774 +      return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
 1.22775 +    }
 1.22776 +
 1.22777 +    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 1.22778 +    /**
 1.22779 +       \param x X-coordinate of the starting point of the region to fill.
 1.22780 +       \param y Y-coordinate of the starting point of the region to fill.
 1.22781 +       \param z Z-coordinate of the starting point of the region to fill.
 1.22782 +       \param color An array of dimv() values of type \c T, defining the drawing color.
 1.22783 +       \param region Image that will contain the mask of the filled region mask, as an output.
 1.22784 +       \param sigma Tolerance concerning neighborhood values.
 1.22785 +       \param opacity Opacity of the drawing.
 1.22786 +       \param high_connexity Tells if 8-connexity must be used (only for 2D images).
 1.22787 +       \return \p region is initialized with the binary mask of the filled region.
 1.22788 +    **/
 1.22789 +    template<typename tc, typename t>
 1.22790 +    CImg<T>& draw_fill(const int x, const int y, const int z,
 1.22791 +                       const tc *const color, const float opacity,
 1.22792 +                       CImg<t>& region, const float sigma=0,
 1.22793 +                       const bool high_connexity=false) {
 1.22794 +
 1.22795 +#define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
 1.22796 +  res = true; \
 1.22797 +  const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
 1.22798 +  for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
 1.22799 +  region(x,y,z) = (t)(res?1:noregion); \
 1.22800 +}
 1.22801 +
 1.22802 +#define _cimg_draw_fill_set(x,y,z) { \
 1.22803 +  const tc *col = color; \
 1.22804 +  T *ptrd = ptr(x,y,z); \
 1.22805 +  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
 1.22806 +  else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
 1.22807 +}
 1.22808 +
 1.22809 +#define _cimg_draw_fill_insert(x,y,z) { \
 1.22810 +  if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
 1.22811 +  unsigned int *ptrr = remaining.ptr(0,posr1); \
 1.22812 +  *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
 1.22813 +}
 1.22814 +
 1.22815 +#define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
 1.22816 +  const unsigned int tx = x, ty = y, tz = z; \
 1.22817 +  _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
 1.22818 +}
 1.22819 +
 1.22820 +      if (!color)
 1.22821 +        throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
 1.22822 +                                    pixel_type());
 1.22823 +      region.assign(width,height,depth,1,(t)0);
 1.22824 +      if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
 1.22825 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.22826 +        const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
 1.22827 +        const bool threed = depth>1;
 1.22828 +        const CImg<T> reference_color = get_vector_at(x,y,z);
 1.22829 +        CImg<uintT> remaining(3,512,1,1,0);
 1.22830 +        remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
 1.22831 +        unsigned int posr0 = 0, posr1 = 1;
 1.22832 +        region(x,y,z) = (t)1;
 1.22833 +        const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
 1.22834 +        if (threed) do { // 3D version of the filling algorithm
 1.22835 +          const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
 1.22836 +          if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 1.22837 +          bool cont, res;
 1.22838 +          unsigned int nxc = xc;
 1.22839 +          do { // X-backward
 1.22840 +            _cimg_draw_fill_set(nxc,yc,zc);
 1.22841 +            _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 1.22842 +            _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 1.22843 +            _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 1.22844 +            _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 1.22845 +            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 1.22846 +          } while (cont);
 1.22847 +          nxc = xc;
 1.22848 +          do { // X-forward
 1.22849 +            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 1.22850 +            if (cont) {
 1.22851 +              _cimg_draw_fill_set(nxc,yc,zc);
 1.22852 +              _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 1.22853 +              _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 1.22854 +              _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 1.22855 +              _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 1.22856 +            }
 1.22857 +          } while (cont);
 1.22858 +          unsigned int nyc = yc;
 1.22859 +          do { // Y-backward
 1.22860 +            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 1.22861 +            if (cont) {
 1.22862 +              _cimg_draw_fill_set(xc,nyc,zc);
 1.22863 +              _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 1.22864 +              _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 1.22865 +              _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 1.22866 +              _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 1.22867 +            }
 1.22868 +          } while (cont);
 1.22869 +          nyc = yc;
 1.22870 +          do { // Y-forward
 1.22871 +            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 1.22872 +            if (cont) {
 1.22873 +              _cimg_draw_fill_set(xc,nyc,zc);
 1.22874 +              _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 1.22875 +              _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 1.22876 +              _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 1.22877 +              _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 1.22878 +            }
 1.22879 +          } while (cont);
 1.22880 +          unsigned int nzc = zc;
 1.22881 +          do { // Z-backward
 1.22882 +            if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 1.22883 +            if (cont) {
 1.22884 +              _cimg_draw_fill_set(xc,yc,nzc);
 1.22885 +              _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 1.22886 +              _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 1.22887 +              _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 1.22888 +              _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 1.22889 +            }
 1.22890 +          } while (cont);
 1.22891 +          nzc = zc;
 1.22892 +          do { // Z-forward
 1.22893 +            if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 1.22894 +            if (cont) {
 1.22895 +              _cimg_draw_fill_set(xc,nyc,zc);
 1.22896 +              _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 1.22897 +              _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 1.22898 +              _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 1.22899 +              _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 1.22900 +            }
 1.22901 +          } while (cont);
 1.22902 +        } while (posr1>posr0);
 1.22903 +        else do { // 2D version of the filling algorithm
 1.22904 +          const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
 1.22905 +          if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 1.22906 +          bool cont, res;
 1.22907 +          unsigned int nxc = xc;
 1.22908 +          do { // X-backward
 1.22909 +            _cimg_draw_fill_set(nxc,yc,0);
 1.22910 +            _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 1.22911 +            _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 1.22912 +            if (high_connexity) {
 1.22913 +              _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 1.22914 +              _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 1.22915 +              _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 1.22916 +              _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 1.22917 +            }
 1.22918 +            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 1.22919 +          } while (cont);
 1.22920 +          nxc = xc;
 1.22921 +          do { // X-forward
 1.22922 +            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 1.22923 +            if (cont) {
 1.22924 +              _cimg_draw_fill_set(nxc,yc,0);
 1.22925 +              _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 1.22926 +              _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 1.22927 +              if (high_connexity) {
 1.22928 +                _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 1.22929 +                _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 1.22930 +                _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 1.22931 +                _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 1.22932 +              }
 1.22933 +            }
 1.22934 +          } while (cont);
 1.22935 +          unsigned int nyc = yc;
 1.22936 +          do { // Y-backward
 1.22937 +            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 1.22938 +            if (cont) {
 1.22939 +              _cimg_draw_fill_set(xc,nyc,0);
 1.22940 +              _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 1.22941 +              _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 1.22942 +              if (high_connexity) {
 1.22943 +                _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 1.22944 +                _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 1.22945 +                _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 1.22946 +                _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 1.22947 +              }
 1.22948 +            }
 1.22949 +          } while (cont);
 1.22950 +          nyc = yc;
 1.22951 +          do { // Y-forward
 1.22952 +            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 1.22953 +            if (cont) {
 1.22954 +              _cimg_draw_fill_set(xc,nyc,0);
 1.22955 +              _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 1.22956 +              _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 1.22957 +              if (high_connexity) {
 1.22958 +                _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 1.22959 +                _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 1.22960 +                _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 1.22961 +                _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 1.22962 +              }
 1.22963 +            }
 1.22964 +          } while (cont);
 1.22965 +        } while (posr1>posr0);
 1.22966 +        if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
 1.22967 +      }
 1.22968 +      return *this;
 1.22969 +    }
 1.22970 +
 1.22971 +    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 1.22972 +    template<typename tc, typename t>
 1.22973 +    CImg<T>& draw_fill(const int x, const int y, const int z,
 1.22974 +                       const CImg<tc>& color, const float opacity,
 1.22975 +                       CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
 1.22976 +      return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
 1.22977 +    }
 1.22978 +
 1.22979 +    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 1.22980 +    /**
 1.22981 +       \param x = X-coordinate of the starting point of the region to fill.
 1.22982 +       \param y = Y-coordinate of the starting point of the region to fill.
 1.22983 +       \param z = Z-coordinate of the starting point of the region to fill.
 1.22984 +       \param color = an array of dimv() values of type \c T, defining the drawing color.
 1.22985 +       \param sigma = tolerance concerning neighborhood values.
 1.22986 +       \param opacity = opacity of the drawing.
 1.22987 +    **/
 1.22988 +    template<typename tc>
 1.22989 +    CImg<T>& draw_fill(const int x, const int y, const int z,
 1.22990 +                       const tc *const color, const float opacity=1,
 1.22991 +                       const float sigma=0, const bool high_connexity=false) {
 1.22992 +      CImg<boolT> tmp;
 1.22993 +      return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
 1.22994 +    }
 1.22995 +
 1.22996 +    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 1.22997 +    template<typename tc>
 1.22998 +    CImg<T>& draw_fill(const int x, const int y, const int z,
 1.22999 +                       const CImg<tc>& color, const float opacity=1,
 1.23000 +                       const float sigma=0, const bool high_connexity=false) {
 1.23001 +      return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
 1.23002 +    }
 1.23003 +
 1.23004 +    //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
 1.23005 +    /**
 1.23006 +       \param x = X-coordinate of the starting point of the region to fill.
 1.23007 +       \param y = Y-coordinate of the starting point of the region to fill.
 1.23008 +       \param color = an array of dimv() values of type \c T, defining the drawing color.
 1.23009 +       \param sigma = tolerance concerning neighborhood values.
 1.23010 +       \param opacity = opacity of the drawing.
 1.23011 +    **/
 1.23012 +    template<typename tc>
 1.23013 +    CImg<T>& draw_fill(const int x, const int y,
 1.23014 +                       const tc *const color, const float opacity=1,
 1.23015 +                       const float sigma=0, const bool high_connexity=false) {
 1.23016 +      CImg<boolT> tmp;
 1.23017 +      return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
 1.23018 +    }
 1.23019 +
 1.23020 +    //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
 1.23021 +    template<typename tc>
 1.23022 +    CImg<T>& draw_fill(const int x, const int y,
 1.23023 +                       const CImg<tc>& color, const float opacity=1,
 1.23024 +                       const float sigma=0, const bool high_connexity=false) {
 1.23025 +      return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
 1.23026 +    }
 1.23027 +
 1.23028 +    //! Draw a plasma random texture.
 1.23029 +    /**
 1.23030 +       \param x0 = X-coordinate of the upper-left corner of the plasma.
 1.23031 +       \param y0 = Y-coordinate of the upper-left corner of the plasma.
 1.23032 +       \param x1 = X-coordinate of the lower-right corner of the plasma.
 1.23033 +       \param y1 = Y-coordinate of the lower-right corner of the plasma.
 1.23034 +       \param alpha = Alpha-parameter of the plasma.
 1.23035 +       \param beta = Beta-parameter of the plasma.
 1.23036 +       \param opacity = opacity of the drawing.
 1.23037 +    **/
 1.23038 +    CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
 1.23039 +                         const float alpha=1, const float beta=1,
 1.23040 +                         const float opacity=1) {
 1.23041 +      if (!is_empty()) {
 1.23042 +        const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.23043 +        int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
 1.23044 +        if (nx1<nx0) cimg::swap(nx0,nx1);
 1.23045 +        if (ny1<ny0) cimg::swap(ny0,ny1);
 1.23046 +        if (nx0<0) nx0 = 0;
 1.23047 +        if (nx1>=dimx()) nx1 = width-1;
 1.23048 +        if (ny0<0) ny0 = 0;
 1.23049 +        if (ny1>=dimy()) ny1 = height-1;
 1.23050 +        const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
 1.23051 +        const Tfloat dc = (Tfloat)(cimg_std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
 1.23052 +        Tfloat val = 0;
 1.23053 +        cimg_forV(*this,k) {
 1.23054 +          if (opacity>=1) {
 1.23055 +            const Tfloat
 1.23056 +              val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
 1.23057 +              val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
 1.23058 +            (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
 1.23059 +            (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
 1.23060 +            (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
 1.23061 +            (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
 1.23062 +            do {
 1.23063 +              val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
 1.23064 +                                   (Tfloat)((*this)(nx1,ny0,0,k)) +
 1.23065 +                                   (Tfloat)((*this)(nx1,ny1,0,k)) +
 1.23066 +                                   (Tfloat)((*this)(nx0,ny1,0,k))) +
 1.23067 +                            dc*cimg::grand());
 1.23068 +            } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
 1.23069 +            (*this)(xc,yc,0,k) = (T)val;
 1.23070 +          } else {
 1.23071 +            const Tfloat
 1.23072 +              val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
 1.23073 +              val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
 1.23074 +            (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
 1.23075 +            (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
 1.23076 +            (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
 1.23077 +            (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
 1.23078 +            do {
 1.23079 +              val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
 1.23080 +                                    (Tfloat)((*this)(nx1,ny0,0,k)) +
 1.23081 +                                    (Tfloat)((*this)(nx1,ny1,0,k)) +
 1.23082 +                                    (Tfloat)((*this)(nx0,ny1,0,k))) +
 1.23083 +                                   dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
 1.23084 +            } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
 1.23085 +            (*this)(xc,yc,0,k) = (T)val;
 1.23086 +          }
 1.23087 +        }
 1.23088 +        if (xc!=nx0 || yc!=ny0) {
 1.23089 +          draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
 1.23090 +          draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
 1.23091 +          draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
 1.23092 +          draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
 1.23093 +        }
 1.23094 +      }
 1.23095 +      return *this;
 1.23096 +    }
 1.23097 +
 1.23098 +    //! Draw a plasma random texture.
 1.23099 +    /**
 1.23100 +       \param alpha = Alpha-parameter of the plasma.
 1.23101 +       \param beta = Beta-parameter of the plasma.
 1.23102 +       \param opacity = opacity of the drawing.
 1.23103 +    **/
 1.23104 +    CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
 1.23105 +                         const float opacity=1) {
 1.23106 +      return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
 1.23107 +    }
 1.23108 +
 1.23109 +    //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 1.23110 +    template<typename tc>
 1.23111 +    CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
 1.23112 +                             const CImg<tc>& color_palette, const float opacity=1,
 1.23113 +                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 1.23114 +                             const unsigned int itermax=255,
 1.23115 +                             const bool normalized_iteration=false,
 1.23116 +                             const bool julia_set=false,
 1.23117 +                             const double paramr=0, const double parami=0) {
 1.23118 +      if (is_empty()) return *this;
 1.23119 +      CImg<tc> palette;
 1.23120 +      if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
 1.23121 +      if (palette && palette.dim!=dim)
 1.23122 +        throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
 1.23123 +                                    "compatible with instance image (%u,%u,%u,%u,%p).",
 1.23124 +                                    pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
 1.23125 +                                    color_palette.data,width,height,depth,dim,data);
 1.23126 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)cimg_std::log(2.0);
 1.23127 +      unsigned int iter = 0;
 1.23128 +      cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 1.23129 +        const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
 1.23130 +        double zr, zi, cr, ci;
 1.23131 +        if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
 1.23132 +        else { zr = paramr; zi = parami; cr = x; ci = y; }
 1.23133 +        for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
 1.23134 +          const double temp = zr*zr - zi*zi + cr;
 1.23135 +          zi = 2*zr*zi + ci;
 1.23136 +          zr = temp;
 1.23137 +        }
 1.23138 +        if (iter>itermax) {
 1.23139 +          if (palette) {
 1.23140 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
 1.23141 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
 1.23142 +          } else {
 1.23143 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
 1.23144 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
 1.23145 +          }
 1.23146 +        } else if (normalized_iteration) {
 1.23147 +          const float
 1.23148 +            normz = (float)cimg::abs(zr*zr+zi*zi),
 1.23149 +            niter = (float)(iter + 1 - cimg_std::log(cimg_std::log(normz))/ln2);
 1.23150 +          if (palette) {
 1.23151 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
 1.23152 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 1.23153 +          } else {
 1.23154 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
 1.23155 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
 1.23156 +          }
 1.23157 +        } else {
 1.23158 +          if (palette) {
 1.23159 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
 1.23160 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 1.23161 +          } else {
 1.23162 +            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
 1.23163 +            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
 1.23164 +          }
 1.23165 +        }
 1.23166 +      }
 1.23167 +      return *this;
 1.23168 +    }
 1.23169 +
 1.23170 +    //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 1.23171 +    template<typename tc>
 1.23172 +    CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
 1.23173 +                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 1.23174 +                             const unsigned int itermax=255,
 1.23175 +                             const bool normalized_iteration=false,
 1.23176 +                             const bool julia_set=false,
 1.23177 +                             const double paramr=0, const double parami=0) {
 1.23178 +      return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
 1.23179 +    }
 1.23180 +
 1.23181 +    //! Draw a 1D gaussian function in the instance image.
 1.23182 +    /**
 1.23183 +       \param xc = X-coordinate of the gaussian center.
 1.23184 +       \param sigma = Standard variation of the gaussian distribution.
 1.23185 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.23186 +       \param opacity = opacity of the drawing.
 1.23187 +    **/
 1.23188 +    template<typename tc>
 1.23189 +    CImg<T>& draw_gaussian(const float xc, const float sigma,
 1.23190 +                           const tc *const color, const float opacity=1) {
 1.23191 +      if (is_empty()) return *this;
 1.23192 +      if (!color)
 1.23193 +        throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
 1.23194 +                                    pixel_type());
 1.23195 +      const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.23196 +      const unsigned int whz = width*height*depth;
 1.23197 +      const tc *col = color;
 1.23198 +      cimg_forX(*this,x) {
 1.23199 +        const float dx = (x - xc), val = (float)cimg_std::exp(-dx*dx/sigma2);
 1.23200 +        T *ptrd = ptr(x,0,0,0);
 1.23201 +        if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 1.23202 +        else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 1.23203 +        col-=dim;
 1.23204 +      }
 1.23205 +      return *this;
 1.23206 +    }
 1.23207 +
 1.23208 +    //! Draw a 1D gaussian function in the instance image.
 1.23209 +    template<typename tc>
 1.23210 +    CImg<T>& draw_gaussian(const float xc, const float sigma,
 1.23211 +                           const CImg<tc>& color, const float opacity=1) {
 1.23212 +      return draw_gaussian(xc,sigma,color.data,opacity);
 1.23213 +    }
 1.23214 +
 1.23215 +    //! Draw an anisotropic 2D gaussian function.
 1.23216 +    /**
 1.23217 +       \param xc = X-coordinate of the gaussian center.
 1.23218 +       \param yc = Y-coordinate of the gaussian center.
 1.23219 +       \param tensor = 2x2 covariance matrix.
 1.23220 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.23221 +       \param opacity = opacity of the drawing.
 1.23222 +    **/
 1.23223 +    template<typename t, typename tc>
 1.23224 +    CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 1.23225 +                           const tc *const color, const float opacity=1) {
 1.23226 +      if (is_empty()) return *this;
 1.23227 +      typedef typename cimg::superset<t,float>::type tfloat;
 1.23228 +      if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
 1.23229 +        throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
 1.23230 +                                    pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
 1.23231 +      if (!color)
 1.23232 +        throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
 1.23233 +                                    pixel_type());
 1.23234 +      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
 1.23235 +      const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
 1.23236 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.23237 +      const unsigned int whz = width*height*depth;
 1.23238 +      const tc *col = color;
 1.23239 +      float dy = -yc;
 1.23240 +      cimg_forY(*this,y) {
 1.23241 +        float dx = -xc;
 1.23242 +        cimg_forX(*this,x) {
 1.23243 +          const float val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
 1.23244 +          T *ptrd = ptr(x,y,0,0);
 1.23245 +          if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 1.23246 +          else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 1.23247 +          col-=dim;
 1.23248 +          ++dx;
 1.23249 +        }
 1.23250 +        ++dy;
 1.23251 +      }
 1.23252 +      return *this;
 1.23253 +    }
 1.23254 +
 1.23255 +    //! Draw an anisotropic 2D gaussian function.
 1.23256 +    template<typename t, typename tc>
 1.23257 +    CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 1.23258 +                           const CImg<tc>& color, const float opacity=1) {
 1.23259 +      return draw_gaussian(xc,yc,tensor,color.data,opacity);
 1.23260 +    }
 1.23261 +
 1.23262 +    //! Draw an anisotropic 2D gaussian function.
 1.23263 +    template<typename tc>
 1.23264 +    CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
 1.23265 +                           const tc *const color, const float opacity=1) {
 1.23266 +      const double
 1.23267 +        a = r1*ru*ru + r2*rv*rv,
 1.23268 +        b = (r1-r2)*ru*rv,
 1.23269 +        c = r1*rv*rv + r2*ru*ru;
 1.23270 +      const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
 1.23271 +      return draw_gaussian(xc,yc,tensor,color,opacity);
 1.23272 +    }
 1.23273 +
 1.23274 +    //! Draw an anisotropic 2D gaussian function.
 1.23275 +    template<typename tc>
 1.23276 +    CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
 1.23277 +                           const CImg<tc>& color, const float opacity=1) {
 1.23278 +      return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
 1.23279 +    }
 1.23280 +
 1.23281 +    //! Draw an isotropic 2D gaussian function.
 1.23282 +    /**
 1.23283 +       \param xc = X-coordinate of the gaussian center.
 1.23284 +       \param yc = Y-coordinate of the gaussian center.
 1.23285 +       \param sigma = standard variation of the gaussian distribution.
 1.23286 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.23287 +       \param opacity = opacity of the drawing.
 1.23288 +    **/
 1.23289 +    template<typename tc>
 1.23290 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
 1.23291 +                           const tc *const color, const float opacity=1) {
 1.23292 +      return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
 1.23293 +    }
 1.23294 +
 1.23295 +    //! Draw an isotropic 2D gaussian function.
 1.23296 +    template<typename tc>
 1.23297 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
 1.23298 +                           const CImg<tc>& color, const float opacity=1) {
 1.23299 +      return draw_gaussian(xc,yc,sigma,color.data,opacity);
 1.23300 +    }
 1.23301 +
 1.23302 +    //! Draw an anisotropic 3D gaussian function.
 1.23303 +    /**
 1.23304 +       \param xc = X-coordinate of the gaussian center.
 1.23305 +       \param yc = Y-coordinate of the gaussian center.
 1.23306 +       \param zc = Z-coordinate of the gaussian center.
 1.23307 +       \param tensor = 3x3 covariance matrix.
 1.23308 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.23309 +       \param opacity = opacity of the drawing.
 1.23310 +    **/
 1.23311 +    template<typename t, typename tc>
 1.23312 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 1.23313 +                           const tc *const color, const float opacity=1) {
 1.23314 +      if (is_empty()) return *this;
 1.23315 +      typedef typename cimg::superset<t,float>::type tfloat;
 1.23316 +      if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
 1.23317 +        throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
 1.23318 +                                    pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
 1.23319 +      const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
 1.23320 +      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);
 1.23321 +      const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
 1.23322 +      const unsigned int whz = width*height*depth;
 1.23323 +      const tc *col = color;
 1.23324 +      cimg_forXYZ(*this,x,y,z) {
 1.23325 +        const float
 1.23326 +          dx = (x - xc), dy = (y - yc), dz = (z - zc),
 1.23327 +          val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
 1.23328 +        T *ptrd = ptr(x,y,z,0);
 1.23329 +        if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
 1.23330 +        else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
 1.23331 +        col-=dim;
 1.23332 +      }
 1.23333 +      return *this;
 1.23334 +    }
 1.23335 +
 1.23336 +    //! Draw an anisotropic 3D gaussian function.
 1.23337 +    template<typename t, typename tc>
 1.23338 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 1.23339 +                           const CImg<tc>& color, const float opacity=1) {
 1.23340 +      return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
 1.23341 +    }
 1.23342 +
 1.23343 +    //! Draw an isotropic 3D gaussian function.
 1.23344 +   /**
 1.23345 +       \param xc = X-coordinate of the gaussian center.
 1.23346 +       \param yc = Y-coordinate of the gaussian center.
 1.23347 +       \param zc = Z-coordinate of the gaussian center.
 1.23348 +       \param sigma = standard variation of the gaussian distribution.
 1.23349 +       \param color = array of dimv() values of type \c T, defining the drawing color.
 1.23350 +       \param opacity = opacity of the drawing.
 1.23351 +    **/
 1.23352 +    template<typename tc>
 1.23353 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
 1.23354 +                           const tc *const color, const float opacity=1) {
 1.23355 +      return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
 1.23356 +    }
 1.23357 +
 1.23358 +    //! Draw an isotropic 3D gaussian function.
 1.23359 +    template<typename tc>
 1.23360 +    CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
 1.23361 +                           const CImg<tc>& color, const float opacity=1) {
 1.23362 +      return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
 1.23363 +    }
 1.23364 +
 1.23365 +    // Draw a 3D object (internal)
 1.23366 +    template<typename tc, typename to>
 1.23367 +    void _draw_object3d_sprite(const int x, const int y,
 1.23368 +                               const CImg<tc>& color, const CImg<to>& opacity, const CImg<T>& sprite) {
 1.23369 +      if (opacity.width==color.width && opacity.height==color.height)
 1.23370 +        draw_image(x,y,sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1));
 1.23371 +      else
 1.23372 +        draw_image(x,y,sprite,opacity(0));
 1.23373 +    }
 1.23374 +
 1.23375 +    template<typename tc>
 1.23376 +    void _draw_object3d_sprite(const int x, const int y,
 1.23377 +                               const CImg<tc>& color, const float opacity, const CImg<T>& sprite) {
 1.23378 +      if (color) draw_image(x,y,sprite,opacity);
 1.23379 +    }
 1.23380 +
 1.23381 +    template<typename tp, typename tf, typename tc, typename to>
 1.23382 +    CImg<T>& _draw_object3d(void *const pboard, float *const zbuffer,
 1.23383 +                            const float X, const float Y, const float Z,
 1.23384 +                            const tp& points, const unsigned int nb_points,
 1.23385 +                            const CImgList<tf>& primitives,
 1.23386 +                            const CImgList<tc>& colors,
 1.23387 +                            const to& opacities, const unsigned int nb_opacities,
 1.23388 +                            const unsigned int render_type,
 1.23389 +                            const bool double_sided, const float focale,
 1.23390 +                            const float lightx, const float lighty, const float lightz,
 1.23391 +                            const float specular_light, const float specular_shine) {
 1.23392 +      if (is_empty()) return *this;
 1.23393 +#ifndef cimg_use_board
 1.23394 +      if (pboard) return *this;
 1.23395 +#endif
 1.23396 +      const float
 1.23397 +        nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
 1.23398 +        nspec2 = 1+(specular_shine<0?0:specular_shine),
 1.23399 +        nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
 1.23400 +        nsl2 = (1-2*nsl1*nspec),
 1.23401 +        nsl3 = nspec2-nsl1-nsl2;
 1.23402 +
 1.23403 +      // Create light texture for phong-like rendering
 1.23404 +      static CImg<floatT> light_texture;
 1.23405 +      if (render_type==5) {
 1.23406 +        if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
 1.23407 +        else {
 1.23408 +          static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
 1.23409 +          if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
 1.23410 +            light_texture.assign(512,512);
 1.23411 +            const float white[] = { 1 },
 1.23412 +              dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
 1.23413 +                nl = (float)cimg_std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
 1.23414 +                nlx = light_texture.width/2*(1+dlx/nl),
 1.23415 +                nly = light_texture.height/2*(1+dly/nl);
 1.23416 +              light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
 1.23417 +              cimg_forXY(light_texture,x,y) {
 1.23418 +                const float factor = light_texture(x,y);
 1.23419 +                if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
 1.23420 +              }
 1.23421 +              olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
 1.23422 +          }
 1.23423 +        }
 1.23424 +      }
 1.23425 +
 1.23426 +      // Compute 3D to 2D projection
 1.23427 +      CImg<floatT> projections(nb_points,2);
 1.23428 +      cimg_forX(projections,l) {
 1.23429 +        const float
 1.23430 +          x = (float)points(l,0),
 1.23431 +          y = (float)points(l,1),
 1.23432 +          z = (float)points(l,2);
 1.23433 +        const float projectedz = z + Z + focale;
 1.23434 +        projections(l,1) = Y + focale*y/projectedz;
 1.23435 +        projections(l,0) = X + focale*x/projectedz;
 1.23436 +      }
 1.23437 +
 1.23438 +      // Compute and sort visible primitives
 1.23439 +      CImg<uintT> visibles(primitives.size);
 1.23440 +      CImg<floatT> zrange(primitives.size);
 1.23441 +      unsigned int nb_visibles = 0;
 1.23442 +      const float zmin = -focale+1.5f;
 1.23443 +      { cimglist_for(primitives,l) {
 1.23444 +        const CImg<tf>& primitive = primitives[l];
 1.23445 +        switch (primitive.size()) {
 1.23446 +
 1.23447 +        case 1 : { // Point
 1.23448 +          const unsigned int i0 = (unsigned int)primitive(0);
 1.23449 +          const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
 1.23450 +          if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
 1.23451 +            visibles(nb_visibles) = (unsigned int)l;
 1.23452 +            zrange(nb_visibles++) = z0;
 1.23453 +          }
 1.23454 +        } break;
 1.23455 +        case 5 : { // Sphere
 1.23456 +          const unsigned int
 1.23457 +            i0 = (unsigned int)primitive(0),
 1.23458 +            i1 = (unsigned int)primitive(1),
 1.23459 +            i2 = (unsigned int)primitive(2);
 1.23460 +          const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
 1.23461 +          int radius;
 1.23462 +          if (i2) radius = (int)(i2*focale/(z0+focale));
 1.23463 +          else {
 1.23464 +            const float x1 = projections(i1,0), y1 = projections(i1,1);
 1.23465 +            const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
 1.23466 +            radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
 1.23467 +          }
 1.23468 +          if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
 1.23469 +            visibles(nb_visibles) = (unsigned int)l;
 1.23470 +            zrange(nb_visibles++) = z0;
 1.23471 +          }
 1.23472 +        } break;
 1.23473 +        case 2 : // Line
 1.23474 +        case 6 : {
 1.23475 +          const unsigned int
 1.23476 +            i0 = (unsigned int)primitive(0),
 1.23477 +            i1 = (unsigned int)primitive(1);
 1.23478 +          const float
 1.23479 +            x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 1.23480 +            x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2));
 1.23481 +          float xm, xM, ym, yM;
 1.23482 +          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 1.23483 +          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 1.23484 +          if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 1.23485 +            visibles(nb_visibles) = (unsigned int)l;
 1.23486 +            zrange(nb_visibles++) = 0.5f*(z0+z1);
 1.23487 +          }
 1.23488 +        } break;
 1.23489 +        case 3 :  // Triangle
 1.23490 +        case 9 : {
 1.23491 +          const unsigned int
 1.23492 +            i0 = (unsigned int)primitive(0),
 1.23493 +            i1 = (unsigned int)primitive(1),
 1.23494 +            i2 = (unsigned int)primitive(2);
 1.23495 +          const float
 1.23496 +            x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 1.23497 +            x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
 1.23498 +            x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2));
 1.23499 +          float xm, xM, ym, yM;
 1.23500 +          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 1.23501 +          if (x2<xm) xm = x2;
 1.23502 +          if (x2>xM) xM = x2;
 1.23503 +          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 1.23504 +          if (y2<ym) ym = y2;
 1.23505 +          if (y2>yM) yM = y2;
 1.23506 +          if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 1.23507 +            const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
 1.23508 +            if (double_sided || d<0) {
 1.23509 +              visibles(nb_visibles) = (unsigned int)l;
 1.23510 +              zrange(nb_visibles++) = (z0+z1+z2)/3;
 1.23511 +            }
 1.23512 +          }
 1.23513 +        } break;
 1.23514 +        case 4 : // Rectangle
 1.23515 +        case 12 : {
 1.23516 +          const unsigned int
 1.23517 +            i0 = (unsigned int)primitive(0),
 1.23518 +            i1 = (unsigned int)primitive(1),
 1.23519 +            i2 = (unsigned int)primitive(2),
 1.23520 +            i3 = (unsigned int)primitive(3);
 1.23521 +          const float
 1.23522 +            x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
 1.23523 +            x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
 1.23524 +            x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)),
 1.23525 +            x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2));
 1.23526 +          float xm, xM, ym, yM;
 1.23527 +          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
 1.23528 +          if (x2<xm) xm = x2;
 1.23529 +          if (x2>xM) xM = x2;
 1.23530 +          if (x3<xm) xm = x3;
 1.23531 +          if (x3>xM) xM = x3;
 1.23532 +          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
 1.23533 +          if (y2<ym) ym = y2;
 1.23534 +          if (y2>yM) yM = y2;
 1.23535 +          if (y3<ym) ym = y3;
 1.23536 +          if (y3>yM) yM = y3;
 1.23537 +          if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
 1.23538 +            const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
 1.23539 +            if (double_sided || d<0) {
 1.23540 +              visibles(nb_visibles) = (unsigned int)l;
 1.23541 +              zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
 1.23542 +            }
 1.23543 +          }
 1.23544 +        } break;
 1.23545 +        default :
 1.23546 +          throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
 1.23547 +                                      pixel_type(),l,primitive.size());
 1.23548 +        }}
 1.23549 +      }
 1.23550 +      if (nb_visibles<=0) return *this;
 1.23551 +      CImg<uintT> permutations;
 1.23552 +      CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
 1.23553 +
 1.23554 +      // Compute light properties
 1.23555 +      CImg<floatT> lightprops;
 1.23556 +      switch (render_type) {
 1.23557 +      case 3 : { // Flat Shading
 1.23558 +        lightprops.assign(nb_visibles);
 1.23559 +        cimg_forX(lightprops,l) {
 1.23560 +          const CImg<tf>& primitive = primitives(visibles(permutations(l)));
 1.23561 +          const unsigned int psize = primitive.size();
 1.23562 +          if (psize==3 || psize==4 || psize==9 || psize==12) {
 1.23563 +            const unsigned int
 1.23564 +              i0 = (unsigned int)primitive(0),
 1.23565 +              i1 = (unsigned int)primitive(1),
 1.23566 +              i2 = (unsigned int)primitive(2);
 1.23567 +            const float
 1.23568 +              x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
 1.23569 +              x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
 1.23570 +              x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
 1.23571 +              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
 1.23572 +              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
 1.23573 +              nx = dy1*dz2 - dz1*dy2,
 1.23574 +              ny = dz1*dx2 - dx1*dz2,
 1.23575 +              nz = dx1*dy2 - dy1*dx2,
 1.23576 +              norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 1.23577 +              lx = X + (x0 + x1 + x2)/3 - lightx,
 1.23578 +              ly = Y + (y0 + y1 + y2)/3 - lighty,
 1.23579 +              lz = Z + (z0 + z1 + z2)/3 - lightz,
 1.23580 +              nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
 1.23581 +              factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
 1.23582 +            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
 1.23583 +          } else lightprops[l] = 1;
 1.23584 +        }
 1.23585 +      } break;
 1.23586 +
 1.23587 +      case 4 : // Gouraud Shading
 1.23588 +      case 5 : { // Phong-Shading
 1.23589 +        CImg<floatT> points_normals(nb_points,3,1,1,0);
 1.23590 +        for (unsigned int l=0; l<nb_visibles; ++l) {
 1.23591 +          const CImg<tf>& primitive = primitives[visibles(l)];
 1.23592 +          const unsigned int psize = primitive.size();
 1.23593 +          const bool
 1.23594 +            triangle_flag = (psize==3) || (psize==9),
 1.23595 +            rectangle_flag = (psize==4) || (psize==12);
 1.23596 +          if (triangle_flag || rectangle_flag) {
 1.23597 +            const unsigned int
 1.23598 +              i0 = (unsigned int)primitive(0),
 1.23599 +              i1 = (unsigned int)primitive(1),
 1.23600 +              i2 = (unsigned int)primitive(2),
 1.23601 +              i3 = rectangle_flag?(unsigned int)primitive(3):0;
 1.23602 +            const float
 1.23603 +              x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
 1.23604 +              x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
 1.23605 +              x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
 1.23606 +              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
 1.23607 +              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
 1.23608 +              nnx = dy1*dz2 - dz1*dy2,
 1.23609 +              nny = dz1*dx2 - dx1*dz2,
 1.23610 +              nnz = dx1*dy2 - dy1*dx2,
 1.23611 +              norm = 1e-5f + (float)cimg_std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
 1.23612 +              nx = nnx/norm,
 1.23613 +              ny = nny/norm,
 1.23614 +              nz = nnz/norm;
 1.23615 +            points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
 1.23616 +            points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
 1.23617 +            points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
 1.23618 +            if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
 1.23619 +          }
 1.23620 +        }
 1.23621 +
 1.23622 +        if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
 1.23623 +          points_normals(p,0) = -points_normals(p,0);
 1.23624 +          points_normals(p,1) = -points_normals(p,1);
 1.23625 +          points_normals(p,2) = -points_normals(p,2);
 1.23626 +        }
 1.23627 +
 1.23628 +        if (render_type==4) {
 1.23629 +          lightprops.assign(nb_points);
 1.23630 +          cimg_forX(lightprops,ll) {
 1.23631 +            const float
 1.23632 +              nx = points_normals(ll,0),
 1.23633 +              ny = points_normals(ll,1),
 1.23634 +              nz = points_normals(ll,2),
 1.23635 +              norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 1.23636 +              lx = (float)(X + points(ll,0) - lightx),
 1.23637 +              ly = (float)(Y + points(ll,1) - lighty),
 1.23638 +              lz = (float)(Z + points(ll,2) - lightz),
 1.23639 +              nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
 1.23640 +              factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
 1.23641 +            lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
 1.23642 +          }
 1.23643 +        } else {
 1.23644 +          const unsigned int
 1.23645 +            lw2 = light_texture.width/2 - 1,
 1.23646 +            lh2 = light_texture.height/2 - 1;
 1.23647 +          lightprops.assign(nb_points,2);
 1.23648 +          cimg_forX(lightprops,ll) {
 1.23649 +            const float
 1.23650 +              nx = points_normals(ll,0),
 1.23651 +              ny = points_normals(ll,1),
 1.23652 +              nz = points_normals(ll,2),
 1.23653 +              norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
 1.23654 +              nnx = nx/norm,
 1.23655 +              nny = ny/norm;
 1.23656 +            lightprops(ll,0) = lw2*(1 + nnx);
 1.23657 +            lightprops(ll,1) = lh2*(1 + nny);
 1.23658 +          }
 1.23659 +        }
 1.23660 +      } break;
 1.23661 +      }
 1.23662 +
 1.23663 +      // Draw visible primitives
 1.23664 +      const CImg<tc> default_color(1,dim,1,1,(tc)200);
 1.23665 +      { for (unsigned int l = 0; l<nb_visibles; ++l) {
 1.23666 +        const unsigned int n_primitive = visibles(permutations(l));
 1.23667 +        const CImg<tf>& primitive = primitives[n_primitive];
 1.23668 +        const CImg<tc>& color = n_primitive<colors.size?colors[n_primitive]:default_color;
 1.23669 +        const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
 1.23670 +#ifdef cimg_use_board
 1.23671 +        BoardLib::Board &board = *(BoardLib::Board*)pboard;
 1.23672 +#endif
 1.23673 +
 1.23674 +        switch (primitive.size()) {
 1.23675 +        case 1 : { // Colored point or sprite
 1.23676 +          const unsigned int n0 = (unsigned int)primitive[0];
 1.23677 +          const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
 1.23678 +          if (color.size()==dim) {
 1.23679 +            draw_point(x0,y0,color,opac);
 1.23680 +#ifdef cimg_use_board
 1.23681 +            if (pboard) {
 1.23682 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23683 +              board.fillCircle((float)x0,dimy()-(float)y0,0);
 1.23684 +            }
 1.23685 +#endif
 1.23686 +          } else {
 1.23687 +            const float z = Z + points(n0,2);
 1.23688 +            const int
 1.23689 +              factor = (int)(focale*100/(z+focale)),
 1.23690 +              sw = color.width*factor/200,
 1.23691 +              sh = color.height*factor/200;
 1.23692 +            if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
 1.23693 +              const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
 1.23694 +              _draw_object3d_sprite(x0-sw,y0-sh,color,opacities[n_primitive%nb_opacities],sprite);
 1.23695 +#ifdef cimg_use_board
 1.23696 +                if (pboard) {
 1.23697 +                  board.setPenColorRGBi(128,128,128);
 1.23698 +                  board.setFillColor(BoardLib::Color::none);
 1.23699 +                  board.drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
 1.23700 +                }
 1.23701 +#endif
 1.23702 +            }
 1.23703 +          }
 1.23704 +        } break;
 1.23705 +        case 2 : { // Colored line
 1.23706 +          const unsigned int
 1.23707 +            n0 = (unsigned int)primitive[0],
 1.23708 +            n1 = (unsigned int)primitive[1];
 1.23709 +          const int
 1.23710 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.23711 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
 1.23712 +          const float
 1.23713 +            z0 = points(n0,2) + Z + focale,
 1.23714 +            z1 = points(n1,2) + Z + focale;
 1.23715 +          if (render_type) {
 1.23716 +            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
 1.23717 +            else draw_line(x0,y0,x1,y1,color,opac);
 1.23718 +#ifdef cimg_use_board
 1.23719 +            if (pboard) {
 1.23720 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23721 +              board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
 1.23722 +            }
 1.23723 +#endif
 1.23724 +          } else {
 1.23725 +            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
 1.23726 +#ifdef cimg_use_board
 1.23727 +            if (pboard) {
 1.23728 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23729 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.23730 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.23731 +            }
 1.23732 +#endif
 1.23733 +          }
 1.23734 +        } break;
 1.23735 +        case 5 : { // Colored sphere
 1.23736 +          const unsigned int
 1.23737 +            n0 = (unsigned int)primitive[0],
 1.23738 +            n1 = (unsigned int)primitive[1],
 1.23739 +            n2 = (unsigned int)primitive[2];
 1.23740 +          const int
 1.23741 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
 1.23742 +          int radius;
 1.23743 +          if (n2) radius = (int)(n2*focale/(Z+points(n0,2)+focale));
 1.23744 +          else {
 1.23745 +            const int
 1.23746 +              x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 1.23747 +              deltax = x1-x0, deltay = y1-y0;
 1.23748 +            radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
 1.23749 +          }
 1.23750 +          switch (render_type) {
 1.23751 +          case 0 :
 1.23752 +            draw_point(x0,y0,color,opac);
 1.23753 +#ifdef cimg_use_board
 1.23754 +            if (pboard) {
 1.23755 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23756 +              board.fillCircle((float)x0,dimy()-(float)y0,0);
 1.23757 +            }
 1.23758 +#endif
 1.23759 +            break;
 1.23760 +          case 1 :
 1.23761 +            draw_circle(x0,y0,radius,color,opac,~0U);
 1.23762 +#ifdef cimg_use_board
 1.23763 +            if (pboard) {
 1.23764 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23765 +              board.setFillColor(BoardLib::Color::none);
 1.23766 +              board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
 1.23767 +            }
 1.23768 +#endif
 1.23769 +            break;
 1.23770 +          default :
 1.23771 +            draw_circle(x0,y0,radius,color,opac);
 1.23772 +#ifdef cimg_use_board
 1.23773 +            if (pboard) {
 1.23774 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23775 +              board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
 1.23776 +            }
 1.23777 +#endif
 1.23778 +            break;
 1.23779 +          }
 1.23780 +        } break;
 1.23781 +        case 6 : { // Textured line
 1.23782 +          const unsigned int
 1.23783 +            n0 = (unsigned int)primitive[0],
 1.23784 +            n1 = (unsigned int)primitive[1],
 1.23785 +            tx0 = (unsigned int)primitive[2],
 1.23786 +            ty0 = (unsigned int)primitive[3],
 1.23787 +            tx1 = (unsigned int)primitive[4],
 1.23788 +            ty1 = (unsigned int)primitive[5];
 1.23789 +          const int
 1.23790 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.23791 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
 1.23792 +          const float
 1.23793 +            z0 = points(n0,2) + Z + focale,
 1.23794 +            z1 = points(n1,2) + Z + focale;
 1.23795 +          if (render_type) {
 1.23796 +            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
 1.23797 +            else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
 1.23798 +#ifdef cimg_use_board
 1.23799 +            if (pboard) {
 1.23800 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.23801 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 1.23802 +            }
 1.23803 +#endif
 1.23804 +          } else {
 1.23805 +            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 1.23806 +              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
 1.23807 +#ifdef cimg_use_board
 1.23808 +            if (pboard) {
 1.23809 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.23810 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.23811 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.23812 +            }
 1.23813 +#endif
 1.23814 +          }
 1.23815 +        } break;
 1.23816 +        case 3 : { // Colored triangle
 1.23817 +          const unsigned int
 1.23818 +            n0 = (unsigned int)primitive[0],
 1.23819 +            n1 = (unsigned int)primitive[1],
 1.23820 +            n2 = (unsigned int)primitive[2];
 1.23821 +          const int
 1.23822 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.23823 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 1.23824 +            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
 1.23825 +          const float
 1.23826 +            z0 = points(n0,2) + Z + focale,
 1.23827 +            z1 = points(n1,2) + Z + focale,
 1.23828 +            z2 = points(n2,2) + Z + focale;
 1.23829 +          switch (render_type) {
 1.23830 +          case 0 :
 1.23831 +            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
 1.23832 +#ifdef cimg_use_board
 1.23833 +            if (pboard) {
 1.23834 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23835 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.23836 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.23837 +              board.drawCircle((float)x2,dimy()-(float)y2,0);
 1.23838 +            }
 1.23839 +#endif
 1.23840 +            break;
 1.23841 +          case 1 :
 1.23842 +            if (zbuffer)
 1.23843 +              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
 1.23844 +                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
 1.23845 +            else
 1.23846 +              draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
 1.23847 +                draw_line(x1,y1,x2,y2,color,opac);
 1.23848 +#ifdef cimg_use_board
 1.23849 +            if (pboard) {
 1.23850 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23851 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 1.23852 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 1.23853 +              board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23854 +            }
 1.23855 +#endif
 1.23856 +            break;
 1.23857 +          case 2 :
 1.23858 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
 1.23859 +            else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
 1.23860 +#ifdef cimg_use_board
 1.23861 +            if (pboard) {
 1.23862 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23863 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23864 +            }
 1.23865 +#endif
 1.23866 +            break;
 1.23867 +          case 3 :
 1.23868 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
 1.23869 +            else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
 1.23870 +#ifdef cimg_use_board
 1.23871 +            if (pboard) {
 1.23872 +              const float lp = cimg::min(lightprops(l),1);
 1.23873 +              board.setPenColorRGBi((unsigned char)(color[0]*lp),
 1.23874 +                                     (unsigned char)(color[1]*lp),
 1.23875 +                                     (unsigned char)(color[2]*lp),
 1.23876 +                                     (unsigned char)(opac*255));
 1.23877 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23878 +            }
 1.23879 +#endif
 1.23880 +            break;
 1.23881 +          case 4 :
 1.23882 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 1.23883 +            else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 1.23884 +#ifdef cimg_use_board
 1.23885 +            if (pboard) {
 1.23886 +              board.setPenColorRGBi((unsigned char)(color[0]),
 1.23887 +                                     (unsigned char)(color[1]),
 1.23888 +                                     (unsigned char)(color[2]),
 1.23889 +                                     (unsigned char)(opac*255));
 1.23890 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 1.23891 +                                         (float)x1,dimy()-(float)y1,lightprops(n1),
 1.23892 +                                         (float)x2,dimy()-(float)y2,lightprops(n2));
 1.23893 +            }
 1.23894 +#endif
 1.23895 +            break;
 1.23896 +          case 5 : {
 1.23897 +            const unsigned int
 1.23898 +              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 1.23899 +              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 1.23900 +              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
 1.23901 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
 1.23902 +            else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
 1.23903 +#ifdef cimg_use_board
 1.23904 +            if (pboard) {
 1.23905 +              const float
 1.23906 +                l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 1.23907 +                l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 1.23908 +                l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 1.23909 +              board.setPenColorRGBi((unsigned char)(color[0]),
 1.23910 +                                     (unsigned char)(color[1]),
 1.23911 +                                     (unsigned char)(color[2]),
 1.23912 +                                     (unsigned char)(opac*255));
 1.23913 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 1.23914 +                                         (float)x1,dimy()-(float)y1,l1,
 1.23915 +                                         (float)x2,dimy()-(float)y2,l2);
 1.23916 +            }
 1.23917 +#endif
 1.23918 +          } break;
 1.23919 +          }
 1.23920 +        } break;
 1.23921 +        case 4 : { // Colored rectangle
 1.23922 +          const unsigned int
 1.23923 +            n0 = (unsigned int)primitive[0],
 1.23924 +            n1 = (unsigned int)primitive[1],
 1.23925 +            n2 = (unsigned int)primitive[2],
 1.23926 +            n3 = (unsigned int)primitive[3];
 1.23927 +          const int
 1.23928 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.23929 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 1.23930 +            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
 1.23931 +            x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
 1.23932 +          const float
 1.23933 +            z0 = points(n0,2) + Z + focale,
 1.23934 +            z1 = points(n1,2) + Z + focale,
 1.23935 +            z2 = points(n2,2) + Z + focale,
 1.23936 +            z3 = points(n3,2) + Z + focale;
 1.23937 +          switch (render_type) {
 1.23938 +          case 0 :
 1.23939 +            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
 1.23940 +              draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
 1.23941 +#ifdef cimg_use_board
 1.23942 +            if (pboard) {
 1.23943 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23944 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.23945 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.23946 +              board.drawCircle((float)x2,dimy()-(float)y2,0);
 1.23947 +              board.drawCircle((float)x3,dimy()-(float)y3,0);
 1.23948 +            }
 1.23949 +#endif
 1.23950 +            break;
 1.23951 +          case 1 :
 1.23952 +            if (zbuffer)
 1.23953 +              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
 1.23954 +                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
 1.23955 +            else
 1.23956 +              draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
 1.23957 +                draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
 1.23958 +#ifdef cimg_use_board
 1.23959 +            if (pboard) {
 1.23960 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23961 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 1.23962 +              board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23963 +              board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.23964 +              board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 1.23965 +            }
 1.23966 +#endif
 1.23967 +            break;
 1.23968 +          case 2 :
 1.23969 +            if (zbuffer)
 1.23970 +              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);
 1.23971 +            else
 1.23972 +              draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
 1.23973 +#ifdef cimg_use_board
 1.23974 +            if (pboard) {
 1.23975 +              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 1.23976 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23977 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.23978 +            }
 1.23979 +#endif
 1.23980 +            break;
 1.23981 +          case 3 :
 1.23982 +            if (zbuffer)
 1.23983 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
 1.23984 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
 1.23985 +            else
 1.23986 +              _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
 1.23987 +                _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
 1.23988 +#ifdef cimg_use_board
 1.23989 +            if (pboard) {
 1.23990 +              const float lp = cimg::min(lightprops(l),1);
 1.23991 +              board.setPenColorRGBi((unsigned char)(color[0]*lp),
 1.23992 +                                     (unsigned char)(color[1]*lp),
 1.23993 +                                     (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
 1.23994 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.23995 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.23996 +            }
 1.23997 +#endif
 1.23998 +            break;
 1.23999 +          case 4 : {
 1.24000 +            const float
 1.24001 +              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
 1.24002 +              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
 1.24003 +            if (zbuffer)
 1.24004 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
 1.24005 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
 1.24006 +            else
 1.24007 +              draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
 1.24008 +                draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
 1.24009 +#ifdef cimg_use_board
 1.24010 +            if (pboard) {
 1.24011 +              board.setPenColorRGBi((unsigned char)(color[0]),
 1.24012 +                                     (unsigned char)(color[1]),
 1.24013 +                                     (unsigned char)(color[2]),
 1.24014 +                                     (unsigned char)(opac*255));
 1.24015 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 1.24016 +                                         (float)x1,dimy()-(float)y1,lightprop1,
 1.24017 +                                         (float)x2,dimy()-(float)y2,lightprop2);
 1.24018 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 1.24019 +                                         (float)x2,dimy()-(float)y2,lightprop2,
 1.24020 +                                         (float)x3,dimy()-(float)y3,lightprop3);
 1.24021 +            }
 1.24022 +#endif
 1.24023 +          } break;
 1.24024 +          case 5 : {
 1.24025 +            const unsigned int
 1.24026 +              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 1.24027 +              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 1.24028 +              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
 1.24029 +              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
 1.24030 +            if (zbuffer)
 1.24031 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 1.24032 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 1.24033 +            else
 1.24034 +              draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 1.24035 +                draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 1.24036 +#ifdef cimg_use_board
 1.24037 +            if (pboard) {
 1.24038 +              const float
 1.24039 +                l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 1.24040 +                l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 1.24041 +                l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 1.24042 +                l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 1.24043 +              board.setPenColorRGBi((unsigned char)(color[0]),
 1.24044 +                                     (unsigned char)(color[1]),
 1.24045 +                                     (unsigned char)(color[2]),
 1.24046 +                                     (unsigned char)(opac*255));
 1.24047 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 1.24048 +                                         (float)x1,dimy()-(float)y1,l1,
 1.24049 +                                         (float)x2,dimy()-(float)y2,l2);
 1.24050 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 1.24051 +                                         (float)x2,dimy()-(float)y2,l2,
 1.24052 +                                         (float)x3,dimy()-(float)y3,l3);
 1.24053 +            }
 1.24054 +#endif
 1.24055 +          } break;
 1.24056 +          }
 1.24057 +        } break;
 1.24058 +        case 9 : { // Textured triangle
 1.24059 +          const unsigned int
 1.24060 +            n0 = (unsigned int)primitive[0],
 1.24061 +            n1 = (unsigned int)primitive[1],
 1.24062 +            n2 = (unsigned int)primitive[2],
 1.24063 +            tx0 = (unsigned int)primitive[3],
 1.24064 +            ty0 = (unsigned int)primitive[4],
 1.24065 +            tx1 = (unsigned int)primitive[5],
 1.24066 +            ty1 = (unsigned int)primitive[6],
 1.24067 +            tx2 = (unsigned int)primitive[7],
 1.24068 +            ty2 = (unsigned int)primitive[8];
 1.24069 +          const int
 1.24070 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.24071 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 1.24072 +            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
 1.24073 +          const float
 1.24074 +            z0 = points(n0,2) + Z + focale,
 1.24075 +            z1 = points(n1,2) + Z + focale,
 1.24076 +            z2 = points(n2,2) + Z + focale;
 1.24077 +          switch (render_type) {
 1.24078 +          case 0 :
 1.24079 +            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 1.24080 +              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 1.24081 +              draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
 1.24082 +#ifdef cimg_use_board
 1.24083 +            if (pboard) {
 1.24084 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24085 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.24086 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.24087 +              board.drawCircle((float)x2,dimy()-(float)y2,0);
 1.24088 +            }
 1.24089 +#endif
 1.24090 +            break;
 1.24091 +          case 1 :
 1.24092 +            if (zbuffer)
 1.24093 +              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 1.24094 +                draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
 1.24095 +                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
 1.24096 +            else
 1.24097 +              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 1.24098 +                draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
 1.24099 +                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
 1.24100 +#ifdef cimg_use_board
 1.24101 +            if (pboard) {
 1.24102 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24103 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 1.24104 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 1.24105 +              board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24106 +            }
 1.24107 +#endif
 1.24108 +            break;
 1.24109 +          case 2 :
 1.24110 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
 1.24111 +            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
 1.24112 +#ifdef cimg_use_board
 1.24113 +            if (pboard) {
 1.24114 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24115 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24116 +            }
 1.24117 +#endif
 1.24118 +            break;
 1.24119 +          case 3 :
 1.24120 +            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
 1.24121 +            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
 1.24122 +#ifdef cimg_use_board
 1.24123 +            if (pboard) {
 1.24124 +              const float lp = cimg::min(lightprops(l),1);
 1.24125 +              board.setPenColorRGBi((unsigned char)(128*lp),
 1.24126 +                                     (unsigned char)(128*lp),
 1.24127 +                                     (unsigned char)(128*lp),
 1.24128 +                                     (unsigned char)(opac*255));
 1.24129 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24130 +            }
 1.24131 +#endif
 1.24132 +            break;
 1.24133 +          case 4 :
 1.24134 +            if (zbuffer)
 1.24135 +              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);
 1.24136 +            else
 1.24137 +              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);
 1.24138 +#ifdef cimg_use_board
 1.24139 +            if (pboard) {
 1.24140 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24141 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 1.24142 +                                         (float)x1,dimy()-(float)y1,lightprops(n1),
 1.24143 +                                         (float)x2,dimy()-(float)y2,lightprops(n2));
 1.24144 +            }
 1.24145 +#endif
 1.24146 +            break;
 1.24147 +          case 5 :
 1.24148 +            if (zbuffer)
 1.24149 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
 1.24150 +                            (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
 1.24151 +                            (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
 1.24152 +                            (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
 1.24153 +                            opac);
 1.24154 +            else
 1.24155 +              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
 1.24156 +                            (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
 1.24157 +                            (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
 1.24158 +                            (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
 1.24159 +                            opac);
 1.24160 +#ifdef cimg_use_board
 1.24161 +            if (pboard) {
 1.24162 +              const float
 1.24163 +                l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 1.24164 +                l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 1.24165 +                l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 1.24166 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24167 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
 1.24168 +            }
 1.24169 +#endif
 1.24170 +            break;
 1.24171 +          }
 1.24172 +        } break;
 1.24173 +        case 12 : { // Textured rectangle
 1.24174 +          const unsigned int
 1.24175 +            n0 = (unsigned int)primitive[0],
 1.24176 +            n1 = (unsigned int)primitive[1],
 1.24177 +            n2 = (unsigned int)primitive[2],
 1.24178 +            n3 = (unsigned int)primitive[3],
 1.24179 +            tx0 = (unsigned int)primitive[4],
 1.24180 +            ty0 = (unsigned int)primitive[5],
 1.24181 +            tx1 = (unsigned int)primitive[6],
 1.24182 +            ty1 = (unsigned int)primitive[7],
 1.24183 +            tx2 = (unsigned int)primitive[8],
 1.24184 +            ty2 = (unsigned int)primitive[9],
 1.24185 +            tx3 = (unsigned int)primitive[10],
 1.24186 +            ty3 = (unsigned int)primitive[11];
 1.24187 +          const int
 1.24188 +            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
 1.24189 +            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
 1.24190 +            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
 1.24191 +            x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
 1.24192 +          const float
 1.24193 +            z0 = points(n0,2) + Z + focale,
 1.24194 +            z1 = points(n1,2) + Z + focale,
 1.24195 +            z2 = points(n2,2) + Z + focale,
 1.24196 +            z3 = points(n3,2) + Z + focale;
 1.24197 +          switch (render_type) {
 1.24198 +          case 0 :
 1.24199 +            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 1.24200 +              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 1.24201 +              draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
 1.24202 +              draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
 1.24203 +#ifdef cimg_use_board
 1.24204 +            if (pboard) {
 1.24205 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24206 +              board.drawCircle((float)x0,dimy()-(float)y0,0);
 1.24207 +              board.drawCircle((float)x1,dimy()-(float)y1,0);
 1.24208 +              board.drawCircle((float)x2,dimy()-(float)y2,0);
 1.24209 +              board.drawCircle((float)x3,dimy()-(float)y3,0);
 1.24210 +            }
 1.24211 +#endif
 1.24212 +            break;
 1.24213 +          case 1 :
 1.24214 +            if (zbuffer)
 1.24215 +              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 1.24216 +                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
 1.24217 +                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
 1.24218 +                draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
 1.24219 +            else
 1.24220 +              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
 1.24221 +                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
 1.24222 +                draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
 1.24223 +                draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
 1.24224 +#ifdef cimg_use_board
 1.24225 +            if (pboard) {
 1.24226 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24227 +              board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 1.24228 +              board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24229 +              board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.24230 +              board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 1.24231 +            }
 1.24232 +#endif
 1.24233 +            break;
 1.24234 +          case 2 :
 1.24235 +            if (zbuffer)
 1.24236 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
 1.24237 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
 1.24238 +            else
 1.24239 +              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
 1.24240 +                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
 1.24241 +#ifdef cimg_use_board
 1.24242 +            if (pboard) {
 1.24243 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24244 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24245 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.24246 +            }
 1.24247 +#endif
 1.24248 +            break;
 1.24249 +          case 3 :
 1.24250 +            if (zbuffer)
 1.24251 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
 1.24252 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
 1.24253 +            else
 1.24254 +              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
 1.24255 +                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
 1.24256 +#ifdef cimg_use_board
 1.24257 +            if (pboard) {
 1.24258 +              const float lp = cimg::min(lightprops(l),1);
 1.24259 +              board.setPenColorRGBi((unsigned char)(128*lp),
 1.24260 +                                     (unsigned char)(128*lp),
 1.24261 +                                     (unsigned char)(128*lp),
 1.24262 +                                     (unsigned char)(opac*255));
 1.24263 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 1.24264 +              board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 1.24265 +            }
 1.24266 +#endif
 1.24267 +            break;
 1.24268 +          case 4 : {
 1.24269 +            const float
 1.24270 +              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
 1.24271 +              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
 1.24272 +            if (zbuffer)
 1.24273 +              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
 1.24274 +                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
 1.24275 +            else
 1.24276 +              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
 1.24277 +                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
 1.24278 +#ifdef cimg_use_board
 1.24279 +            if (pboard) {
 1.24280 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24281 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 1.24282 +                                         (float)x1,dimy()-(float)y1,lightprop1,
 1.24283 +                                         (float)x2,dimy()-(float)y2,lightprop2);
 1.24284 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 1.24285 +                                         (float)x2,dimy()-(float)y2,lightprop2,
 1.24286 +                                         (float)x3,dimy()-(float)y3,lightprop3);
 1.24287 +            }
 1.24288 +#endif
 1.24289 +          } break;
 1.24290 +          case 5 : {
 1.24291 +            const unsigned int
 1.24292 +              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
 1.24293 +              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
 1.24294 +              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
 1.24295 +              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
 1.24296 +            if (zbuffer)
 1.24297 +              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).
 1.24298 +                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);
 1.24299 +            else
 1.24300 +              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).
 1.24301 +                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);
 1.24302 +#ifdef cimg_use_board
 1.24303 +            if (pboard) {
 1.24304 +              const float
 1.24305 +                l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 1.24306 +                l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 1.24307 +                l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 1.24308 +                l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 1.24309 +              board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 1.24310 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 1.24311 +                                         (float)x1,dimy()-(float)y1,l1,
 1.24312 +                                         (float)x2,dimy()-(float)y2,l2);
 1.24313 +              board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 1.24314 +                                         (float)x2,dimy()-(float)y2,l2,
 1.24315 +                                         (float)x3,dimy()-(float)y3,l3);
 1.24316 +            }
 1.24317 +#endif
 1.24318 +          } break;
 1.24319 +          }
 1.24320 +        } break;
 1.24321 +        }
 1.24322 +      }
 1.24323 +      }
 1.24324 +      return *this;
 1.24325 +    }
 1.24326 +
 1.24327 +    //! Draw a 3D object.
 1.24328 +    /**
 1.24329 +       \param X = X-coordinate of the 3d object position
 1.24330 +       \param Y = Y-coordinate of the 3d object position
 1.24331 +       \param Z = Z-coordinate of the 3d object position
 1.24332 +       \param points = Image N*3 describing 3D point coordinates
 1.24333 +       \param primitives = List of P primitives
 1.24334 +       \param colors = List of P color (or textures)
 1.24335 +       \param opacities = Image of P opacities
 1.24336 +       \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)
 1.24337 +       \param double_sided = Tell if object faces have two sides or are oriented.
 1.24338 +       \param focale = length of the focale
 1.24339 +       \param lightx = X-coordinate of the light
 1.24340 +       \param lighty = Y-coordinate of the light
 1.24341 +       \param lightz = Z-coordinate of the light
 1.24342 +       \param specular_shine = Shininess of the object
 1.24343 +    **/
 1.24344 +    template<typename tp, typename tf, typename tc, typename to>
 1.24345 +    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 1.24346 +                           const CImg<tp>& points, const CImgList<tf>& primitives,
 1.24347 +                           const CImgList<tc>& colors, const CImgList<to>& opacities,
 1.24348 +                           const unsigned int render_type=4,
 1.24349 +                           const bool double_sided=false, const float focale=500,
 1.24350 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24351 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24352 +                           float *const zbuffer=0) {
 1.24353 +      if (!points) return *this;
 1.24354 +      return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 1.24355 +                            primitives,colors,opacities,opacities.size,
 1.24356 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24357 +    }
 1.24358 +
 1.24359 +#ifdef cimg_use_board
 1.24360 +    template<typename tp, typename tf, typename tc, typename to>
 1.24361 +    CImg<T>& draw_object3d(BoardLib::Board& board,
 1.24362 +                           const float x0, const float y0, const float z0,
 1.24363 +                           const CImg<tp>& points, const CImgList<tf>& primitives,
 1.24364 +                           const CImgList<tc>& colors, const CImgList<to>& opacities,
 1.24365 +                           const unsigned int render_type=4,
 1.24366 +                           const bool double_sided=false, const float focale=500,
 1.24367 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24368 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24369 +                           float *const zbuffer=0) {
 1.24370 +      if (!points) return *this;
 1.24371 +      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 1.24372 +                            primitives,colors,opacities,opacities.size,
 1.24373 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24374 +    }
 1.24375 +#endif
 1.24376 +
 1.24377 +    //! Draw a 3D object.
 1.24378 +    template<typename tp, typename tf, typename tc, typename to>
 1.24379 +    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 1.24380 +                           const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.24381 +                           const CImgList<tc>& colors, const CImgList<to>& opacities,
 1.24382 +                           const unsigned int render_type=4,
 1.24383 +                           const bool double_sided=false, const float focale=500,
 1.24384 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24385 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24386 +                           float *const zbuffer=0) {
 1.24387 +      if (!points) return *this;
 1.24388 +      return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
 1.24389 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24390 +    }
 1.24391 +
 1.24392 +#ifdef cimg_use_board
 1.24393 +    template<typename tp, typename tf, typename tc, typename to>
 1.24394 +    CImg<T>& draw_object3d(BoardLib::Board& board,
 1.24395 +                           const float x0, const float y0, const float z0,
 1.24396 +                           const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.24397 +                           const CImgList<tc>& colors, const CImgList<to>& opacities,
 1.24398 +                           const unsigned int render_type=4,
 1.24399 +                           const bool double_sided=false, const float focale=500,
 1.24400 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24401 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24402 +                           float *const zbuffer=0) {
 1.24403 +      if (!points) return *this;
 1.24404 +      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
 1.24405 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24406 +    }
 1.24407 +#endif
 1.24408 +
 1.24409 +    //! Draw a 3D object.
 1.24410 +    template<typename tp, typename tf, typename tc, typename to>
 1.24411 +    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 1.24412 +                           const CImg<tp>& points, const CImgList<tf>& primitives,
 1.24413 +                           const CImgList<tc>& colors, const CImg<to>& opacities,
 1.24414 +                           const unsigned int render_type=4,
 1.24415 +                           const bool double_sided=false, const float focale=500,
 1.24416 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24417 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24418 +                           float *const zbuffer=0) {
 1.24419 +      if (!points) return *this;
 1.24420 +      return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
 1.24421 +                            primitives,colors,opacities,opacities.size(),
 1.24422 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24423 +    }
 1.24424 +
 1.24425 +#ifdef cimg_use_board
 1.24426 +    template<typename tp, typename tf, typename tc, typename to>
 1.24427 +    CImg<T>& draw_object3d(BoardLib::Board& board,
 1.24428 +                           const float x0, const float y0, const float z0,
 1.24429 +                           const CImg<tp>& points, const CImgList<tf>& primitives,
 1.24430 +                           const CImgList<tc>& colors, const CImg<to>& opacities,
 1.24431 +                           const unsigned int render_type=4,
 1.24432 +                           const bool double_sided=false, const float focale=500,
 1.24433 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24434 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24435 +                           float *const zbuffer=0) {
 1.24436 +      if (!points) return *this;
 1.24437 +      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width
 1.24438 +                            ,primitives,colors,opacities,opacities.size(),
 1.24439 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24440 +    }
 1.24441 +#endif
 1.24442 +
 1.24443 +    //! Draw a 3D object.
 1.24444 +    template<typename tp, typename tf, typename tc, typename to>
 1.24445 +    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 1.24446 +                           const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.24447 +                           const CImgList<tc>& colors, const CImg<to>& opacities,
 1.24448 +                           const unsigned int render_type=4,
 1.24449 +                           const bool double_sided=false, const float focale=500,
 1.24450 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24451 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24452 +                           float *const zbuffer=0) {
 1.24453 +      if (!points) return *this;
 1.24454 +      return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
 1.24455 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24456 +    }
 1.24457 +
 1.24458 +#ifdef cimg_use_board
 1.24459 +    template<typename tp, typename tf, typename tc, typename to>
 1.24460 +    CImg<T>& draw_object3d(BoardLib::Board& board,
 1.24461 +                           const float x0, const float y0, const float z0,
 1.24462 +                           const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.24463 +                           const CImgList<tc>& colors, const CImg<to>& opacities,
 1.24464 +                           const unsigned int render_type=4,
 1.24465 +                           const bool double_sided=false, const float focale=500,
 1.24466 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24467 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24468 +                           float *const zbuffer=0) {
 1.24469 +      if (!points) return *this;
 1.24470 +      return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
 1.24471 +                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 1.24472 +    }
 1.24473 +#endif
 1.24474 +
 1.24475 +    //! Draw a 3D object.
 1.24476 +    template<typename tp, typename tf, typename tc>
 1.24477 +    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
 1.24478 +                           const tp& points, const CImgList<tf>& primitives,
 1.24479 +                           const CImgList<tc>& colors,
 1.24480 +                           const unsigned int render_type=4,
 1.24481 +                           const bool double_sided=false, const float focale=500,
 1.24482 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24483 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24484 +                           float *const zbuffer=0) {
 1.24485 +      static const CImg<floatT> opacities;
 1.24486 +      return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
 1.24487 +                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
 1.24488 +    }
 1.24489 +
 1.24490 +#ifdef cimg_use_board
 1.24491 +    template<typename tp, typename tf, typename tc, typename to>
 1.24492 +    CImg<T>& draw_object3d(BoardLib::Board& board,
 1.24493 +                           const float x0, const float y0, const float z0,
 1.24494 +                           const tp& points, const CImgList<tf>& primitives,
 1.24495 +                           const CImgList<tc>& colors,
 1.24496 +                           const unsigned int render_type=4,
 1.24497 +                           const bool double_sided=false, const float focale=500,
 1.24498 +                           const float lightx=0, const float lighty=0, const float lightz=-5000,
 1.24499 +                           const float specular_light=0.2f, const float specular_shine=0.1f,
 1.24500 +                           float *const zbuffer=0) {
 1.24501 +      static const CImg<floatT> opacities;
 1.24502 +      return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
 1.24503 +                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
 1.24504 +    }
 1.24505 +#endif
 1.24506 +
 1.24507 +    //@}
 1.24508 +    //----------------------------
 1.24509 +    //
 1.24510 +    //! \name Image Filtering
 1.24511 +    //@{
 1.24512 +    //----------------------------
 1.24513 +
 1.24514 +    //! Compute the correlation of the instance image by a mask.
 1.24515 +    /**
 1.24516 +       The correlation of the instance image \p *this by the mask \p mask is defined to be :
 1.24517 +
 1.24518 +       res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k)
 1.24519 +
 1.24520 +       \param mask = the correlation kernel.
 1.24521 +       \param cond = the border condition type (0=zero, 1=dirichlet)
 1.24522 +       \param weighted_correl = enable local normalization.
 1.24523 +    **/
 1.24524 +    template<typename t>
 1.24525 +    CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
 1.24526 +      return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
 1.24527 +    }
 1.24528 +
 1.24529 +    template<typename t>
 1.24530 +    CImg<typename cimg::superset2<T,t,float>::type> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
 1.24531 +                                                                  const bool weighted_correl=false) const {
 1.24532 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.24533 +      if (is_empty()) return *this;
 1.24534 +      if (!mask || mask.dim!=1)
 1.24535 +        throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
 1.24536 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 1.24537 +      CImg<Ttfloat> dest(width,height,depth,dim);
 1.24538 +      if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
 1.24539 +        // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
 1.24540 +        switch (mask.depth) {
 1.24541 +        case 3 : {
 1.24542 +          T I[27] = { 0 };
 1.24543 +          cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24544 +            (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
 1.24545 +             I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 1.24546 +             I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
 1.24547 +             I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 1.24548 +             I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 1.24549 +             I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 1.24550 +             I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
 1.24551 +             I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 1.24552 +             I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
 1.24553 +          if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
 1.24554 +            const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
 1.24555 +                                           I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
 1.24556 +                                           I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
 1.24557 +                                           I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 1.24558 +                                           I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 1.24559 +                                           I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 1.24560 +                                           I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
 1.24561 +                                           I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 1.24562 +                                           I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
 1.24563 +            if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24564 +          }
 1.24565 +        } break;
 1.24566 +        case 2 : {
 1.24567 +          T I[8] = { 0 };
 1.24568 +          cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24569 +            (I[0]*mask[0] + I[1]*mask[1] +
 1.24570 +             I[2]*mask[2] + I[3]*mask[3] +
 1.24571 +             I[4]*mask[4] + I[5]*mask[5] +
 1.24572 +             I[6]*mask[6] + I[7]*mask[7]);
 1.24573 +          if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
 1.24574 +            const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 1.24575 +                                           I[2]*I[2] + I[3]*I[3] +
 1.24576 +                                           I[4]*I[4] + I[5]*I[5] +
 1.24577 +                                           I[6]*I[6] + I[7]*I[7]);
 1.24578 +            if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24579 +          }
 1.24580 +        } break;
 1.24581 +        default :
 1.24582 +        case 1 :
 1.24583 +          switch (mask.width) {
 1.24584 +          case 6 : {
 1.24585 +            T I[36] = { 0 };
 1.24586 +            cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24587 +              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 1.24588 +               I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 1.24589 +               I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 1.24590 +               I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 1.24591 +               I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
 1.24592 +               I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
 1.24593 +            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 1.24594 +              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] +
 1.24595 +                                             I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 1.24596 +                                             I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 1.24597 +                                             I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 1.24598 +                                             I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
 1.24599 +                                             I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
 1.24600 +              if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24601 +            }
 1.24602 +          } break;
 1.24603 +          case 5 : {
 1.24604 +            T I[25] = { 0 };
 1.24605 +            cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24606 +              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
 1.24607 +               I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
 1.24608 +               I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 1.24609 +               I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
 1.24610 +               I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
 1.24611 +            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 1.24612 +              const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
 1.24613 +                                             I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
 1.24614 +                                             I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 1.24615 +                                             I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
 1.24616 +                                             I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
 1.24617 +              if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24618 +            }
 1.24619 +          } break;
 1.24620 +          case 4 : {
 1.24621 +            T I[16] = { 0 };
 1.24622 +            cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24623 +              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
 1.24624 +               I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
 1.24625 +               I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 1.24626 +               I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
 1.24627 +            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
 1.24628 +              const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
 1.24629 +                                             I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
 1.24630 +                                             I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 1.24631 +                                             I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
 1.24632 +              if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24633 +            }
 1.24634 +          } break;
 1.24635 +          case 3 : {
 1.24636 +            T I[9] = { 0 };
 1.24637 +            cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24638 +              (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 1.24639 +               I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 1.24640 +               I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 1.24641 +            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
 1.24642 +              const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
 1.24643 +                                             I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
 1.24644 +                                             I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
 1.24645 +              if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24646 +            }
 1.24647 +          } break;
 1.24648 +          case 2 : {
 1.24649 +            T I[4] = { 0 };
 1.24650 +            cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 1.24651 +              (I[0]*mask[0] + I[1]*mask[1] +
 1.24652 +               I[2]*mask[2] + I[3]*mask[3]);
 1.24653 +            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
 1.24654 +              const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 1.24655 +                                             I[2]*I[2] + I[3]*I[3]);
 1.24656 +              if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
 1.24657 +            }
 1.24658 +          } break;
 1.24659 +          case 1 : (dest.assign(*this))*=mask(0); break;
 1.24660 +          }
 1.24661 +        }
 1.24662 +      } else { // Generic version for other masks
 1.24663 +        const int
 1.24664 +          mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 1.24665 +          mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 1.24666 +          mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 1.24667 +        cimg_forV(*this,v)
 1.24668 +          if (!weighted_correl) { // Classical correlation
 1.24669 +            for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24670 +              Ttfloat val = 0;
 1.24671 +              for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 1.24672 +                val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 1.24673 +              dest(x,y,z,v) = (Ttfloat)val;
 1.24674 +            }
 1.24675 +            if (cond)
 1.24676 +              cimg_forYZV(*this,y,z,v)
 1.24677 +                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24678 +                  Ttfloat val = 0;
 1.24679 +                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 1.24680 +                    val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 1.24681 +                  dest(x,y,z,v) = (Ttfloat)val;
 1.24682 +                }
 1.24683 +            else
 1.24684 +              cimg_forYZV(*this,y,z,v)
 1.24685 +                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24686 +                  Ttfloat val = 0;
 1.24687 +                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 1.24688 +                    val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
 1.24689 +                  dest(x,y,z,v) = (Ttfloat)val;
 1.24690 +                }
 1.24691 +          } else { // Weighted correlation
 1.24692 +            for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24693 +              Ttfloat val = 0, weight = 0;
 1.24694 +              for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24695 +                const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
 1.24696 +                val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 1.24697 +                weight+=cval*cval;
 1.24698 +              }
 1.24699 +              dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 1.24700 +            }
 1.24701 +            if (cond)
 1.24702 +              cimg_forYZV(*this,y,z,v)
 1.24703 +                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24704 +                  Ttfloat val = 0, weight = 0;
 1.24705 +                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24706 +                    const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
 1.24707 +                    val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 1.24708 +                    weight+=cval*cval;
 1.24709 +                  }
 1.24710 +                  dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 1.24711 +                }
 1.24712 +            else
 1.24713 +              cimg_forYZV(*this,y,z,v)
 1.24714 +                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24715 +                  Ttfloat val = 0, weight = 0;
 1.24716 +                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24717 +                    const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
 1.24718 +                    val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 1.24719 +                    weight+=cval*cval;
 1.24720 +                  }
 1.24721 +                  dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
 1.24722 +                }
 1.24723 +          }
 1.24724 +      }
 1.24725 +      return dest;
 1.24726 +    }
 1.24727 +
 1.24728 +    //! Compute the convolution of the image by a mask.
 1.24729 +    /**
 1.24730 +       The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
 1.24731 +
 1.24732 +       res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)
 1.24733 +
 1.24734 +       \param mask = the correlation kernel.
 1.24735 +       \param cond = the border condition type (0=zero, 1=dirichlet)
 1.24736 +       \param weighted_convol = enable local normalization.
 1.24737 +    **/
 1.24738 +    template<typename t>
 1.24739 +    CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
 1.24740 +      return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
 1.24741 +    }
 1.24742 +
 1.24743 +    template<typename t>
 1.24744 +    CImg<typename cimg::superset2<T,t,float>::type> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
 1.24745 +                                                                 const bool weighted_convol=false) const {
 1.24746 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.24747 +      if (is_empty()) return *this;
 1.24748 +      if (!mask || mask.dim!=1)
 1.24749 +        throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
 1.24750 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 1.24751 +      return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
 1.24752 +    }
 1.24753 +
 1.24754 +    //! Return the erosion of the image by a structuring element.
 1.24755 +    template<typename t>
 1.24756 +    CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
 1.24757 +      return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
 1.24758 +    }
 1.24759 +
 1.24760 +    template<typename t>
 1.24761 +    CImg<typename cimg::superset<T,t>::type> get_erode(const CImg<t>& mask, const unsigned int cond=1,
 1.24762 +                                                       const bool weighted_erosion=false) const {
 1.24763 +      typedef typename cimg::superset<T,t>::type Tt;
 1.24764 +      if (is_empty()) return *this;
 1.24765 +      if (!mask || mask.dim!=1)
 1.24766 +        throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
 1.24767 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 1.24768 +      CImg<Tt> dest(width,height,depth,dim);
 1.24769 +      const int
 1.24770 +        mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 1.24771 +        mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 1.24772 +        mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 1.24773 +      cimg_forV(*this,v)
 1.24774 +        if (!weighted_erosion) { // Classical erosion
 1.24775 +          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24776 +            Tt min_val = cimg::type<Tt>::max();
 1.24777 +            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24778 +              const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 1.24779 +              if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 1.24780 +            }
 1.24781 +            dest(x,y,z,v) = min_val;
 1.24782 +          }
 1.24783 +          if (cond)
 1.24784 +            cimg_forYZV(*this,y,z,v)
 1.24785 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24786 +                Tt min_val = cimg::type<Tt>::max();
 1.24787 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24788 +                  const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
 1.24789 +                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 1.24790 +                }
 1.24791 +                dest(x,y,z,v) = min_val;
 1.24792 +              }
 1.24793 +          else
 1.24794 +            cimg_forYZV(*this,y,z,v)
 1.24795 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24796 +                Tt min_val = cimg::type<Tt>::max();
 1.24797 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24798 +                  const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
 1.24799 +                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 1.24800 +                }
 1.24801 +                dest(x,y,z,v) = min_val;
 1.24802 +              }
 1.24803 +        } else { // Weighted erosion
 1.24804 +          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24805 +            Tt min_val = cimg::type<Tt>::max();
 1.24806 +            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24807 +              const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24808 +              const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
 1.24809 +              if (mval && cval<min_val) min_val = cval;
 1.24810 +            }
 1.24811 +            dest(x,y,z,v) = min_val;
 1.24812 +          }
 1.24813 +          if (cond)
 1.24814 +            cimg_forYZV(*this,y,z,v)
 1.24815 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24816 +                Tt min_val = cimg::type<Tt>::max();
 1.24817 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24818 +                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24819 +                  const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
 1.24820 +                  if (mval && cval<min_val) min_val = cval;
 1.24821 +                }
 1.24822 +                dest(x,y,z,v) = min_val;
 1.24823 +              }
 1.24824 +          else
 1.24825 +            cimg_forYZV(*this,y,z,v)
 1.24826 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24827 +                Tt min_val = cimg::type<Tt>::max();
 1.24828 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24829 +                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24830 +                  const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
 1.24831 +                  if (mval && cval<min_val) min_val = cval;
 1.24832 +                }
 1.24833 +                dest(x,y,z,v) = min_val;
 1.24834 +              }
 1.24835 +        }
 1.24836 +      return dest;
 1.24837 +    }
 1.24838 +
 1.24839 +    //! Erode the image by a square structuring element of size n.
 1.24840 +    CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
 1.24841 +      if (n<2) return *this;
 1.24842 +      return get_erode(n,cond).transfer_to(*this);
 1.24843 +    }
 1.24844 +
 1.24845 +    CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
 1.24846 +      static CImg<T> mask;
 1.24847 +      if (n<2) return *this;
 1.24848 +      if (mask.width!=n) mask.assign(n,n,1,1,1);
 1.24849 +      const CImg<T> res = get_erode(mask,cond,false);
 1.24850 +      if (n>20) mask.assign();
 1.24851 +      return res;
 1.24852 +    }
 1.24853 +
 1.24854 +    //! Dilate the image by a structuring element.
 1.24855 +    template<typename t>
 1.24856 +    CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
 1.24857 +      return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
 1.24858 +    }
 1.24859 +
 1.24860 +    template<typename t>
 1.24861 +    CImg<typename cimg::superset<T,t>::type> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
 1.24862 +                                                        const bool weighted_dilatation=false) const {
 1.24863 +      typedef typename cimg::superset<T,t>::type Tt;
 1.24864 +      if (is_empty()) return *this;
 1.24865 +      if (!mask || mask.dim!=1)
 1.24866 +        throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
 1.24867 +                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
 1.24868 +      CImg<Tt> dest(width,height,depth,dim);
 1.24869 +      const int
 1.24870 +        mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 1.24871 +        mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 1.24872 +        mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
 1.24873 +      cimg_forV(*this,v)
 1.24874 +        if (!weighted_dilatation) { // Classical dilatation
 1.24875 +          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24876 +            Tt max_val = cimg::type<Tt>::min();
 1.24877 +            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24878 +              const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 1.24879 +              if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 1.24880 +            }
 1.24881 +            dest(x,y,z,v) = max_val;
 1.24882 +          }
 1.24883 +          if (cond)
 1.24884 +            cimg_forYZV(*this,y,z,v)
 1.24885 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24886 +                Tt max_val = cimg::type<Tt>::min();
 1.24887 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24888 +                  const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
 1.24889 +                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 1.24890 +                }
 1.24891 +                dest(x,y,z,v) = max_val;
 1.24892 +              }
 1.24893 +          else
 1.24894 +            cimg_forYZV(*this,y,z,v)
 1.24895 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24896 +                Tt max_val = cimg::type<Tt>::min();
 1.24897 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24898 +                  const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
 1.24899 +                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 1.24900 +                }
 1.24901 +                dest(x,y,z,v) = max_val;
 1.24902 +              }
 1.24903 +        } else { // Weighted dilatation
 1.24904 +          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 1.24905 +            Tt max_val = cimg::type<Tt>::min();
 1.24906 +            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24907 +              const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24908 +              const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
 1.24909 +              if (mval && cval>max_val) max_val = cval;
 1.24910 +            }
 1.24911 +            dest(x,y,z,v) = max_val;
 1.24912 +          }
 1.24913 +          if (cond)
 1.24914 +            cimg_forYZV(*this,y,z,v)
 1.24915 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24916 +                Tt max_val = cimg::type<Tt>::min();
 1.24917 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24918 +                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24919 +                  const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
 1.24920 +                  if (mval && cval>max_val) max_val = cval;
 1.24921 +                }
 1.24922 +                dest(x,y,z,v) = max_val;
 1.24923 +              }
 1.24924 +          else
 1.24925 +            cimg_forYZV(*this,y,z,v)
 1.24926 +              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 1.24927 +                Tt max_val = cimg::type<Tt>::min();
 1.24928 +                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 1.24929 +                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 1.24930 +                  const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
 1.24931 +                  if (mval && cval>max_val) max_val = cval;
 1.24932 +                }
 1.24933 +                dest(x,y,z,v) = max_val;
 1.24934 +              }
 1.24935 +        }
 1.24936 +      return dest;
 1.24937 +    }
 1.24938 +
 1.24939 +    //! Dilate the image by a square structuring element of size n.
 1.24940 +    CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
 1.24941 +      if (n<2) return *this;
 1.24942 +      return get_dilate(n,cond).transfer_to(*this);
 1.24943 +    }
 1.24944 +
 1.24945 +    CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
 1.24946 +      static CImg<T> mask;
 1.24947 +      if (n<2) return *this;
 1.24948 +      if (mask.width!=n) mask.assign(n,n,1,1,1);
 1.24949 +      const CImg<T> res = get_dilate(mask,cond,false);
 1.24950 +      if (n>20) mask.assign();
 1.24951 +      return res;
 1.24952 +    }
 1.24953 +
 1.24954 +    //! Add noise to the image.
 1.24955 +    /**
 1.24956 +       \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
 1.24957 +       \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper, 3=Poisson, 4=Rician.
 1.24958 +       \return A noisy version of the instance image.
 1.24959 +    **/
 1.24960 +    CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
 1.24961 +      if (!is_empty()) {
 1.24962 +        double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
 1.24963 +        Tfloat m = 0, M = 0;
 1.24964 +        if (nsigma==0 && noise_type!=3) return *this;
 1.24965 +        if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
 1.24966 +        if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
 1.24967 +        switch (noise_type) {
 1.24968 +        case 0 : { // Gaussian noise
 1.24969 +          cimg_for(*this,ptr,T) {
 1.24970 +            double val = *ptr + nsigma*cimg::grand();
 1.24971 +            if (val>max) val = max;
 1.24972 +            if (val<min) val = min;
 1.24973 +            *ptr = (T)val;
 1.24974 +          }
 1.24975 +        } break;
 1.24976 +        case 1 : { // Uniform noise
 1.24977 +          cimg_for(*this,ptr,T) {
 1.24978 +            double val = *ptr + nsigma*cimg::crand();
 1.24979 +            if (val>max) val = max;
 1.24980 +            if (val<min) val = min;
 1.24981 +            *ptr = (T)val;
 1.24982 +          }
 1.24983 +        } break;
 1.24984 +        case 2 : { // Salt & Pepper noise
 1.24985 +          if (nsigma<0) nsigma = -nsigma;
 1.24986 +          if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
 1.24987 +          cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
 1.24988 +        } break;
 1.24989 +
 1.24990 +        case 3 : { // Poisson Noise
 1.24991 +          cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
 1.24992 +        } break;
 1.24993 +
 1.24994 +        case 4 : { // Rice noise
 1.24995 +          const double sqrt2 = (double)cimg_std::sqrt(2.0);
 1.24996 +          cimg_for(*this,ptr,T) {
 1.24997 +            const double
 1.24998 +              val0 = (double)*ptr/sqrt2,
 1.24999 +              re = val0 + nsigma*cimg::grand(),
 1.25000 +              im = val0 + nsigma*cimg::grand();
 1.25001 +            double val = cimg_std::sqrt(re*re + im*im);
 1.25002 +            if (val>max) val = max;
 1.25003 +            if (val<min) val = min;
 1.25004 +            *ptr = (T)val;
 1.25005 +          }
 1.25006 +        } break;
 1.25007 +        default :
 1.25008 +          throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
 1.25009 +                                      "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
 1.25010 +        }
 1.25011 +      }
 1.25012 +      return *this;
 1.25013 +    }
 1.25014 +
 1.25015 +    CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
 1.25016 +      return (+*this).noise(sigma,noise_type);
 1.25017 +    }
 1.25018 +
 1.25019 +    //! Compute the result of the Deriche filter.
 1.25020 +    /**
 1.25021 +       The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
 1.25022 +       order 0,1 or 2 of an image.
 1.25023 +    **/
 1.25024 +    CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
 1.25025 +#define _cimg_deriche2_apply \
 1.25026 +  Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
 1.25027 +  T xp = (T)0; \
 1.25028 +  if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
 1.25029 +  for (int m=0; m<N; ++m) { \
 1.25030 +    const T xc = *ptrX; ptrX+=off; \
 1.25031 +    const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
 1.25032 +    xp = xc; yb = yp; yp = yc; \
 1.25033 +  } \
 1.25034 +  T xn = (T)0, xa = (T)0; \
 1.25035 +  Tfloat yn = 0, ya = 0; \
 1.25036 +  if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
 1.25037 +  for (int n=N-1; n>=0; --n) { \
 1.25038 +    const T xc = *(ptrX-=off); \
 1.25039 +    const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
 1.25040 +    xa = xn; xn = xc; ya = yn; yn = yc; \
 1.25041 +    *ptrX = (T)(*(--ptrY)+yc); \
 1.25042 +  }
 1.25043 +      if (sigma<0)
 1.25044 +        throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",
 1.25045 +                                    pixel_type(),sigma);
 1.25046 +      if (is_empty() || (sigma<0.1 && !order)) return *this;
 1.25047 +      const float
 1.25048 +        nsigma = sigma<0.1f?0.1f:sigma,
 1.25049 +        alpha = 1.695f/nsigma,
 1.25050 +        ema = (float)cimg_std::exp(-alpha),
 1.25051 +        ema2 = (float)cimg_std::exp(-2*alpha),
 1.25052 +        b1 = -2*ema,
 1.25053 +        b2 = ema2;
 1.25054 +      float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
 1.25055 +      switch (order) {
 1.25056 +      case 0 : {
 1.25057 +        const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
 1.25058 +        a0 = k;
 1.25059 +        a1 = k*(alpha-1)*ema;
 1.25060 +        a2 = k*(alpha+1)*ema;
 1.25061 +        a3 = -k*ema2;
 1.25062 +      } break;
 1.25063 +      case 1 : {
 1.25064 +        const float k = (1-ema)*(1-ema)/ema;
 1.25065 +        a0 = k*ema;
 1.25066 +        a1 = a3 = 0;
 1.25067 +        a2 = -a0;
 1.25068 +      } break;
 1.25069 +      case 2 : {
 1.25070 +        const float
 1.25071 +          ea = (float)cimg_std::exp(-alpha),
 1.25072 +          k = -(ema2-1)/(2*alpha*ema),
 1.25073 +          kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
 1.25074 +        a0 = kn;
 1.25075 +        a1 = -kn*(1+k*alpha)*ema;
 1.25076 +        a2 = kn*(1-k*alpha)*ema;
 1.25077 +        a3 = -kn*ema2;
 1.25078 +      } break;
 1.25079 +      default :
 1.25080 +        throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
 1.25081 +                                    pixel_type(),order);
 1.25082 +      }
 1.25083 +      coefp = (a0+a1)/(1+b1+b2);
 1.25084 +      coefn = (a2+a3)/(1+b1+b2);
 1.25085 +      switch (cimg::uncase(axis)) {
 1.25086 +      case 'x' : {
 1.25087 +        const int N = width, off = 1;
 1.25088 +        CImg<Tfloat> Y(N);
 1.25089 +        cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
 1.25090 +      } break;
 1.25091 +      case 'y' : {
 1.25092 +        const int N = height, off = width;
 1.25093 +        CImg<Tfloat> Y(N);
 1.25094 +        cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
 1.25095 +      } break;
 1.25096 +      case 'z' : {
 1.25097 +        const int N = depth, off = width*height;
 1.25098 +        CImg<Tfloat> Y(N);
 1.25099 +        cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
 1.25100 +      } break;
 1.25101 +      case 'v' : {
 1.25102 +        const int N = dim, off = width*height*depth;
 1.25103 +        CImg<Tfloat> Y(N);
 1.25104 +        cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
 1.25105 +      } break;
 1.25106 +      }
 1.25107 +      return *this;
 1.25108 +    }
 1.25109 +
 1.25110 +    CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
 1.25111 +      return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
 1.25112 +    }
 1.25113 +
 1.25114 +    //! Return a blurred version of the image, using a Canny-Deriche filter.
 1.25115 +    /**
 1.25116 +       Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
 1.25117 +    **/
 1.25118 +    CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
 1.25119 +      if (!is_empty()) {
 1.25120 +        if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
 1.25121 +        if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
 1.25122 +        if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
 1.25123 +      }
 1.25124 +      return *this;
 1.25125 +    }
 1.25126 +
 1.25127 +    CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
 1.25128 +                          const bool cond=true) const {
 1.25129 +      return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
 1.25130 +    }
 1.25131 +
 1.25132 +    //! Return a blurred version of the image, using a Canny-Deriche filter.
 1.25133 +    CImg<T>& blur(const float sigma, const bool cond=true) {
 1.25134 +      return blur(sigma,sigma,sigma,cond);
 1.25135 +    }
 1.25136 +
 1.25137 +    CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
 1.25138 +      return CImg<Tfloat>(*this,false).blur(sigma,cond);
 1.25139 +    }
 1.25140 +
 1.25141 +    //! Blur the image anisotropically following a field of diffusion tensors.
 1.25142 +    /**
 1.25143 +       \param G = Field of square roots of diffusion tensors used to drive the smoothing.
 1.25144 +       \param amplitude = amplitude of the smoothing.
 1.25145 +       \param dl = spatial discretization.
 1.25146 +       \param da = angular discretization.
 1.25147 +       \param gauss_prec = precision of the gaussian function.
 1.25148 +       \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 1.25149 +       \param fast_approx = Tell to use the fast approximation or not.
 1.25150 +    **/
 1.25151 +    template<typename t>
 1.25152 +    CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
 1.25153 +                              const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) {
 1.25154 +#define _cimg_valign2d(i,j) \
 1.25155 +    { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
 1.25156 +    if (u*curru + v*currv<0) { u=-u; v=-v; }}
 1.25157 +#define _cimg_valign3d(i,j,k) \
 1.25158 +    { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
 1.25159 +    if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
 1.25160 +
 1.25161 +      // Check arguments and init variables
 1.25162 +      if (!is_empty() && amplitude>0) {
 1.25163 +        if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
 1.25164 +          throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
 1.25165 +                                      pixel_type(),G.width,G.height,G.depth,G.dim);
 1.25166 +
 1.25167 +        const float sqrt2amplitude = (float)cimg_std::sqrt(2*amplitude);
 1.25168 +        const bool threed = (G.dim>=6);
 1.25169 +        const int
 1.25170 +          dx1 = dimx()-1,
 1.25171 +          dy1 = dimy()-1,
 1.25172 +          dz1 = dimz()-1;
 1.25173 +        CImg<Tfloat>
 1.25174 +          dest(width,height,depth,dim,0),
 1.25175 +          W(width,height,depth,threed?4:3),
 1.25176 +          tmp(dim);
 1.25177 +        int N = 0;
 1.25178 +
 1.25179 +        if (threed)
 1.25180 +          // 3D version of the algorithm
 1.25181 +          for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
 1.25182 +            const float
 1.25183 +              phir = (float)(phi*cimg::valuePI/180),
 1.25184 +              datmp = (float)(da/cimg_std::cos(phir)),
 1.25185 +              da2 = datmp<1?360.0f:datmp;
 1.25186 +
 1.25187 +            for (float theta=0; theta<360; (theta+=da2),++N) {
 1.25188 +              const float
 1.25189 +                thetar = (float)(theta*cimg::valuePI/180),
 1.25190 +                vx = (float)(cimg_std::cos(thetar)*cimg_std::cos(phir)),
 1.25191 +                vy = (float)(cimg_std::sin(thetar)*cimg_std::cos(phir)),
 1.25192 +                vz = (float)cimg_std::sin(phir);
 1.25193 +              const t
 1.25194 +                *pa = G.ptr(0,0,0,0),
 1.25195 +                *pb = G.ptr(0,0,0,1),
 1.25196 +                *pc = G.ptr(0,0,0,2),
 1.25197 +                *pd = G.ptr(0,0,0,3),
 1.25198 +                *pe = G.ptr(0,0,0,4),
 1.25199 +                *pf = G.ptr(0,0,0,5);
 1.25200 +              Tfloat
 1.25201 +                *pd0 = W.ptr(0,0,0,0),
 1.25202 +                *pd1 = W.ptr(0,0,0,1),
 1.25203 +                *pd2 = W.ptr(0,0,0,2),
 1.25204 +                *pd3 = W.ptr(0,0,0,3);
 1.25205 +              cimg_forXYZ(G,xg,yg,zg) {
 1.25206 +                const t
 1.25207 +                  a = *(pa++), b = *(pb++), c = *(pc++),
 1.25208 +                  d = *(pd++), e = *(pe++), f = *(pf++);
 1.25209 +                const float
 1.25210 +                  u = (float)(a*vx + b*vy + c*vz),
 1.25211 +                  v = (float)(b*vx + d*vy + e*vz),
 1.25212 +                  w = (float)(c*vx + e*vy + f*vz),
 1.25213 +                  n = (float)cimg_std::sqrt(1e-5+u*u+v*v+w*w),
 1.25214 +                  dln = dl/n;
 1.25215 +                *(pd0++) = (Tfloat)(u*dln);
 1.25216 +                *(pd1++) = (Tfloat)(v*dln);
 1.25217 +                *(pd2++) = (Tfloat)(w*dln);
 1.25218 +                *(pd3++) = (Tfloat)n;
 1.25219 +              }
 1.25220 +
 1.25221 +              cimg_forXYZ(*this,x,y,z) {
 1.25222 +                tmp.fill(0);
 1.25223 +                const float
 1.25224 +                  cu = (float)W(x,y,z,0),
 1.25225 +                  cv = (float)W(x,y,z,1),
 1.25226 +                  cw = (float)W(x,y,z,2),
 1.25227 +                  n = (float)W(x,y,z,3),
 1.25228 +                  fsigma = (float)(n*sqrt2amplitude),
 1.25229 +                  length = gauss_prec*fsigma,
 1.25230 +                  fsigma2 = 2*fsigma*fsigma;
 1.25231 +                float
 1.25232 +                  S = 0,
 1.25233 +                  pu = cu,
 1.25234 +                  pv = cv,
 1.25235 +                  pw = cw,
 1.25236 +                  X = (float)x,
 1.25237 +                  Y = (float)y,
 1.25238 +                  Z = (float)z;
 1.25239 +
 1.25240 +                switch (interpolation_type) {
 1.25241 +                case 0 : {
 1.25242 +                  // Nearest neighbor
 1.25243 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 1.25244 +                    const int
 1.25245 +                      cx = (int)(X+0.5f),
 1.25246 +                      cy = (int)(Y+0.5f),
 1.25247 +                      cz = (int)(Z+0.5f);
 1.25248 +                    float
 1.25249 +                      u = (float)W(cx,cy,cz,0),
 1.25250 +                      v = (float)W(cx,cy,cz,1),
 1.25251 +                      w = (float)W(cx,cy,cz,2);
 1.25252 +                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 1.25253 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
 1.25254 +                    else {
 1.25255 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25256 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
 1.25257 +                      S+=coef;
 1.25258 +                    }
 1.25259 +                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 1.25260 +                  }
 1.25261 +                } break;
 1.25262 +
 1.25263 +                case 1 : {
 1.25264 +                  // Linear interpolation
 1.25265 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 1.25266 +                    const int
 1.25267 +                      cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 1.25268 +                      cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
 1.25269 +                      cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
 1.25270 +                    const float
 1.25271 +                      curru = (float)W(cx,cy,cz,0),
 1.25272 +                      currv = (float)W(cx,cy,cz,1),
 1.25273 +                      currw = (float)W(cx,cy,cz,2);
 1.25274 +                    _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 1.25275 +                    _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 1.25276 +                    _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 1.25277 +                    _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 1.25278 +                    _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 1.25279 +                    _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 1.25280 +                    _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 1.25281 +                    _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 1.25282 +                    _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
 1.25283 +                    float
 1.25284 +                      u = (float)(W._linear_atXYZ(X,Y,Z,0)),
 1.25285 +                      v = (float)(W._linear_atXYZ(X,Y,Z,1)),
 1.25286 +                      w = (float)(W._linear_atXYZ(X,Y,Z,2));
 1.25287 +                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 1.25288 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
 1.25289 +                    else {
 1.25290 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25291 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
 1.25292 +                      S+=coef;
 1.25293 +                    }
 1.25294 +                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 1.25295 +                  }
 1.25296 +                } break;
 1.25297 +
 1.25298 +                default : {
 1.25299 +                  // 2nd order Runge Kutta
 1.25300 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
 1.25301 +                    const int
 1.25302 +                      cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 1.25303 +                      cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
 1.25304 +                      cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
 1.25305 +                    const float
 1.25306 +                      curru = (float)W(cx,cy,cz,0),
 1.25307 +                      currv = (float)W(cx,cy,cz,1),
 1.25308 +                      currw = (float)W(cx,cy,cz,2);
 1.25309 +                    _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 1.25310 +                    _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 1.25311 +                    _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 1.25312 +                    _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 1.25313 +                    _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 1.25314 +                    _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 1.25315 +                    _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 1.25316 +                    _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 1.25317 +                    _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
 1.25318 +                    const float
 1.25319 +                      u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
 1.25320 +                      v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
 1.25321 +                      w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
 1.25322 +                    float
 1.25323 +                      u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
 1.25324 +                      v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
 1.25325 +                      w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
 1.25326 +                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
 1.25327 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
 1.25328 +                    else {
 1.25329 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25330 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
 1.25331 +                      S+=coef;
 1.25332 +                    }
 1.25333 +                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
 1.25334 +                  }
 1.25335 +                } break;
 1.25336 +                }
 1.25337 +                if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
 1.25338 +                else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
 1.25339 +                cimg_plugin_greycstoration_count;
 1.25340 +              }
 1.25341 +            }
 1.25342 +          } else
 1.25343 +            // 2D version of the algorithm
 1.25344 +            for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
 1.25345 +              const float
 1.25346 +                thetar = (float)(theta*cimg::valuePI/180),
 1.25347 +                vx = (float)(cimg_std::cos(thetar)),
 1.25348 +                vy = (float)(cimg_std::sin(thetar));
 1.25349 +              const t
 1.25350 +                *pa = G.ptr(0,0,0,0),
 1.25351 +                *pb = G.ptr(0,0,0,1),
 1.25352 +                *pc = G.ptr(0,0,0,2);
 1.25353 +              Tfloat
 1.25354 +                *pd0 = W.ptr(0,0,0,0),
 1.25355 +                *pd1 = W.ptr(0,0,0,1),
 1.25356 +                *pd2 = W.ptr(0,0,0,2);
 1.25357 +              cimg_forXY(G,xg,yg) {
 1.25358 +                const t a = *(pa++), b = *(pb++), c = *(pc++);
 1.25359 +                const float
 1.25360 +                  u = (float)(a*vx + b*vy),
 1.25361 +                  v = (float)(b*vx + c*vy),
 1.25362 +                  n = (float)cimg_std::sqrt(1e-5+u*u+v*v),
 1.25363 +                  dln = dl/n;
 1.25364 +                *(pd0++) = (Tfloat)(u*dln);
 1.25365 +                *(pd1++) = (Tfloat)(v*dln);
 1.25366 +                *(pd2++) = (Tfloat)n;
 1.25367 +              }
 1.25368 +
 1.25369 +              cimg_forXY(*this,x,y) {
 1.25370 +                tmp.fill(0);
 1.25371 +                const float
 1.25372 +                  cu = (float)W(x,y,0,0),
 1.25373 +                  cv = (float)W(x,y,0,1),
 1.25374 +                  n = (float)W(x,y,0,2),
 1.25375 +                  fsigma = (float)(n*sqrt2amplitude),
 1.25376 +                  length = gauss_prec*fsigma,
 1.25377 +                  fsigma2 = 2*fsigma*fsigma;
 1.25378 +                float
 1.25379 +                  S = 0,
 1.25380 +                  pu = cu,
 1.25381 +                  pv = cv,
 1.25382 +                  X = (float)x,
 1.25383 +                  Y = (float)y;
 1.25384 +
 1.25385 +                switch (interpolation_type) {
 1.25386 +
 1.25387 +                case 0 : {
 1.25388 +                  // Nearest-neighbor interpolation for 2D images
 1.25389 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 1.25390 +                    const int
 1.25391 +                      cx = (int)(X+0.5f),
 1.25392 +                      cy = (int)(Y+0.5f);
 1.25393 +                    float
 1.25394 +                      u = (float)W(cx,cy,0,0),
 1.25395 +                      v = (float)W(cx,cy,0,1);
 1.25396 +                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 1.25397 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
 1.25398 +                    else {
 1.25399 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25400 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
 1.25401 +                      S+=coef;
 1.25402 +                    }
 1.25403 +                    X+=(pu=u); Y+=(pv=v);
 1.25404 +                  }
 1.25405 +                } break;
 1.25406 +
 1.25407 +                case 1 : {
 1.25408 +                  // Linear interpolation for 2D images
 1.25409 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 1.25410 +                    const int
 1.25411 +                      cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 1.25412 +                      cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
 1.25413 +                    const float
 1.25414 +                      curru = (float)W(cx,cy,0,0),
 1.25415 +                      currv = (float)W(cx,cy,0,1);
 1.25416 +                    _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 1.25417 +                    _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 1.25418 +                    _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
 1.25419 +                    float
 1.25420 +                      u = (float)(W._linear_atXY(X,Y,0,0)),
 1.25421 +                      v = (float)(W._linear_atXY(X,Y,0,1));
 1.25422 +                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 1.25423 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
 1.25424 +                    else {
 1.25425 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25426 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
 1.25427 +                      S+=coef;
 1.25428 +                    }
 1.25429 +                    X+=(pu=u); Y+=(pv=v);
 1.25430 +                  }
 1.25431 +                } break;
 1.25432 +
 1.25433 +                default : {
 1.25434 +                  // 2nd-order Runge-kutta interpolation for 2D images
 1.25435 +                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
 1.25436 +                    const int
 1.25437 +                      cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
 1.25438 +                      cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
 1.25439 +                    const float
 1.25440 +                      curru = (float)W(cx,cy,0,0),
 1.25441 +                      currv = (float)W(cx,cy,0,1);
 1.25442 +                    _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 1.25443 +                    _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 1.25444 +                    _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
 1.25445 +                    const float
 1.25446 +                      u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),
 1.25447 +                      v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
 1.25448 +                    float
 1.25449 +                      u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)),
 1.25450 +                      v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
 1.25451 +                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
 1.25452 +                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
 1.25453 +                    else {
 1.25454 +                      const float coef = (float)cimg_std::exp(-l*l/fsigma2);
 1.25455 +                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
 1.25456 +                      S+=coef;
 1.25457 +                    }
 1.25458 +                    X+=(pu=u); Y+=(pv=v);
 1.25459 +                  }
 1.25460 +                }
 1.25461 +                }
 1.25462 +                if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
 1.25463 +                else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
 1.25464 +                cimg_plugin_greycstoration_count;
 1.25465 +              }
 1.25466 +            }
 1.25467 +        const Tfloat *ptrs = dest.data+dest.size();
 1.25468 +        const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
 1.25469 +        cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
 1.25470 +      }
 1.25471 +      return *this;
 1.25472 +    }
 1.25473 +
 1.25474 +    template<typename t>
 1.25475 +    CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
 1.25476 +                                 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
 1.25477 +      return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 1.25478 +    }
 1.25479 +
 1.25480 +    //! Blur an image in an anisotropic way.
 1.25481 +    /**
 1.25482 +       \param mask Binary mask.
 1.25483 +       \param amplitude Amplitude of the anisotropic blur.
 1.25484 +       \param sharpness Contour preservation.
 1.25485 +       \param anisotropy Smoothing anisotropy.
 1.25486 +       \param alpha Image pre-blurring (gaussian).
 1.25487 +       \param sigma Regularity of the tensor-valued geometry.
 1.25488 +       \param dl Spatial discretization.
 1.25489 +       \param da Angular discretization.
 1.25490 +       \param gauss_prec Precision of the gaussian function.
 1.25491 +       \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 1.25492 +       \param fast_approx Tell to use the fast approximation or not
 1.25493 +       \param geom_factor Geometry factor.
 1.25494 +    **/
 1.25495 +    template<typename tm>
 1.25496 +    CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 1.25497 +                              const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
 1.25498 +                              const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
 1.25499 +                              const float geom_factor=1) {
 1.25500 +      if (!is_empty() && amplitude>0) {
 1.25501 +        if (amplitude==0) return *this;
 1.25502 +        if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
 1.25503 +          throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), "
 1.25504 +                                      "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n"
 1.25505 +                                      "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], "
 1.25506 +                                      "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.",
 1.25507 +                                      pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
 1.25508 +        const bool threed = (depth>1), no_mask = mask.is_empty();
 1.25509 +        const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
 1.25510 +        CImg<floatT> blurred = CImg<floatT>(*this,false).blur(alpha);
 1.25511 +        if (geom_factor>0) blurred*=geom_factor;
 1.25512 +        else blurred.normalize(0,-geom_factor);
 1.25513 +
 1.25514 +        if (threed) { // Field for 3D volumes
 1.25515 +          cimg_plugin_greycstoration_lock;
 1.25516 +          CImg<floatT> val(3), vec(3,3), G(blurred.get_structure_tensor());
 1.25517 +          if (sigma>0) G.blur(sigma);
 1.25518 +          cimg_forXYZ(*this,x,y,z) {
 1.25519 +            if (no_mask || mask(x,y,z)) {
 1.25520 +              G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
 1.25521 +              const float l1 = val[2], l2 = val[1], l3 = val[0],
 1.25522 +                ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
 1.25523 +                vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
 1.25524 +                wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
 1.25525 +                n1 = (float)cimg_std::pow(1+l1+l2+l3,-power1),
 1.25526 +                n2 = (float)cimg_std::pow(1+l1+l2+l3,-power2);
 1.25527 +              G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
 1.25528 +              G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
 1.25529 +              G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
 1.25530 +              G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
 1.25531 +              G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
 1.25532 +              G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
 1.25533 +            } 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;
 1.25534 +            cimg_plugin_greycstoration_count;
 1.25535 +          }
 1.25536 +          cimg_plugin_greycstoration_unlock;
 1.25537 +          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 1.25538 +        } else { // Field for 2D images
 1.25539 +          cimg_plugin_greycstoration_lock;
 1.25540 +          CImg<floatT> val(2), vec(2,2), G(blurred.get_structure_tensor());
 1.25541 +          if (sigma>0) G.blur(sigma);
 1.25542 +          cimg_forXY(*this,x,y) {
 1.25543 +            if (no_mask || mask(x,y)) {
 1.25544 +              G.get_tensor_at(x,y).symmetric_eigen(val,vec);
 1.25545 +              const float l1 = val[1], l2 = val[0],
 1.25546 +                ux = vec(1,0), uy = vec(1,1),
 1.25547 +                vx = vec(0,0), vy = vec(0,1),
 1.25548 +                n1 = (float)cimg_std::pow(1+l1+l2,-power1),
 1.25549 +                n2 = (float)cimg_std::pow(1+l1+l2,-power2);
 1.25550 +              G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
 1.25551 +              G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
 1.25552 +              G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
 1.25553 +            } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
 1.25554 +            cimg_plugin_greycstoration_count;
 1.25555 +          }
 1.25556 +          cimg_plugin_greycstoration_unlock;
 1.25557 +          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 1.25558 +        }
 1.25559 +      }
 1.25560 +      return *this;
 1.25561 +    }
 1.25562 +
 1.25563 +    template<typename tm>
 1.25564 +    CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 1.25565 +                                 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 1.25566 +                                 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
 1.25567 +                                 const bool fast_approx=true, const float geom_factor=1) const {
 1.25568 +      return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 1.25569 +    }
 1.25570 +
 1.25571 +    //! Blur an image following in an anisotropic way.
 1.25572 +    CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 1.25573 +                              const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
 1.25574 +                              const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
 1.25575 +                              const float geom_factor=1) {
 1.25576 +      return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 1.25577 +    }
 1.25578 +
 1.25579 +    CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 1.25580 +                                 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 1.25581 +                                 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
 1.25582 +                                 const bool fast_approx=true, const float geom_factor=1) const {
 1.25583 +      return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 1.25584 +    }
 1.25585 +
 1.25586 +    //! Blur an image using the bilateral filter.
 1.25587 +    /**
 1.25588 +       \param sigmax Amount of blur along the X-axis.
 1.25589 +       \param sigmay Amount of blur along the Y-axis.
 1.25590 +       \param sigmaz Amount of blur along the Z-axis.
 1.25591 +       \param sigmar Amount of blur along the range axis.
 1.25592 +       \param bgridx Size of the bilateral grid along the X-axis.
 1.25593 +       \param bgridy Size of the bilateral grid along the Y-axis.
 1.25594 +       \param bgridz Size of the bilateral grid along the Z-axis.
 1.25595 +       \param bgridr Size of the bilateral grid along the range axis.
 1.25596 +       \param interpolation_type Use interpolation for image slicing.
 1.25597 +       \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
 1.25598 +       (extended for 3D volumetric images).
 1.25599 +    **/
 1.25600 +    CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 1.25601 +                            const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 1.25602 +                            const bool interpolation_type=true) {
 1.25603 +      T m, M = maxmin(m);
 1.25604 +      const float range = (float)(1.0f+M-m);
 1.25605 +      const unsigned int
 1.25606 +        bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
 1.25607 +        by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
 1.25608 +        bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
 1.25609 +        br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
 1.25610 +        bx = bx0>0?bx0:1,
 1.25611 +        by = by0>0?by0:1,
 1.25612 +        bz = bz0>0?bz0:1,
 1.25613 +        br = br0>0?br0:1;
 1.25614 +      const float
 1.25615 +        nsigmax = sigmax*bx/width,
 1.25616 +        nsigmay = sigmay*by/height,
 1.25617 +        nsigmaz = sigmaz*bz/depth,
 1.25618 +        nsigmar = sigmar*br/range;
 1.25619 +      if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
 1.25620 +        const bool threed = depth>1;
 1.25621 +        if (threed) { // 3d version of the algorithm
 1.25622 +          CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
 1.25623 +          cimg_forV(*this,k) {
 1.25624 +            bgrid.fill(0); bgridw.fill(0);
 1.25625 +            cimg_forXYZ(*this,x,y,z) {
 1.25626 +              const T val = (*this)(x,y,z,k);
 1.25627 +              const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 1.25628 +              bgrid(X,Y,Z,R) = (float)val;
 1.25629 +              bgridw(X,Y,Z,R) = 1;
 1.25630 +            }
 1.25631 +            bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 1.25632 +            bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 1.25633 +            if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
 1.25634 +              const T val = (*this)(x,y,z,k);
 1.25635 +              const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
 1.25636 +                bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
 1.25637 +              (*this)(x,y,z,k) = (T)(bval0/bval1);
 1.25638 +            } else cimg_forXYZ(*this,x,y,z) {
 1.25639 +              const T val = (*this)(x,y,z,k);
 1.25640 +              const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 1.25641 +              const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
 1.25642 +              (*this)(x,y,z,k) = (T)(bval0/bval1);
 1.25643 +            }
 1.25644 +          }
 1.25645 +        } else { // 2d version of the algorithm
 1.25646 +          CImg<floatT> bgrid(bx,by,br,2);
 1.25647 +          cimg_forV(*this,k) {
 1.25648 +            bgrid.fill(0);
 1.25649 +            cimg_forXY(*this,x,y) {
 1.25650 +              const T val = (*this)(x,y,k);
 1.25651 +              const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 1.25652 +              bgrid(X,Y,R,0) = (float)val;
 1.25653 +              bgrid(X,Y,R,1) = 1;
 1.25654 +            }
 1.25655 +            bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
 1.25656 +            if (interpolation_type) cimg_forXY(*this,x,y) {
 1.25657 +              const T val = (*this)(x,y,k);
 1.25658 +              const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
 1.25659 +                bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
 1.25660 +              (*this)(x,y,k) = (T)(bval0/bval1);
 1.25661 +            } else cimg_forXY(*this,x,y) {
 1.25662 +              const T val = (*this)(x,y,k);
 1.25663 +              const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 1.25664 +              const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
 1.25665 +              (*this)(x,y,k) = (T)(bval0/bval1);
 1.25666 +            }
 1.25667 +          }
 1.25668 +        }
 1.25669 +      }
 1.25670 +      return *this;
 1.25671 +    }
 1.25672 +
 1.25673 +    CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 1.25674 +                               const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 1.25675 +                               const bool interpolation_type=true) const {
 1.25676 +      return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
 1.25677 +    }
 1.25678 +
 1.25679 +    //! Blur an image using the bilateral filter.
 1.25680 +    CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 1.25681 +                            const bool interpolation_type=true) {
 1.25682 +      return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 1.25683 +    }
 1.25684 +
 1.25685 +    CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 1.25686 +                               const bool interpolation_type=true) const {
 1.25687 +      return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 1.25688 +    }
 1.25689 +
 1.25690 +    //! Blur an image in its patch-based space.
 1.25691 +    CImg<T>& blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
 1.25692 +                        const unsigned int lookup_size=4, const bool fast_approx=true) {
 1.25693 +
 1.25694 +#define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
 1.25695 +#define _cimg_blur_patch_slowfunc(x) cimg_std::exp(-(x))
 1.25696 +#define _cimg_blur_patch3d(N,func) { \
 1.25697 +  const unsigned int N3 = N*N*N; \
 1.25698 +  cimg_for##N##XYZ(*this,x,y,z) { \
 1.25699 +    cimg_plugin_greycstoration_count; \
 1.25700 +    cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
 1.25701 +    const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
 1.25702 +    float sum_weights = 0; \
 1.25703 +    cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
 1.25704 +      cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
 1.25705 +      float distance2 = 0; \
 1.25706 +      const T *pQ = Q.end(); \
 1.25707 +      cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
 1.25708 +      distance2/=Pnorm; \
 1.25709 +      const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
 1.25710 +        alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)func(alldist); \
 1.25711 +      sum_weights+=weight; \
 1.25712 +      { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
 1.25713 +    } \
 1.25714 +    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)); \
 1.25715 +  }}
 1.25716 +#define _cimg_blur_patch2d(N,func) { \
 1.25717 +  const unsigned int N2 = N*N; \
 1.25718 +  cimg_for##N##XY(*this,x,y) { \
 1.25719 +    cimg_plugin_greycstoration_count; \
 1.25720 +    cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
 1.25721 +    const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
 1.25722 +    float sum_weights = 0; \
 1.25723 +    cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
 1.25724 +      cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
 1.25725 +      float distance2 = 0; \
 1.25726 +      const T *pQ = Q.end(); \
 1.25727 +      cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
 1.25728 +      distance2/=Pnorm; \
 1.25729 +      const float dx = (float)p-x, dy = (float)q-y, \
 1.25730 +        alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
 1.25731 +      sum_weights+=weight; \
 1.25732 +      { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
 1.25733 +    } \
 1.25734 +    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)); \
 1.25735 +  }}
 1.25736 +
 1.25737 +      CImg<Tfloat> res(width,height,depth,dim,0);
 1.25738 +      CImg<T> P(patch_size*patch_size*dim), Q(P);
 1.25739 +      const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
 1.25740 +      const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
 1.25741 +      if (depth>1) switch (patch_size) { // 3D version
 1.25742 +      case 2 :
 1.25743 +        if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
 1.25744 +        else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
 1.25745 +        break;
 1.25746 +      case 3 :
 1.25747 +        if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
 1.25748 +        else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
 1.25749 +        break;
 1.25750 +      default : {
 1.25751 +        const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 1.25752 +        cimg_forXYZ(*this,x,y,z) {
 1.25753 +          cimg_plugin_greycstoration_count;
 1.25754 +          P = get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
 1.25755 +          const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
 1.25756 +          float sum_weights = 0;
 1.25757 +          cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
 1.25758 +            (Q = get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
 1.25759 +            const float
 1.25760 +              dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
 1.25761 +              distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
 1.25762 +              weight = (float)cimg_std::exp(-distance2);
 1.25763 +            sum_weights+=weight;
 1.25764 +            cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
 1.25765 +          }
 1.25766 +          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));
 1.25767 +        }
 1.25768 +      }
 1.25769 +      } else switch (patch_size) { // 2D version
 1.25770 +      case 2 :
 1.25771 +        if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
 1.25772 +        else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
 1.25773 +        break;
 1.25774 +      case 3 :
 1.25775 +        if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
 1.25776 +        else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
 1.25777 +        break;
 1.25778 +      case 4 :
 1.25779 +        if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
 1.25780 +        else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
 1.25781 +        break;
 1.25782 +      case 5 :
 1.25783 +        if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
 1.25784 +        else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
 1.25785 +        break;
 1.25786 +      case 6 :
 1.25787 +        if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
 1.25788 +        else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
 1.25789 +        break;
 1.25790 +      case 7 :
 1.25791 +        if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
 1.25792 +        else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
 1.25793 +        break;
 1.25794 +      case 8 :
 1.25795 +        if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
 1.25796 +        else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
 1.25797 +        break;
 1.25798 +      case 9 :
 1.25799 +        if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
 1.25800 +        else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
 1.25801 +        break;
 1.25802 +      default : {
 1.25803 +        const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 1.25804 +        cimg_forXY(*this,x,y) {
 1.25805 +          cimg_plugin_greycstoration_count;
 1.25806 +          P = get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
 1.25807 +          const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
 1.25808 +          float sum_weights = 0;
 1.25809 +          cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 1.25810 +            (Q = get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
 1.25811 +            const float
 1.25812 +              dx = (float)x - p, dy = (float)y - q,
 1.25813 +              distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
 1.25814 +              weight = (float)cimg_std::exp(-distance2);
 1.25815 +            sum_weights+=weight;
 1.25816 +            cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
 1.25817 +          }
 1.25818 +          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));
 1.25819 +        }
 1.25820 +      }
 1.25821 +      }
 1.25822 +      return res.transfer_to(*this);
 1.25823 +    }
 1.25824 +
 1.25825 +    CImg<T> get_blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
 1.25826 +                           const unsigned int lookup_size=4, const bool fast_approx=true) const {
 1.25827 +      return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
 1.25828 +    }
 1.25829 +
 1.25830 +    //! Compute the Fast Fourier Transform of an image (along a specified axis).
 1.25831 +    CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
 1.25832 +      return CImgList<Tfloat>(*this).FFT(axis,invert);
 1.25833 +    }
 1.25834 +
 1.25835 +    //! Compute the Fast Fourier Transform on an image.
 1.25836 +    CImgList<Tfloat> get_FFT(const bool invert=false) const {
 1.25837 +      return CImgList<Tfloat>(*this).FFT(invert);
 1.25838 +    }
 1.25839 +
 1.25840 +    //! Apply a median filter.
 1.25841 +    CImg<T>& blur_median(const unsigned int n) {
 1.25842 +      return get_blur_median(n).transfer_to(*this);
 1.25843 +    }
 1.25844 +
 1.25845 +    CImg<T> get_blur_median(const unsigned int n) {
 1.25846 +      CImg<T> res(width,height,depth,dim);
 1.25847 +      if (!n || n==1) return *this;
 1.25848 +      const int hl=n/2, hr=hl-1+n%2;
 1.25849 +      if (res.depth!=1) {  // 3D median filter
 1.25850 +        CImg<T> vois;
 1.25851 +        cimg_forXYZV(*this,x,y,z,k) {
 1.25852 +          const int
 1.25853 +            x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
 1.25854 +            nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
 1.25855 +            nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
 1.25856 +          vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
 1.25857 +          res(x,y,z,k) = vois.median();
 1.25858 +        }
 1.25859 +      } else {
 1.25860 +#define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
 1.25861 +        if (res.height!=1) switch (n) { // 2D median filter
 1.25862 +        case 3 : {
 1.25863 +          T I[9] = { 0 };
 1.25864 +          CImg_3x3(J,T);
 1.25865 +          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 1.25866 +            cimg_std::memcpy(J,I,9*sizeof(T));
 1.25867 +            _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 1.25868 +            _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
 1.25869 +            _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 1.25870 +            _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
 1.25871 +            _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
 1.25872 +            _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
 1.25873 +            _cimg_median_sort(Jcc, Jnp);
 1.25874 +            res(x,y,0,k) = Jcc;
 1.25875 +          }
 1.25876 +        } break;
 1.25877 +        case 5 : {
 1.25878 +          T I[25] = { 0 };
 1.25879 +          CImg_5x5(J,T);
 1.25880 +          cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
 1.25881 +            cimg_std::memcpy(J,I,25*sizeof(T));
 1.25882 +            _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
 1.25883 +            _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
 1.25884 +            _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
 1.25885 +            _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
 1.25886 +            _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
 1.25887 +            _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
 1.25888 +            _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
 1.25889 +            _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
 1.25890 +            _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
 1.25891 +            _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
 1.25892 +            _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
 1.25893 +            _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
 1.25894 +            _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
 1.25895 +            _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
 1.25896 +            _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
 1.25897 +            _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
 1.25898 +            _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
 1.25899 +            _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
 1.25900 +            _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
 1.25901 +            _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
 1.25902 +            _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
 1.25903 +            _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
 1.25904 +            _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
 1.25905 +            _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
 1.25906 +            _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
 1.25907 +            res(x,y,0,k) = Jcc;
 1.25908 +          }
 1.25909 +        } break;
 1.25910 +        default : {
 1.25911 +          CImg<T> vois;
 1.25912 +          cimg_forXYV(*this,x,y,k) {
 1.25913 +            const int
 1.25914 +              x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
 1.25915 +              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
 1.25916 +              nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
 1.25917 +            vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
 1.25918 +            res(x,y,0,k) = vois.median();
 1.25919 +          }
 1.25920 +        }
 1.25921 +        } else switch (n) { // 1D median filter
 1.25922 +        case 2 : {
 1.25923 +          T I[4] = { 0 };
 1.25924 +          cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
 1.25925 +        } break;
 1.25926 +        case 3 : {
 1.25927 +          T I[9] = { 0 };
 1.25928 +          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 1.25929 +            res(x,0,0,k) = I[3]<I[4]?
 1.25930 +              (I[4]<I[5]?I[4]:
 1.25931 +               (I[3]<I[5]?I[5]:I[3])):
 1.25932 +              (I[3]<I[5]?I[3]:
 1.25933 +               (I[4]<I[5]?I[5]:I[4]));
 1.25934 +          }
 1.25935 +        } break;
 1.25936 +        default : {
 1.25937 +          CImg<T> vois;
 1.25938 +          cimg_forXV(*this,x,k) {
 1.25939 +            const int
 1.25940 +              x0 = x - hl, x1 = x + hr,
 1.25941 +              nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
 1.25942 +            vois = get_crop(nx0,0,0,k,nx1,0,0,k);
 1.25943 +            res(x,0,0,k) = vois.median();
 1.25944 +          }
 1.25945 +        }
 1.25946 +        }
 1.25947 +      }
 1.25948 +      return res;
 1.25949 +    }
 1.25950 +
 1.25951 +    //! Sharpen image using anisotropic shock filters or inverse diffusion.
 1.25952 +    CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
 1.25953 +      if (is_empty()) return *this;
 1.25954 +      T valm, valM = maxmin(valm);
 1.25955 +      const bool threed = (depth>1);
 1.25956 +      const float nedge = 0.5f*edge;
 1.25957 +      CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
 1.25958 +
 1.25959 +      if (threed) {
 1.25960 +        CImg_3x3x3(I,T);
 1.25961 +        if (sharpen_type) { // 3D Shock filter.
 1.25962 +          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
 1.25963 +          if (sigma>0) G.blur(sigma);
 1.25964 +
 1.25965 +          cimg_forXYZ(G,x,y,z) {
 1.25966 +            G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
 1.25967 +            G(x,y,z,0) = vec(0,0);
 1.25968 +            G(x,y,z,1) = vec(0,1);
 1.25969 +            G(x,y,z,2) = vec(0,2);
 1.25970 +            G(x,y,z,3) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
 1.25971 +          }
 1.25972 +          cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 1.25973 +            const Tfloat
 1.25974 +              u = G(x,y,z,0),
 1.25975 +              v = G(x,y,z,1),
 1.25976 +              w = G(x,y,z,2),
 1.25977 +              amp = G(x,y,z,3),
 1.25978 +              ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
 1.25979 +              ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
 1.25980 +              ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
 1.25981 +              iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
 1.25982 +              iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
 1.25983 +              izz = (Tfloat)Iccn + Iccp - 2*Iccc,
 1.25984 +              ixf = (Tfloat)Incc - Iccc,
 1.25985 +              ixb = (Tfloat)Iccc - Ipcc,
 1.25986 +              iyf = (Tfloat)Icnc - Iccc,
 1.25987 +              iyb = (Tfloat)Iccc - Icpc,
 1.25988 +              izf = (Tfloat)Iccn - Iccc,
 1.25989 +              izb = (Tfloat)Iccc - Iccp,
 1.25990 +              itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
 1.25991 +              it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
 1.25992 +            veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
 1.25993 +          }
 1.25994 +        } 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.
 1.25995 +      } else {
 1.25996 +        CImg_3x3(I,T);
 1.25997 +        if (sharpen_type) { // 2D Shock filter.
 1.25998 +          CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
 1.25999 +          if (sigma>0) G.blur(sigma);
 1.26000 +          cimg_forXY(G,x,y) {
 1.26001 +            G.get_tensor_at(x,y).symmetric_eigen(val,vec);
 1.26002 +            G(x,y,0) = vec(0,0);
 1.26003 +            G(x,y,1) = vec(0,1);
 1.26004 +            G(x,y,2) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1],-(Tfloat)nedge);
 1.26005 +          }
 1.26006 +          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 1.26007 +            const Tfloat
 1.26008 +              u = G(x,y,0),
 1.26009 +              v = G(x,y,1),
 1.26010 +              amp = G(x,y,2),
 1.26011 +              ixx = (Tfloat)Inc + Ipc - 2*Icc,
 1.26012 +              ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
 1.26013 +              iyy = (Tfloat)Icn + Icp - 2*Icc,
 1.26014 +              ixf = (Tfloat)Inc - Icc,
 1.26015 +              ixb = (Tfloat)Icc - Ipc,
 1.26016 +              iyf = (Tfloat)Icn - Icc,
 1.26017 +              iyb = (Tfloat)Icc - Icp,
 1.26018 +              itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
 1.26019 +              it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
 1.26020 +            veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
 1.26021 +          }
 1.26022 +        } 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.
 1.26023 +      }
 1.26024 +      float m, M = (float)veloc.maxmin(m);
 1.26025 +      const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
 1.26026 +      if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
 1.26027 +      return cut(valm,valM);
 1.26028 +    }
 1.26029 +
 1.26030 +    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 {
 1.26031 +      return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
 1.26032 +    }
 1.26033 +
 1.26034 +    //! Compute the Haar multiscale wavelet transform (monodimensional version).
 1.26035 +    /**
 1.26036 +       \param axis Axis considered for the transform.
 1.26037 +       \param invert Set inverse of direct transform.
 1.26038 +       \param nb_scales Number of scales used for the transform.
 1.26039 +    **/
 1.26040 +    CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
 1.26041 +      return get_haar(axis,invert,nb_scales).transfer_to(*this);
 1.26042 +    }
 1.26043 +
 1.26044 +    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
 1.26045 +      if (is_empty() || !nb_scales) return *this;
 1.26046 +      CImg<Tfloat> res;
 1.26047 +
 1.26048 +      if (nb_scales==1) {
 1.26049 +        switch (cimg::uncase(axis)) { // Single scale transform
 1.26050 +        case 'x' : {
 1.26051 +          const unsigned int w = width/2;
 1.26052 +          if (w) {
 1.26053 +            if (w%2)
 1.26054 +              throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
 1.26055 +                                          pixel_type(),w);
 1.26056 +            res.assign(width,height,depth,dim);
 1.26057 +            if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
 1.26058 +              for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 1.26059 +                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
 1.26060 +                res(x2++,y,z,v) = val0 - val1;
 1.26061 +                res(x2++,y,z,v) = val0 + val1;
 1.26062 +              }
 1.26063 +            } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
 1.26064 +              for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 1.26065 +                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
 1.26066 +                res(x,y,z,v) = (val0 + val1)/2;
 1.26067 +                res(xw,y,z,v) = (val1 - val0)/2;
 1.26068 +              }
 1.26069 +            }
 1.26070 +          } else return *this;
 1.26071 +        } break;
 1.26072 +        case 'y' : {
 1.26073 +          const unsigned int h = height/2;
 1.26074 +          if (h) {
 1.26075 +            if (h%2)
 1.26076 +              throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
 1.26077 +                                          pixel_type(),h);
 1.26078 +            res.assign(width,height,depth,dim);
 1.26079 +            if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
 1.26080 +              for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
 1.26081 +                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
 1.26082 +                res(x,y2++,z,v) = val0 - val1;
 1.26083 +                res(x,y2++,z,v) = val0 + val1;
 1.26084 +              }
 1.26085 +            } else cimg_forXZV(*this,x,z,v) {
 1.26086 +              for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
 1.26087 +                const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
 1.26088 +                res(x,y,z,v) = (val0 + val1)/2;
 1.26089 +                res(x,yh,z,v) = (val1 - val0)/2;
 1.26090 +              }
 1.26091 +            }
 1.26092 +          } else return *this;
 1.26093 +        } break;
 1.26094 +        case 'z' : {
 1.26095 +          const unsigned int d = depth/2;
 1.26096 +          if (d) {
 1.26097 +            if (d%2)
 1.26098 +              throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
 1.26099 +                                          pixel_type(),d);
 1.26100 +            res.assign(width,height,depth,dim);
 1.26101 +            if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
 1.26102 +              for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
 1.26103 +                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
 1.26104 +                res(x,y,z2++,v) = val0 - val1;
 1.26105 +                res(x,y,z2++,v) = val0 + val1;
 1.26106 +              }
 1.26107 +            } else cimg_forXYV(*this,x,y,v) {
 1.26108 +              for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
 1.26109 +                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
 1.26110 +                res(x,y,z,v) = (val0 + val1)/2;
 1.26111 +                res(x,y,zd,v) = (val1 - val0)/2;
 1.26112 +              }
 1.26113 +            }
 1.26114 +          } else return *this;
 1.26115 +        } break;
 1.26116 +        default :
 1.26117 +          throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 1.26118 +                                      pixel_type(),axis);
 1.26119 +        }
 1.26120 +      } else { // Multi-scale version
 1.26121 +        if (invert) {
 1.26122 +          res.assign(*this);
 1.26123 +          switch (cimg::uncase(axis)) {
 1.26124 +          case 'x' : {
 1.26125 +            unsigned int w = width;
 1.26126 +            for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 1.26127 +            for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
 1.26128 +          } break;
 1.26129 +          case 'y' : {
 1.26130 +            unsigned int h = width;
 1.26131 +            for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 1.26132 +            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));
 1.26133 +          } break;
 1.26134 +          case 'z' : {
 1.26135 +            unsigned int d = depth;
 1.26136 +            for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 1.26137 +            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));
 1.26138 +          } break;
 1.26139 +          default :
 1.26140 +            throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 1.26141 +                                        pixel_type(),axis);
 1.26142 +          }
 1.26143 +        } else { // Direct transform
 1.26144 +          res = get_haar(axis,false,1);
 1.26145 +          switch (cimg::uncase(axis)) {
 1.26146 +          case 'x' : {
 1.26147 +            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));
 1.26148 +          } break;
 1.26149 +          case 'y' : {
 1.26150 +            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));
 1.26151 +          } break;
 1.26152 +          case 'z' : {
 1.26153 +            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));
 1.26154 +          } break;
 1.26155 +          default :
 1.26156 +            throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
 1.26157 +                                        pixel_type(),axis);
 1.26158 +          }
 1.26159 +        }
 1.26160 +      }
 1.26161 +      return res;
 1.26162 +    }
 1.26163 +
 1.26164 +    //! Compute the Haar multiscale wavelet transform.
 1.26165 +    /**
 1.26166 +       \param invert Set inverse of direct transform.
 1.26167 +       \param nb_scales Number of scales used for the transform.
 1.26168 +    **/
 1.26169 +    CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
 1.26170 +      return get_haar(invert,nb_scales).transfer_to(*this);
 1.26171 +    }
 1.26172 +
 1.26173 +    CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
 1.26174 +      CImg<Tfloat> res;
 1.26175 +
 1.26176 +      if (nb_scales==1) { // Single scale transform
 1.26177 +        if (width>1) get_haar('x',invert,1).transfer_to(res);
 1.26178 +        if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
 1.26179 +        if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
 1.26180 +        if (res) return res;
 1.26181 +      } else { // Multi-scale transform
 1.26182 +        if (invert) { // Inverse transform
 1.26183 +          res.assign(*this);
 1.26184 +          if (width>1) {
 1.26185 +            if (height>1) {
 1.26186 +              if (depth>1) {
 1.26187 +                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; }
 1.26188 +                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)
 1.26189 +                  res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
 1.26190 +              } else {
 1.26191 +                unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
 1.26192 +                for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
 1.26193 +                  res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
 1.26194 +              }
 1.26195 +            } else {
 1.26196 +              if (depth>1) {
 1.26197 +                unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
 1.26198 +                for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
 1.26199 +                  res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
 1.26200 +              } else {
 1.26201 +                unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 1.26202 +                for (w=w?w:1; w<=width; w*=2)
 1.26203 +                  res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
 1.26204 +              }
 1.26205 +            }
 1.26206 +          } else {
 1.26207 +            if (height>1) {
 1.26208 +              if (depth>1) {
 1.26209 +                unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
 1.26210 +                for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
 1.26211 +                  res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
 1.26212 +              } else {
 1.26213 +                unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 1.26214 +                for (h=h?h:1; h<=height; h*=2)
 1.26215 +                  res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
 1.26216 +              }
 1.26217 +            } else {
 1.26218 +              if (depth>1) {
 1.26219 +                unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 1.26220 +                for (d=d?d:1; d<=depth; d*=2)
 1.26221 +                  res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
 1.26222 +              } else return *this;
 1.26223 +            }
 1.26224 +          }
 1.26225 +        } else { // Direct transform
 1.26226 +          res = get_haar(false,1);
 1.26227 +          if (width>1) {
 1.26228 +            if (height>1) {
 1.26229 +              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)
 1.26230 +                res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
 1.26231 +              else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
 1.26232 +                res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
 1.26233 +            } else {
 1.26234 +              if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
 1.26235 +                res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
 1.26236 +              else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
 1.26237 +                res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
 1.26238 +            }
 1.26239 +          } else {
 1.26240 +            if (height>1) {
 1.26241 +              if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
 1.26242 +                res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
 1.26243 +              else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
 1.26244 +                res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
 1.26245 +            } else {
 1.26246 +              if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
 1.26247 +                res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
 1.26248 +              else return *this;
 1.26249 +            }
 1.26250 +          }
 1.26251 +        }
 1.26252 +        return res;
 1.26253 +      }
 1.26254 +      return *this;
 1.26255 +    }
 1.26256 +
 1.26257 +    //! Estimate a displacement field between instance image and given target image.
 1.26258 +    CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
 1.26259 +                                const unsigned int nb_scales=0, const unsigned int itermax=10000) {
 1.26260 +      return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
 1.26261 +    }
 1.26262 +
 1.26263 +    CImg<Tfloat> get_displacement_field(const CImg<T>& target,
 1.26264 +                                        const float smoothness=0.1f, const float precision=0.1f,
 1.26265 +                                        const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
 1.26266 +      if (is_empty() || !target) return *this;
 1.26267 +      if (!is_sameXYZV(target))
 1.26268 +        throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
 1.26269 +                                    "have different size.",
 1.26270 +                                    pixel_type(),width,height,depth,dim,data,
 1.26271 +                                    target.width,target.height,target.depth,target.dim,target.data);
 1.26272 +      if (smoothness<0)
 1.26273 +        throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
 1.26274 +                                    pixel_type(),smoothness);
 1.26275 +      if (precision<0)
 1.26276 +        throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
 1.26277 +                                    pixel_type(),precision);
 1.26278 +
 1.26279 +      const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*cimg_std::log((double)(cimg::max(width,height,depth))));
 1.26280 +      Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
 1.26281 +      const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
 1.26282 +      CImg<Tfloat> U0;
 1.26283 +      const bool threed = (depth>1);
 1.26284 +
 1.26285 +      // Begin multi-scale motion estimation
 1.26286 +      for (int scale = (int)nscales-1; scale>=0; --scale) {
 1.26287 +        const float sfactor = (float)cimg_std::pow(1.5f,(float)scale), sprecision = (float)(precision/cimg_std::pow(2.25,1+scale));
 1.26288 +        const int
 1.26289 +          sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
 1.26290 +          swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
 1.26291 +        CImg<Tfloat>
 1.26292 +          I1 = get_resize(swidth,sheight,sdepth,-100,2),
 1.26293 +          I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
 1.26294 +        I1/=factor; I2/=factor;
 1.26295 +        CImg<Tfloat> U;
 1.26296 +        if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
 1.26297 +        else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
 1.26298 +
 1.26299 +        // Begin single-scale motion estimation
 1.26300 +        CImg<Tfloat> veloc(U);
 1.26301 +        float dt = 2, Energy = cimg::type<float>::max();
 1.26302 +        const CImgList<Tfloat> dI = I2.get_gradient();
 1.26303 +        for (unsigned int iter=0; iter<itermax; iter++) {
 1.26304 +          veloc.fill(0);
 1.26305 +          float nEnergy = 0;
 1.26306 +          if (threed) {
 1.26307 +            cimg_for3XYZ(U,x,y,z) {
 1.26308 +              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));
 1.26309 +              cimg_forV(U,k) {
 1.26310 +                const Tfloat
 1.26311 +                  Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
 1.26312 +                  Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
 1.26313 +                  Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
 1.26314 +                  Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
 1.26315 +                  Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
 1.26316 +                  Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
 1.26317 +                nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
 1.26318 +                Tfloat deltaIgrad = 0;
 1.26319 +                cimg_forV(I1,i) {
 1.26320 +                  const Tfloat deltaIi = (float)(I2._linear_atXYZ(X,Y,Z,i) - I1(x,y,z,i));
 1.26321 +                  nEnergy += (float)(deltaIi*deltaIi/2);
 1.26322 +                  deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
 1.26323 +                }
 1.26324 +                veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
 1.26325 +              }
 1.26326 +            }
 1.26327 +          } else {
 1.26328 +            cimg_for3XY(U,x,y) {
 1.26329 +              const float X = (float)(x + U(x,y,0)), Y = (float)(y + U(x,y,1));
 1.26330 +              cimg_forV(U,k) {
 1.26331 +                const Tfloat
 1.26332 +                  Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
 1.26333 +                  Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
 1.26334 +                  Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
 1.26335 +                  Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
 1.26336 +                nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
 1.26337 +                Tfloat deltaIgrad = 0;
 1.26338 +                cimg_forV(I1,i) {
 1.26339 +                  const Tfloat deltaIi = (float)(I2._linear_atXY(X,Y,i) - I1(x,y,i));
 1.26340 +                  nEnergy += (float)(deltaIi*deltaIi/2);
 1.26341 +                  deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
 1.26342 +                }
 1.26343 +                veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
 1.26344 +              }
 1.26345 +            }
 1.26346 +          }
 1.26347 +          const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
 1.26348 +          U+=(veloc*=dt/vmax);
 1.26349 +          if (cimg::abs(nEnergy-Energy)<sprecision) break;
 1.26350 +          if (nEnergy<Energy) dt*=0.5f;
 1.26351 +          Energy = nEnergy;
 1.26352 +        }
 1.26353 +        U.transfer_to(U0);
 1.26354 +      }
 1.26355 +      return U0;
 1.26356 +    }
 1.26357 +
 1.26358 +    //@}
 1.26359 +    //-----------------------------
 1.26360 +    //
 1.26361 +    //! \name Matrix and Vectors
 1.26362 +    //@{
 1.26363 +    //-----------------------------
 1.26364 +
 1.26365 +    //! Return a vector with specified coefficients.
 1.26366 +    static CImg<T> vector(const T& a0) {
 1.26367 +      static CImg<T> r(1,1); r[0] = a0;
 1.26368 +      return r;
 1.26369 +    }
 1.26370 +
 1.26371 +    //! Return a vector with specified coefficients.
 1.26372 +    static CImg<T> vector(const T& a0, const T& a1) {
 1.26373 +      static CImg<T> r(1,2); T *ptr = r.data;
 1.26374 +      *(ptr++) = a0; *(ptr++) = a1;
 1.26375 +      return r;
 1.26376 +    }
 1.26377 +
 1.26378 +    //! Return a vector with specified coefficients.
 1.26379 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
 1.26380 +      static CImg<T> r(1,3); T *ptr = r.data;
 1.26381 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
 1.26382 +      return r;
 1.26383 +    }
 1.26384 +
 1.26385 +    //! Return a vector with specified coefficients.
 1.26386 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
 1.26387 +      static CImg<T> r(1,4); T *ptr = r.data;
 1.26388 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26389 +      return r;
 1.26390 +    }
 1.26391 +
 1.26392 +    //! Return a vector with specified coefficients.
 1.26393 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 1.26394 +      static CImg<T> r(1,5); T *ptr = r.data;
 1.26395 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
 1.26396 +      return r;
 1.26397 +    }
 1.26398 +
 1.26399 +    //! Return a vector with specified coefficients.
 1.26400 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
 1.26401 +      static CImg<T> r(1,6); T *ptr = r.data;
 1.26402 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
 1.26403 +      return r;
 1.26404 +    }
 1.26405 +
 1.26406 +    //! Return a vector with specified coefficients.
 1.26407 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26408 +                          const T& a4, const T& a5, const T& a6) {
 1.26409 +      static CImg<T> r(1,7); T *ptr = r.data;
 1.26410 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26411 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
 1.26412 +      return r;
 1.26413 +    }
 1.26414 +
 1.26415 +    //! Return a vector with specified coefficients.
 1.26416 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26417 +                          const T& a4, const T& a5, const T& a6, const T& a7) {
 1.26418 +      static CImg<T> r(1,8); T *ptr = r.data;
 1.26419 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26420 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26421 +      return r;
 1.26422 +    }
 1.26423 +
 1.26424 +    //! Return a vector with specified coefficients.
 1.26425 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26426 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26427 +                          const T& a8) {
 1.26428 +      static CImg<T> r(1,9); T *ptr = r.data;
 1.26429 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26430 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26431 +      *(ptr++) = a8;
 1.26432 +      return r;
 1.26433 +    }
 1.26434 +
 1.26435 +    //! Return a vector with specified coefficients.
 1.26436 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26437 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26438 +                          const T& a8, const T& a9) {
 1.26439 +      static CImg<T> r(1,10); T *ptr = r.data;
 1.26440 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26441 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26442 +      *(ptr++) = a8; *(ptr++) = a9;
 1.26443 +      return r;
 1.26444 +    }
 1.26445 +
 1.26446 +    //! Return a vector with specified coefficients.
 1.26447 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26448 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26449 +                          const T& a8, const T& a9, const T& a10) {
 1.26450 +      static CImg<T> r(1,11); T *ptr = r.data;
 1.26451 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26452 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26453 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
 1.26454 +      return r;
 1.26455 +    }
 1.26456 +
 1.26457 +    //! Return a vector with specified coefficients.
 1.26458 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26459 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26460 +                          const T& a8, const T& a9, const T& a10, const T& a11) {
 1.26461 +      static CImg<T> r(1,12); T *ptr = r.data;
 1.26462 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26463 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26464 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26465 +      return r;
 1.26466 +    }
 1.26467 +
 1.26468 +    //! Return a vector with specified coefficients.
 1.26469 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26470 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26471 +                          const T& a8, const T& a9, const T& a10, const T& a11,
 1.26472 +                          const T& a12) {
 1.26473 +      static CImg<T> r(1,13); T *ptr = r.data;
 1.26474 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26475 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26476 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26477 +      *(ptr++) = a12;
 1.26478 +      return r;
 1.26479 +    }
 1.26480 +
 1.26481 +    //! Return a vector with specified coefficients.
 1.26482 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26483 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26484 +                          const T& a8, const T& a9, const T& a10, const T& a11,
 1.26485 +                          const T& a12, const T& a13) {
 1.26486 +      static CImg<T> r(1,14); T *ptr = r.data;
 1.26487 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26488 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26489 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26490 +      *(ptr++) = a12; *(ptr++) = a13;
 1.26491 +      return r;
 1.26492 +    }
 1.26493 +
 1.26494 +    //! Return a vector with specified coefficients.
 1.26495 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26496 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26497 +                          const T& a8, const T& a9, const T& a10, const T& a11,
 1.26498 +                          const T& a12, const T& a13, const T& a14) {
 1.26499 +      static CImg<T> r(1,15); T *ptr = r.data;
 1.26500 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26501 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26502 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26503 +      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
 1.26504 +      return r;
 1.26505 +    }
 1.26506 +
 1.26507 +    //! Return a vector with specified coefficients.
 1.26508 +    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26509 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26510 +                          const T& a8, const T& a9, const T& a10, const T& a11,
 1.26511 +                          const T& a12, const T& a13, const T& a14, const T& a15) {
 1.26512 +      static CImg<T> r(1,16); T *ptr = r.data;
 1.26513 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26514 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26515 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26516 +      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
 1.26517 +      return r;
 1.26518 +    }
 1.26519 +
 1.26520 +    //! Return a 1x1 square matrix with specified coefficients.
 1.26521 +    static CImg<T> matrix(const T& a0) {
 1.26522 +      return vector(a0);
 1.26523 +    }
 1.26524 +
 1.26525 +    //! Return a 2x2 square matrix with specified coefficients.
 1.26526 +    static CImg<T> matrix(const T& a0, const T& a1,
 1.26527 +                          const T& a2, const T& a3) {
 1.26528 +      static CImg<T> r(2,2); T *ptr = r.data;
 1.26529 +      *(ptr++) = a0; *(ptr++) = a1;
 1.26530 +      *(ptr++) = a2; *(ptr++) = a3;
 1.26531 +      return r;
 1.26532 +    }
 1.26533 +
 1.26534 +    //! Return a 3x3 square matrix with specified coefficients.
 1.26535 +    static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
 1.26536 +                          const T& a3, const T& a4, const T& a5,
 1.26537 +                          const T& a6, const T& a7, const T& a8) {
 1.26538 +      static CImg<T> r(3,3); T *ptr = r.data;
 1.26539 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
 1.26540 +      *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
 1.26541 +      *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
 1.26542 +      return r;
 1.26543 +    }
 1.26544 +
 1.26545 +    //! Return a 4x4 square matrix with specified coefficients.
 1.26546 +    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
 1.26547 +                          const T& a4, const T& a5, const T& a6, const T& a7,
 1.26548 +                          const T& a8, const T& a9, const T& a10, const T& a11,
 1.26549 +                          const T& a12, const T& a13, const T& a14, const T& a15) {
 1.26550 +      static CImg<T> r(4,4); T *ptr = r.data;
 1.26551 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 1.26552 +      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 1.26553 +      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 1.26554 +      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
 1.26555 +      return r;
 1.26556 +    }
 1.26557 +
 1.26558 +    //! Return a 5x5 square matrix with specified coefficients.
 1.26559 +    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
 1.26560 +                          const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
 1.26561 +                          const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
 1.26562 +                          const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
 1.26563 +                          const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
 1.26564 +      static CImg<T> r(5,5); T *ptr = r.data;
 1.26565 +      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
 1.26566 +      *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
 1.26567 +      *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
 1.26568 +      *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
 1.26569 +      *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
 1.26570 +      return r;
 1.26571 +    }
 1.26572 +
 1.26573 +    //! Return a 1x1 symmetric matrix with specified coefficients.
 1.26574 +    static CImg<T> tensor(const T& a1) {
 1.26575 +      return matrix(a1);
 1.26576 +    }
 1.26577 +
 1.26578 +    //! Return a 2x2 symmetric matrix tensor with specified coefficients.
 1.26579 +    static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
 1.26580 +      return matrix(a1,a2,a2,a3);
 1.26581 +    }
 1.26582 +
 1.26583 +    //! Return a 3x3 symmetric matrix with specified coefficients.
 1.26584 +    static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
 1.26585 +      return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
 1.26586 +    }
 1.26587 +
 1.26588 +    //! Return a 1x1 diagonal matrix with specified coefficients.
 1.26589 +    static CImg<T> diagonal(const T& a0) {
 1.26590 +      return matrix(a0);
 1.26591 +    }
 1.26592 +
 1.26593 +    //! Return a 2x2 diagonal matrix with specified coefficients.
 1.26594 +    static CImg<T> diagonal(const T& a0, const T& a1) {
 1.26595 +      return matrix(a0,0,0,a1);
 1.26596 +    }
 1.26597 +
 1.26598 +    //! Return a 3x3 diagonal matrix with specified coefficients.
 1.26599 +    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
 1.26600 +      return matrix(a0,0,0,0,a1,0,0,0,a2);
 1.26601 +    }
 1.26602 +
 1.26603 +    //! Return a 4x4 diagonal matrix with specified coefficients.
 1.26604 +    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
 1.26605 +      return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
 1.26606 +    }
 1.26607 +
 1.26608 +    //! Return a 5x5 diagonal matrix with specified coefficients.
 1.26609 +    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 1.26610 +      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);
 1.26611 +    }
 1.26612 +
 1.26613 +    //! Return a NxN identity matrix.
 1.26614 +    static CImg<T> identity_matrix(const unsigned int N) {
 1.26615 +      CImg<T> res(N,N,1,1,0);
 1.26616 +      cimg_forX(res,x) res(x,x) = 1;
 1.26617 +      return res;
 1.26618 +    }
 1.26619 +
 1.26620 +    //! Return a N-numbered sequence vector from \p a0 to \p a1.
 1.26621 +    static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
 1.26622 +      if (N) return CImg<T>(1,N).sequence(a0,a1);
 1.26623 +      return CImg<T>();
 1.26624 +    }
 1.26625 +
 1.26626 +    //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
 1.26627 +    static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
 1.26628 +      float X,Y,Z,W;
 1.26629 +      if (!quaternion_data) {
 1.26630 +        const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z),
 1.26631 +          nx = norm>0?x/norm:0,
 1.26632 +          ny = norm>0?y/norm:0,
 1.26633 +          nz = norm>0?z/norm:1,
 1.26634 +          nw = norm>0?w:0,
 1.26635 +          sina = (float)cimg_std::sin(nw/2),
 1.26636 +          cosa = (float)cimg_std::cos(nw/2);
 1.26637 +        X = nx*sina;
 1.26638 +        Y = ny*sina;
 1.26639 +        Z = nz*sina;
 1.26640 +        W = cosa;
 1.26641 +      } else {
 1.26642 +        const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z + w*w);
 1.26643 +        if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
 1.26644 +        else { X = Y = Z = 0; W = 1; }
 1.26645 +      }
 1.26646 +      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;
 1.26647 +      return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)),   (T)(2*(xz-yw)),
 1.26648 +                             (T)(2*(xy-zw)),   (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
 1.26649 +                             (T)(2*(xz+yw)),   (T)(2*(yz-xw)),   (T)(1-2*(xx+yy)));
 1.26650 +    }
 1.26651 +
 1.26652 +    //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
 1.26653 +    CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
 1.26654 +      static CImg<T> dest;
 1.26655 +      if (dest.height!=dim) dest.assign(1,dim);
 1.26656 +      const unsigned int whz = width*height*depth;
 1.26657 +      const T *ptrs = ptr(x,y,z);
 1.26658 +      T *ptrd = dest.data;
 1.26659 +      cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
 1.26660 +      return dest;
 1.26661 +    }
 1.26662 +
 1.26663 +    //! 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.
 1.26664 +    template<typename t>
 1.26665 +    CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
 1.26666 +      if (x<width && y<height && z<depth) {
 1.26667 +        const unsigned int whz = width*height*depth;
 1.26668 +        const t *ptrs = vec.data;
 1.26669 +        T *ptrd = ptr(x,y,z);
 1.26670 +        for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
 1.26671 +      }
 1.26672 +      return *this;
 1.26673 +    }
 1.26674 +
 1.26675 +    //! 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.
 1.26676 +    CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
 1.26677 +      const int n = (int)cimg_std::sqrt((double)dim);
 1.26678 +      CImg<T> dest(n,n);
 1.26679 +      cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
 1.26680 +      return dest;
 1.26681 +    }
 1.26682 +
 1.26683 +    //! 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.
 1.26684 +    template<typename t>
 1.26685 +    CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 1.26686 +      return set_vector_at(mat,x,y,z);
 1.26687 +    }
 1.26688 +
 1.26689 +    //! 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.
 1.26690 +    CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
 1.26691 +      if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
 1.26692 +                                (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
 1.26693 +      if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
 1.26694 +      return tensor((*this)(x,y,z,0));
 1.26695 +    }
 1.26696 +
 1.26697 +    //! 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.
 1.26698 +    template<typename t>
 1.26699 +    CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 1.26700 +      if (ten.height==2) {
 1.26701 +        (*this)(x,y,z,0) = (T)ten[0];
 1.26702 +        (*this)(x,y,z,1) = (T)ten[1];
 1.26703 +        (*this)(x,y,z,2) = (T)ten[3];
 1.26704 +      }
 1.26705 +      else {
 1.26706 +        (*this)(x,y,z,0) = (T)ten[0];
 1.26707 +        (*this)(x,y,z,1) = (T)ten[1];
 1.26708 +        (*this)(x,y,z,2) = (T)ten[2];
 1.26709 +        (*this)(x,y,z,3) = (T)ten[4];
 1.26710 +        (*this)(x,y,z,4) = (T)ten[5];
 1.26711 +        (*this)(x,y,z,5) = (T)ten[8];
 1.26712 +      }
 1.26713 +      return *this;
 1.26714 +    }
 1.26715 +
 1.26716 +    //! Unroll all images values into a one-column vector.
 1.26717 +    CImg<T>& vector() {
 1.26718 +      return unroll('y');
 1.26719 +    }
 1.26720 +
 1.26721 +    CImg<T> get_vector() const {
 1.26722 +      return get_unroll('y');
 1.26723 +    }
 1.26724 +
 1.26725 +    //! Realign pixel values of the instance image as a square matrix
 1.26726 +    CImg<T>& matrix() {
 1.26727 +      const unsigned int siz = size();
 1.26728 +      switch (siz) {
 1.26729 +      case 1 : break;
 1.26730 +      case 4 : width = height = 2; break;
 1.26731 +      case 9 : width = height = 3; break;
 1.26732 +      case 16 : width = height = 4; break;
 1.26733 +      case 25 : width = height = 5; break;
 1.26734 +      case 36 : width = height = 6; break;
 1.26735 +      case 49 : width = height = 7; break;
 1.26736 +      case 64 : width = height = 8; break;
 1.26737 +      case 81 : width = height = 9; break;
 1.26738 +      case 100 : width = height = 10; break;
 1.26739 +      default : {
 1.26740 +        unsigned int i = 11, i2 = i*i;
 1.26741 +        while (i2<siz) { i2+=2*i+1; ++i; }
 1.26742 +        if (i2==siz) width = height = i;
 1.26743 +        else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
 1.26744 +                                         pixel_type(),siz);
 1.26745 +      }
 1.26746 +      }
 1.26747 +      return *this;
 1.26748 +    }
 1.26749 +
 1.26750 +    CImg<T> get_matrix() const {
 1.26751 +      return (+*this).matrix();
 1.26752 +    }
 1.26753 +
 1.26754 +    //! Realign pixel values of the instance image as a symmetric tensor.
 1.26755 +    CImg<T>& tensor() {
 1.26756 +      return get_tensor().transfer_to(*this);
 1.26757 +    }
 1.26758 +
 1.26759 +    CImg<T> get_tensor() const {
 1.26760 +      CImg<T> res;
 1.26761 +      const unsigned int siz = size();
 1.26762 +      switch (siz) {
 1.26763 +      case 1 : break;
 1.26764 +      case 3 :
 1.26765 +        res.assign(2,2);
 1.26766 +        res(0,0) = (*this)(0);
 1.26767 +        res(1,0) = res(0,1) = (*this)(1);
 1.26768 +        res(1,1) = (*this)(2);
 1.26769 +        break;
 1.26770 +      case 6 :
 1.26771 +        res.assign(3,3);
 1.26772 +        res(0,0) = (*this)(0);
 1.26773 +        res(1,0) = res(0,1) = (*this)(1);
 1.26774 +        res(2,0) = res(0,2) = (*this)(2);
 1.26775 +        res(1,1) = (*this)(3);
 1.26776 +        res(2,1) = res(1,2) = (*this)(4);
 1.26777 +        res(2,2) = (*this)(5);
 1.26778 +        break;
 1.26779 +      default :
 1.26780 +        throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
 1.26781 +                                    pixel_type(), dim);
 1.26782 +      }
 1.26783 +      return res;
 1.26784 +    }
 1.26785 +
 1.26786 +    //! Unroll all images values into specified axis.
 1.26787 +    CImg<T>& unroll(const char axis) {
 1.26788 +      const unsigned int siz = size();
 1.26789 +      if (siz) switch (axis) {
 1.26790 +      case 'x' : width = siz; height=depth=dim=1; break;
 1.26791 +      case 'y' : height = siz; width=depth=dim=1; break;
 1.26792 +      case 'z' : depth = siz; width=height=dim=1; break;
 1.26793 +      case 'v' : dim = siz; width=height=depth=1; break;
 1.26794 +      default :
 1.26795 +        throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
 1.26796 +                                    pixel_type(),axis);
 1.26797 +      }
 1.26798 +      return *this;
 1.26799 +    }
 1.26800 +
 1.26801 +    CImg<T> get_unroll(const char axis) const {
 1.26802 +      return (+*this).unroll(axis);
 1.26803 +    }
 1.26804 +
 1.26805 +    //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
 1.26806 +    CImg<T>& diagonal() {
 1.26807 +      return get_diagonal().transfer_to(*this);
 1.26808 +    }
 1.26809 +
 1.26810 +    CImg<T> get_diagonal() const {
 1.26811 +      if (is_empty()) return *this;
 1.26812 +      CImg<T> res(size(),size(),1,1,0);
 1.26813 +      cimg_foroff(*this,off) res(off,off) = (*this)(off);
 1.26814 +      return res;
 1.26815 +    }
 1.26816 +
 1.26817 +    //! Get an identity matrix having same dimension than instance image.
 1.26818 +    CImg<T>& identity_matrix() {
 1.26819 +      return identity_matrix(cimg::max(width,height)).transfer_to(*this);
 1.26820 +    }
 1.26821 +
 1.26822 +    CImg<T> get_identity_matrix() const {
 1.26823 +      return identity_matrix(cimg::max(width,height));
 1.26824 +    }
 1.26825 +
 1.26826 +    //! Return a N-numbered sequence vector from \p a0 to \p a1.
 1.26827 +    CImg<T>& sequence(const T a0, const T a1) {
 1.26828 +      if (is_empty()) return *this;
 1.26829 +      const unsigned int siz = size() - 1;
 1.26830 +      T* ptr = data;
 1.26831 +      if (siz) {
 1.26832 +        const Tfloat delta = (Tfloat)a1 - a0;
 1.26833 +        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
 1.26834 +      } else *ptr = a0;
 1.26835 +      return *this;
 1.26836 +    }
 1.26837 +
 1.26838 +    CImg<T> get_sequence(const T a0, const T a1) const {
 1.26839 +      return (+*this).sequence(a0,a1);
 1.26840 +    }
 1.26841 +
 1.26842 +    //! Transpose the current matrix.
 1.26843 +    CImg<T>& transpose() {
 1.26844 +      if (width==1) { width=height; height=1; return *this; }
 1.26845 +      if (height==1) { height=width; width=1; return *this; }
 1.26846 +      if (width==height) {
 1.26847 +        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));
 1.26848 +        return *this;
 1.26849 +      }
 1.26850 +      return get_transpose().transfer_to(*this);
 1.26851 +    }
 1.26852 +
 1.26853 +    CImg<T> get_transpose() const {
 1.26854 +      return get_permute_axes("yxzv");
 1.26855 +    }
 1.26856 +
 1.26857 +    //! Invert the current matrix.
 1.26858 +    CImg<T>& invert(const bool use_LU=true) {
 1.26859 +      if (!is_empty()) {
 1.26860 +        if (width!=height || depth!=1 || dim!=1)
 1.26861 +          throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
 1.26862 +                                      pixel_type(),width,height,depth,dim,data);
 1.26863 +#ifdef cimg_use_lapack
 1.26864 +        int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
 1.26865 +        Tfloat
 1.26866 +          *lapA = new Tfloat[N*N],
 1.26867 +          *WORK = new Tfloat[LWORK];
 1.26868 +        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
 1.26869 +        cimg::getrf(N,lapA,IPIV,INFO);
 1.26870 +        if (INFO)
 1.26871 +          cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
 1.26872 +                     pixel_type(),INFO);
 1.26873 +        else {
 1.26874 +          cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
 1.26875 +          if (INFO)
 1.26876 +            cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
 1.26877 +                       pixel_type(),INFO);
 1.26878 +        }
 1.26879 +        if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
 1.26880 +        delete[] IPIV; delete[] lapA; delete[] WORK;
 1.26881 +#else
 1.26882 +        const double dete = width>3?-1.0:det();
 1.26883 +        if (dete!=0.0 && width==2) {
 1.26884 +          const double
 1.26885 +            a = data[0], c = data[1],
 1.26886 +            b = data[2], d = data[3];
 1.26887 +          data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
 1.26888 +          data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
 1.26889 +        } else if (dete!=0.0 && width==3) {
 1.26890 +          const double
 1.26891 +            a = data[0], d = data[1], g = data[2],
 1.26892 +            b = data[3], e = data[4], h = data[5],
 1.26893 +            c = data[6], f = data[7], i = data[8];
 1.26894 +          data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
 1.26895 +          data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
 1.26896 +          data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
 1.26897 +        } else {
 1.26898 +          if (use_LU) { // LU-based inverse computation
 1.26899 +            CImg<Tfloat> A(*this), indx, col(1,width);
 1.26900 +            bool d;
 1.26901 +            A._LU(indx,d);
 1.26902 +            cimg_forX(*this,j) {
 1.26903 +              col.fill(0);
 1.26904 +              col(j) = 1;
 1.26905 +              col._solve(A,indx);
 1.26906 +              cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
 1.26907 +            }
 1.26908 +          } else { // SVD-based inverse computation
 1.26909 +            CImg<Tfloat> U(width,width), S(1,width), V(width,width);
 1.26910 +            SVD(U,S,V,false);
 1.26911 +            U.transpose();
 1.26912 +            cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
 1.26913 +            S.diagonal();
 1.26914 +            *this = V*S*U;
 1.26915 +          }
 1.26916 +        }
 1.26917 +#endif
 1.26918 +      }
 1.26919 +      return *this;
 1.26920 +    }
 1.26921 +
 1.26922 +    CImg<Tfloat> get_invert(const bool use_LU=true) const {
 1.26923 +      return CImg<Tfloat>(*this,false).invert(use_LU);
 1.26924 +    }
 1.26925 +
 1.26926 +    //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
 1.26927 +    CImg<T>& pseudoinvert() {
 1.26928 +      return get_pseudoinvert().transfer_to(*this);
 1.26929 +    }
 1.26930 +
 1.26931 +    CImg<Tfloat> get_pseudoinvert() const {
 1.26932 +      CImg<Tfloat> U, S, V;
 1.26933 +      SVD(U,S,V);
 1.26934 +      cimg_forX(V,x) {
 1.26935 +        const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
 1.26936 +        cimg_forY(V,y) V(x,y)*=invs;
 1.26937 +      }
 1.26938 +      return V*U.transpose();
 1.26939 +    }
 1.26940 +
 1.26941 +    //! Compute the cross product between two 3d vectors.
 1.26942 +    template<typename t>
 1.26943 +    CImg<T>& cross(const CImg<t>& img) {
 1.26944 +      if (width!=1 || height<3 || img.width!=1 || img.height<3)
 1.26945 +        throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
 1.26946 +                                    pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
 1.26947 +      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
 1.26948 +      (*this)[0] = (T)(y*img[2]-z*img[1]);
 1.26949 +      (*this)[1] = (T)(z*img[0]-x*img[2]);
 1.26950 +      (*this)[2] = (T)(x*img[1]-y*img[0]);
 1.26951 +      return *this;
 1.26952 +    }
 1.26953 +
 1.26954 +    template<typename t>
 1.26955 +    CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
 1.26956 +      typedef typename cimg::superset<T,t>::type Tt;
 1.26957 +      return CImg<Tt>(*this).cross(img);
 1.26958 +    }
 1.26959 +
 1.26960 +    //! Solve a linear system AX=B where B=*this.
 1.26961 +    template<typename t>
 1.26962 +    CImg<T>& solve(const CImg<t>& A) {
 1.26963 +      if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
 1.26964 +        throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
 1.26965 +                                    "size of given matrix A is (%u,%u,%u,%u).",
 1.26966 +                                    pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
 1.26967 +
 1.26968 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.26969 +      if (A.width==A.height) {
 1.26970 +#ifdef cimg_use_lapack
 1.26971 +        char TRANS='N';
 1.26972 +        int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
 1.26973 +        Ttfloat
 1.26974 +          *lapA = new Ttfloat[N*N],
 1.26975 +          *lapB = new Ttfloat[N],
 1.26976 +          *WORK = new Ttfloat[LWORK];
 1.26977 +        cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
 1.26978 +        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
 1.26979 +        cimg::getrf(N,lapA,IPIV,INFO);
 1.26980 +        if (INFO)
 1.26981 +          cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
 1.26982 +                     pixel_type(),INFO);
 1.26983 +        if (!INFO) {
 1.26984 +          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
 1.26985 +          if (INFO)
 1.26986 +            cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
 1.26987 +                       pixel_type(),INFO);
 1.26988 +        }
 1.26989 +        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
 1.26990 +        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
 1.26991 +#else
 1.26992 +        CImg<Ttfloat> lu(A);
 1.26993 +        CImg<Ttfloat> indx;
 1.26994 +        bool d;
 1.26995 +        lu._LU(indx,d);
 1.26996 +        _solve(lu,indx);
 1.26997 +#endif
 1.26998 +      } else assign(A.get_pseudoinvert()*(*this));
 1.26999 +      return *this;
 1.27000 +    }
 1.27001 +
 1.27002 +    template<typename t>
 1.27003 +    CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
 1.27004 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.27005 +      return CImg<Ttfloat>(*this,false).solve(A);
 1.27006 +    }
 1.27007 +
 1.27008 +    template<typename t, typename ti>
 1.27009 +    CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
 1.27010 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.27011 +      const int N = size();
 1.27012 +      int ii = -1;
 1.27013 +      Ttfloat sum;
 1.27014 +      for (int i=0; i<N; ++i) {
 1.27015 +        const int ip = (int)indx[i];
 1.27016 +        Ttfloat sum = (*this)(ip);
 1.27017 +        (*this)(ip) = (*this)(i);
 1.27018 +        if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
 1.27019 +        else if (sum!=0) ii=i;
 1.27020 +        (*this)(i) = (T)sum;
 1.27021 +      }
 1.27022 +      { for (int i=N-1; i>=0; --i) {
 1.27023 +        sum = (*this)(i);
 1.27024 +        for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
 1.27025 +        (*this)(i) = (T)(sum/A(i,i));
 1.27026 +      }}
 1.27027 +      return *this;
 1.27028 +    }
 1.27029 +
 1.27030 +    //! 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 ].
 1.27031 +    // (Use the Thomas Algorithm).
 1.27032 +    template<typename t>
 1.27033 +    CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
 1.27034 +      const int siz = (int)size();
 1.27035 +      if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
 1.27036 +        throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
 1.27037 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.27038 +      CImg<Ttfloat> nc(siz);
 1.27039 +      const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
 1.27040 +      T *ptrnc = nc.data, *ptrd = data;
 1.27041 +      const Ttfloat valb0 = (Ttfloat)*(ptrb++);
 1.27042 +      *ptrnc = *(ptrc++)/valb0;
 1.27043 +      Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
 1.27044 +      for (int i = 1; i<siz; ++i) {
 1.27045 +        const Ttfloat
 1.27046 +          vala = (Tfloat)*(ptra++),
 1.27047 +          id = 1/(*(ptrb++) - *(ptrnc++)*vala);
 1.27048 +        *ptrnc = *(ptrc++)*id;
 1.27049 +        vald = ((*ptrd-=vala*vald)*=id);
 1.27050 +        ++ptrd;
 1.27051 +      }
 1.27052 +      vald = *(--ptrd);
 1.27053 +      for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
 1.27054 +      return *this;
 1.27055 +    }
 1.27056 +
 1.27057 +    template<typename t>
 1.27058 +    CImg<typename cimg::superset2<T,t,float>::type> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
 1.27059 +      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 1.27060 +      return CImg<Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
 1.27061 +    }
 1.27062 +
 1.27063 +    //! Sort values of a vector and get permutations.
 1.27064 +    template<typename t>
 1.27065 +    CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
 1.27066 +      if (is_empty()) permutations.assign();
 1.27067 +      else {
 1.27068 +        if (permutations.size()!=size()) permutations.assign(size());
 1.27069 +        cimg_foroff(permutations,off) permutations[off] = (t)off;
 1.27070 +        _quicksort(0,size()-1,permutations,increasing);
 1.27071 +      }
 1.27072 +      return *this;
 1.27073 +    }
 1.27074 +
 1.27075 +    template<typename t>
 1.27076 +    CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
 1.27077 +      return (+*this).sort(permutations,increasing);
 1.27078 +    }
 1.27079 +
 1.27080 +    // Sort image values.
 1.27081 +    CImg<T>& sort(const bool increasing=true) {
 1.27082 +      CImg<T> foo;
 1.27083 +      return sort(foo,increasing);
 1.27084 +    }
 1.27085 +
 1.27086 +    CImg<T> get_sort(const bool increasing=true) const {
 1.27087 +      return (+*this).sort(increasing);
 1.27088 +    }
 1.27089 +
 1.27090 +    template<typename t>
 1.27091 +    CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
 1.27092 +      if (min<max) {
 1.27093 +        const int mid = (min+max)/2;
 1.27094 +        if (increasing) {
 1.27095 +          if ((*this)[min]>(*this)[mid]) {
 1.27096 +            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 1.27097 +          if ((*this)[mid]>(*this)[max]) {
 1.27098 +            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 1.27099 +          if ((*this)[min]>(*this)[mid]) {
 1.27100 +            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 1.27101 +        } else {
 1.27102 +          if ((*this)[min]<(*this)[mid]) {
 1.27103 +            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 1.27104 +          if ((*this)[mid]<(*this)[max]) {
 1.27105 +            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 1.27106 +          if ((*this)[min]<(*this)[mid]) {
 1.27107 +            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 1.27108 +        }
 1.27109 +        if (max-min>=3) {
 1.27110 +          const T pivot = (*this)[mid];
 1.27111 +          int i = min, j = max;
 1.27112 +          if (increasing) {
 1.27113 +            do {
 1.27114 +              while ((*this)[i]<pivot) ++i;
 1.27115 +              while ((*this)[j]>pivot) --j;
 1.27116 +              if (i<=j) {
 1.27117 +                cimg::swap((*this)[i],(*this)[j]);
 1.27118 +                cimg::swap(permutations[i++],permutations[j--]);
 1.27119 +              }
 1.27120 +            } while (i<=j);
 1.27121 +          } else {
 1.27122 +            do {
 1.27123 +              while ((*this)[i]>pivot) ++i;
 1.27124 +              while ((*this)[j]<pivot) --j;
 1.27125 +              if (i<=j) {
 1.27126 +                cimg::swap((*this)[i],(*this)[j]);
 1.27127 +                cimg::swap(permutations[i++],permutations[j--]);
 1.27128 +              }
 1.27129 +            } while (i<=j);
 1.27130 +          }
 1.27131 +          if (min<j) _quicksort(min,j,permutations,increasing);
 1.27132 +          if (i<max) _quicksort(i,max,permutations,increasing);
 1.27133 +        }
 1.27134 +      }
 1.27135 +      return *this;
 1.27136 +    }
 1.27137 +
 1.27138 +    //! Get a permutation of the pixels.
 1.27139 +    template<typename t>
 1.27140 +    CImg<T>& permute(const CImg<t>& permutation) {
 1.27141 +      return get_permute(permutation).transfer_to(*this);
 1.27142 +    }
 1.27143 +
 1.27144 +    template<typename t>
 1.27145 +    CImg<T> get_permute(const CImg<t>& permutation) const {
 1.27146 +      if (permutation.size()!=size())
 1.27147 +        throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
 1.27148 +                                    "have different sizes.",
 1.27149 +                                    pixel_type(),width,height,depth,dim,data,
 1.27150 +                                    permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
 1.27151 +      CImg<T> res(width,height,depth,dim);
 1.27152 +      const t *p = permutation.ptr(permutation.size());
 1.27153 +      cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
 1.27154 +      return res;
 1.27155 +    }
 1.27156 +
 1.27157 +    //! Compute the SVD of a general matrix.
 1.27158 +    template<typename t>
 1.27159 +    const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
 1.27160 +                       const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
 1.27161 +      if (is_empty()) { U.assign(); S.assign(); V.assign(); }
 1.27162 +      else {
 1.27163 +        U = *this;
 1.27164 +        if (lambda!=0) {
 1.27165 +          const unsigned int delta = cimg::min(U.width,U.height);
 1.27166 +          for (unsigned int i=0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
 1.27167 +        }
 1.27168 +        if (S.size()<width) S.assign(1,width);
 1.27169 +        if (V.width<width || V.height<height) V.assign(width,width);
 1.27170 +        CImg<t> rv1(width);
 1.27171 +        t anorm = 0, c, f, g = 0, h, s, scale = 0;
 1.27172 +        int l = 0, nm = 0;
 1.27173 +
 1.27174 +        cimg_forX(U,i) {
 1.27175 +          l = i+1; rv1[i] = scale*g; g = s = scale = 0;
 1.27176 +          if (i<dimy()) {
 1.27177 +            for (int k=i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
 1.27178 +            if (scale) {
 1.27179 +              for (int k=i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
 1.27180 +              f = U(i,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
 1.27181 +              for (int j=l; j<dimx(); ++j) {
 1.27182 +                s = 0; for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
 1.27183 +                f = s/h;
 1.27184 +                { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
 1.27185 +              }
 1.27186 +              { for (int k=i; k<dimy(); ++k) U(i,k)*= scale; }
 1.27187 +            }
 1.27188 +          }
 1.27189 +          S[i]=scale*g;
 1.27190 +
 1.27191 +          g = s = scale = 0;
 1.27192 +          if (i<dimy() && i!=dimx()-1) {
 1.27193 +            for (int k=l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
 1.27194 +            if (scale) {
 1.27195 +              for (int k=l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
 1.27196 +              f = U(l,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
 1.27197 +              { for (int k=l; k<dimx(); ++k) rv1[k]=U(k,i)/h; }
 1.27198 +              for (int j=l; j<dimy(); ++j) {
 1.27199 +                s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
 1.27200 +                { for (int k=l; k<dimx(); ++k) U(k,j)+= s*rv1[k]; }
 1.27201 +              }
 1.27202 +              { for (int k=l; k<dimx(); ++k) U(k,i)*= scale; }
 1.27203 +            }
 1.27204 +          }
 1.27205 +          anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
 1.27206 +        }
 1.27207 +
 1.27208 +        { for (int i=dimx()-1; i>=0; --i) {
 1.27209 +          if (i<dimx()-1) {
 1.27210 +            if (g) {
 1.27211 +              { for (int j=l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; }
 1.27212 +              for (int j=l; j<dimx(); ++j) {
 1.27213 +                s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
 1.27214 +                { for (int k=l; k<dimx(); ++k) V(j,k)+= s*V(i,k); }
 1.27215 +              }
 1.27216 +            }
 1.27217 +            for (int j=l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
 1.27218 +          }
 1.27219 +          V(i,i) = (t)1.0; g = rv1[i]; l = i;
 1.27220 +        }
 1.27221 +        }
 1.27222 +
 1.27223 +        { for (int i=cimg::min(dimx(),dimy())-1; i>=0; --i) {
 1.27224 +          l = i+1; g = S[i];
 1.27225 +          for (int j=l; j<dimx(); ++j) U(j,i) = 0;
 1.27226 +          if (g) {
 1.27227 +            g = 1/g;
 1.27228 +            for (int j=l; j<dimx(); ++j) {
 1.27229 +              s = 0; for (int k=l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
 1.27230 +              f = (s/U(i,i))*g;
 1.27231 +              { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
 1.27232 +            }
 1.27233 +            { for (int j=i; j<dimy(); ++j) U(i,j)*= g; }
 1.27234 +          } else for (int j=i; j<dimy(); ++j) U(i,j) = 0;
 1.27235 +          ++U(i,i);
 1.27236 +        }
 1.27237 +        }
 1.27238 +
 1.27239 +        for (int k=dimx()-1; k>=0; --k) {
 1.27240 +          for (unsigned int its=0; its<max_iter; ++its) {
 1.27241 +            bool flag = true;
 1.27242 +            for (l=k; l>=1; --l) {
 1.27243 +              nm = l-1;
 1.27244 +              if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
 1.27245 +              if ((cimg::abs(S[nm])+anorm)==anorm) break;
 1.27246 +            }
 1.27247 +            if (flag) {
 1.27248 +              c = 0; s = 1;
 1.27249 +              for (int i=l; i<=k; ++i) {
 1.27250 +                f = s*rv1[i]; rv1[i] = c*rv1[i];
 1.27251 +                if ((cimg::abs(f)+anorm)==anorm) break;
 1.27252 +                g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
 1.27253 +                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; }
 1.27254 +              }
 1.27255 +            }
 1.27256 +            const t z = S[k];
 1.27257 +            if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
 1.27258 +            nm = k-1;
 1.27259 +            t x = S[l], y = S[nm];
 1.27260 +            g = rv1[nm]; h = rv1[k];
 1.27261 +            f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
 1.27262 +            g = (t)cimg::_pythagore(f,1.0);
 1.27263 +            f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
 1.27264 +            c = s = 1;
 1.27265 +            for (int j=l; j<=nm; ++j) {
 1.27266 +              const int i = j+1;
 1.27267 +              g = rv1[i]; h = s*g; g = c*g;
 1.27268 +              t y = S[i];
 1.27269 +              t z = (t)cimg::_pythagore(f,h);
 1.27270 +              rv1[j] = z; c = f/z; s = h/z;
 1.27271 +              f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
 1.27272 +              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; }
 1.27273 +              z = (t)cimg::_pythagore(f,h); S[j] = z;
 1.27274 +              if (z) { z = 1/z; c = f*z; s = h*z; }
 1.27275 +              f = c*g+s*y; x = c*y-s*g;
 1.27276 +              { 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; }}
 1.27277 +            }
 1.27278 +            rv1[l] = 0; rv1[k]=f; S[k]=x;
 1.27279 +          }
 1.27280 +        }
 1.27281 +
 1.27282 +        if (sorting) {
 1.27283 +          CImg<intT> permutations(width);
 1.27284 +          CImg<t> tmp(width);
 1.27285 +          S.sort(permutations,false);
 1.27286 +          cimg_forY(U,k) {
 1.27287 +            cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
 1.27288 +            cimg_std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
 1.27289 +          }
 1.27290 +          { cimg_forY(V,k) {
 1.27291 +            cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
 1.27292 +            cimg_std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
 1.27293 +          }}
 1.27294 +        }
 1.27295 +      }
 1.27296 +    return *this;
 1.27297 +    }
 1.27298 +
 1.27299 +    //! Compute the SVD of a general matrix.
 1.27300 +    template<typename t>
 1.27301 +    const CImg<T>& SVD(CImgList<t>& USV) const {
 1.27302 +      if (USV.size<3) USV.assign(3);
 1.27303 +      return SVD(USV[0],USV[1],USV[2]);
 1.27304 +    }
 1.27305 +
 1.27306 +    //! Compute the SVD of a general matrix.
 1.27307 +    CImgList<Tfloat> get_SVD(const bool sorting=true) const {
 1.27308 +      CImgList<Tfloat> res(3);
 1.27309 +      SVD(res[0],res[1],res[2],sorting);
 1.27310 +      return res;
 1.27311 +    }
 1.27312 +
 1.27313 +    // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
 1.27314 +    template<typename t>
 1.27315 +    CImg<T>& _LU(CImg<t>& indx, bool& d) {
 1.27316 +      const int N = dimx();
 1.27317 +      int imax = 0;
 1.27318 +      CImg<Tfloat> vv(N);
 1.27319 +      indx.assign(N);
 1.27320 +      d = true;
 1.27321 +      cimg_forX(*this,i) {
 1.27322 +        Tfloat vmax = 0;
 1.27323 +        cimg_forX(*this,j) {
 1.27324 +          const Tfloat tmp = cimg::abs((*this)(j,i));
 1.27325 +          if (tmp>vmax) vmax = tmp;
 1.27326 +        }
 1.27327 +        if (vmax==0) { indx.fill(0); return fill(0); }
 1.27328 +        vv[i] = 1/vmax;
 1.27329 +      }
 1.27330 +      cimg_forX(*this,j) {
 1.27331 +        for (int i=0; i<j; ++i) {
 1.27332 +          Tfloat sum=(*this)(j,i);
 1.27333 +          for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
 1.27334 +          (*this)(j,i) = (T)sum;
 1.27335 +        }
 1.27336 +        Tfloat vmax = 0;
 1.27337 +        { for (int i=j; i<dimx(); ++i) {
 1.27338 +          Tfloat sum=(*this)(j,i);
 1.27339 +          for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
 1.27340 +          (*this)(j,i) = (T)sum;
 1.27341 +          const Tfloat tmp = vv[i]*cimg::abs(sum);
 1.27342 +          if (tmp>=vmax) { vmax=tmp; imax=i; }
 1.27343 +        }}
 1.27344 +        if (j!=imax) {
 1.27345 +          cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
 1.27346 +          d =!d;
 1.27347 +          vv[imax] = vv[j];
 1.27348 +        }
 1.27349 +        indx[j] = (t)imax;
 1.27350 +        if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
 1.27351 +        if (j<N) {
 1.27352 +          const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
 1.27353 +          for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
 1.27354 +        }
 1.27355 +      }
 1.27356 +      return *this;
 1.27357 +    }
 1.27358 +
 1.27359 +    //! Compute the eigenvalues and eigenvectors of a matrix.
 1.27360 +    template<typename t>
 1.27361 +    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
 1.27362 +      if (is_empty()) { val.assign(); vec.assign(); }
 1.27363 +      else {
 1.27364 +        if (width!=height || depth>1 || dim>1)
 1.27365 +          throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
 1.27366 +                                      pixel_type(),width,height,depth,dim,data);
 1.27367 +        if (val.size()<width) val.assign(1,width);
 1.27368 +        if (vec.size()<width*width) vec.assign(width,width);
 1.27369 +        switch (width) {
 1.27370 +        case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
 1.27371 +        case 2 : {
 1.27372 +          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
 1.27373 +          double f = e*e-4*(a*d-b*c);
 1.27374 +          if (f<0)
 1.27375 +            cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
 1.27376 +                       pixel_type());
 1.27377 +          f = cimg_std::sqrt(f);
 1.27378 +          const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
 1.27379 +          const double theta1 = cimg_std::atan2(l2-a,b), theta2 = cimg_std::atan2(l1-a,b);
 1.27380 +          val[0]=(t)l2;
 1.27381 +          val[1]=(t)l1;
 1.27382 +          vec(0,0) = (t)cimg_std::cos(theta1);
 1.27383 +          vec(0,1) = (t)cimg_std::sin(theta1);
 1.27384 +          vec(1,0) = (t)cimg_std::cos(theta2);
 1.27385 +          vec(1,1) = (t)cimg_std::sin(theta2);
 1.27386 +        } break;
 1.27387 +        default :
 1.27388 +          throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
 1.27389 +                                      "to 2x2 matrices (given is %ux%u)",
 1.27390 +                                      pixel_type(),width,height);
 1.27391 +        }
 1.27392 +      }
 1.27393 +      return *this;
 1.27394 +    }
 1.27395 +
 1.27396 +    //! Compute the eigenvalues and eigenvectors of a matrix.
 1.27397 +    CImgList<Tfloat> get_eigen() const {
 1.27398 +      CImgList<Tfloat> res(2);
 1.27399 +      eigen(res[0],res[1]);
 1.27400 +      return res;
 1.27401 +    }
 1.27402 +
 1.27403 +    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
 1.27404 +    template<typename t>
 1.27405 +    const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
 1.27406 +      if (is_empty()) { val.assign(); vec.assign(); }
 1.27407 +      else {
 1.27408 +#ifdef cimg_use_lapack
 1.27409 +        char JOB = 'V', UPLO = 'U';
 1.27410 +        int N = width, LWORK = 4*N, INFO;
 1.27411 +        Tfloat
 1.27412 +          *lapA = new Tfloat[N*N],
 1.27413 +          *lapW = new Tfloat[N],
 1.27414 +          *WORK = new Tfloat[LWORK];
 1.27415 +        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
 1.27416 +        cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
 1.27417 +        if (INFO)
 1.27418 +          cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
 1.27419 +                     pixel_type(),INFO);
 1.27420 +        val.assign(1,N);
 1.27421 +        vec.assign(N,N);
 1.27422 +        if (!INFO) {
 1.27423 +          cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
 1.27424 +          cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
 1.27425 +        } else { val.fill(0); vec.fill(0); }
 1.27426 +        delete[] lapA; delete[] lapW; delete[] WORK;
 1.27427 +#else
 1.27428 +        if (width!=height || depth>1 || dim>1)
 1.27429 +          throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
 1.27430 +                                      pixel_type(),width,height,depth,dim,data);
 1.27431 +        val.assign(1,width);
 1.27432 +        if (vec.data) vec.assign(width,width);
 1.27433 +        if (width<3) return eigen(val,vec);
 1.27434 +        CImg<t> V(width,width);
 1.27435 +        SVD(vec,val,V,false);
 1.27436 +        bool ambiguous = false;
 1.27437 +        float eig = 0;
 1.27438 +        cimg_forY(val,p) {       // check for ambiguous cases.
 1.27439 +          if (val[p]>eig) eig = (float)val[p];
 1.27440 +          t scal = 0;
 1.27441 +          cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
 1.27442 +          if (cimg::abs(scal)<0.9f) ambiguous = true;
 1.27443 +          if (scal<0) val[p] = -val[p];
 1.27444 +        }
 1.27445 +        if (ambiguous) {
 1.27446 +          (eig*=2)++;
 1.27447 +          SVD(vec,val,V,false,40,eig);
 1.27448 +          val-=eig;
 1.27449 +        }
 1.27450 +        CImg<intT> permutations(width);  // sort eigenvalues in decreasing order
 1.27451 +        CImg<t> tmp(width);
 1.27452 +        val.sort(permutations,false);
 1.27453 +        cimg_forY(vec,k) {
 1.27454 +          cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
 1.27455 +          cimg_std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
 1.27456 +        }
 1.27457 +#endif
 1.27458 +      }
 1.27459 +      return *this;
 1.27460 +    }
 1.27461 +
 1.27462 +    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
 1.27463 +    CImgList<Tfloat> get_symmetric_eigen() const {
 1.27464 +      CImgList<Tfloat> res(2);
 1.27465 +      symmetric_eigen(res[0],res[1]);
 1.27466 +      return res;
 1.27467 +    }
 1.27468 +
 1.27469 +    //@}
 1.27470 +    //-------------------
 1.27471 +    //
 1.27472 +    //! \name Display
 1.27473 +    //@{
 1.27474 +    //-------------------
 1.27475 +
 1.27476 +    //! Display an image into a CImgDisplay window.
 1.27477 +    const CImg<T>& display(CImgDisplay& disp) const {
 1.27478 +      disp.display(*this);
 1.27479 +      return *this;
 1.27480 +    }
 1.27481 +
 1.27482 +    //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
 1.27483 +    const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
 1.27484 +      return _display(disp,0,display_info);
 1.27485 +    }
 1.27486 +
 1.27487 +    //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
 1.27488 +    const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
 1.27489 +      CImgDisplay disp;
 1.27490 +      return _display(disp,title,display_info);
 1.27491 +    }
 1.27492 +
 1.27493 +    const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
 1.27494 +      if (is_empty())
 1.27495 +        throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.27496 +                                    pixel_type(),width,height,depth,dim,data);
 1.27497 +      unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
 1.27498 +      int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
 1.27499 +      float frametiming = 5;
 1.27500 +
 1.27501 +      char ntitle[256] = { 0 };
 1.27502 +      if (!disp) {
 1.27503 +        if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 1.27504 +        disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 1.27505 +      }
 1.27506 +      cimg_std::strncpy(ntitle,disp.title,255);
 1.27507 +      if (display_info) print(ntitle);
 1.27508 +
 1.27509 +      CImg<T> zoom;
 1.27510 +      for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
 1.27511 +        if (reset_view) {
 1.27512 +          XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
 1.27513 +          x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
 1.27514 +          oldw = disp.width; oldh = disp.height;
 1.27515 +          reset_view = false;
 1.27516 +        }
 1.27517 +        if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
 1.27518 +        else zoom = get_crop(x0,y0,z0,x1,y1,z1);
 1.27519 +
 1.27520 +        const unsigned int
 1.27521 +          dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
 1.27522 +          tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
 1.27523 +        if (resize_disp) {
 1.27524 +          const unsigned int
 1.27525 +            ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
 1.27526 +            dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
 1.27527 +            imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
 1.27528 +          disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
 1.27529 +          resize_disp = false;
 1.27530 +        }
 1.27531 +        oldw = tw; oldh = th;
 1.27532 +
 1.27533 +        bool
 1.27534 +          go_up = false, go_down = false, go_left = false, go_right = false,
 1.27535 +          go_inc = false, go_dec = false, go_in = false, go_out = false,
 1.27536 +          go_in_center = false;
 1.27537 +        const CImg<T>& visu = zoom?zoom:*this;
 1.27538 +        const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
 1.27539 +        if (disp.wheel) {
 1.27540 +          if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
 1.27541 +          else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
 1.27542 +          else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
 1.27543 +          else mkey = 0;
 1.27544 +          disp.wheel = 0;
 1.27545 +        } else mkey = 0;
 1.27546 +        const int
 1.27547 +          sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
 1.27548 +          sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
 1.27549 +        if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
 1.27550 +          x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
 1.27551 +          if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
 1.27552 +          resize_disp = true;
 1.27553 +        } else switch (key = disp.key) {
 1.27554 +        case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
 1.27555 +        case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
 1.27556 +          const unsigned int
 1.27557 +            w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
 1.27558 +            h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
 1.27559 +          disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
 1.27560 +          for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
 1.27561 +            if (disp.is_resized) disp.resize();
 1.27562 +            if (!timer) {
 1.27563 +              visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
 1.27564 +              if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
 1.27565 +            }
 1.27566 +            if (++timer>(unsigned int)frametiming) timer = 0;
 1.27567 +            if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
 1.27568 +            switch (key = disp.key) {
 1.27569 +            case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 1.27570 +            case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
 1.27571 +            case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
 1.27572 +            case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 1.27573 +              disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 1.27574 +                                         CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
 1.27575 +              disp.key = key = 0;
 1.27576 +            } break;
 1.27577 +            case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 1.27578 +              disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
 1.27579 +              disp.key = key = 0;
 1.27580 +            } break;
 1.27581 +            case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 1.27582 +              disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
 1.27583 +              disp.key = key = 0;
 1.27584 +            } break;
 1.27585 +            case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 1.27586 +              disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
 1.27587 +              disp.key = key = 0;
 1.27588 +            } break;
 1.27589 +            }
 1.27590 +            frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
 1.27591 +            disp.wait(20);
 1.27592 +          }
 1.27593 +          const unsigned int
 1.27594 +            w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
 1.27595 +            h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
 1.27596 +          disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
 1.27597 +          key = disp.key = disp.button = disp.wheel = 0;
 1.27598 +        } break;
 1.27599 +        case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
 1.27600 +        case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
 1.27601 +        case cimg::keyPADSUB : go_out = true; key = 0; break;
 1.27602 +        case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
 1.27603 +        case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
 1.27604 +        case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
 1.27605 +        case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
 1.27606 +        case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
 1.27607 +        case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
 1.27608 +        case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
 1.27609 +        case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
 1.27610 +        case cimg::keyPAGEUP : go_inc = true; key = 0; break;
 1.27611 +        case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
 1.27612 +        }
 1.27613 +        if (go_in) {
 1.27614 +          const int
 1.27615 +            mx = go_in_center?disp.dimx()/2:disp.mouse_x,
 1.27616 +            my = go_in_center?disp.dimy()/2:disp.mouse_y,
 1.27617 +            mX = mx*(width+(depth>1?depth:0))/disp.width,
 1.27618 +            mY = my*(height+(depth>1?depth:0))/disp.height;
 1.27619 +          int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
 1.27620 +          if (mX<dimx() && mY<dimy())  { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
 1.27621 +          if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
 1.27622 +          if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
 1.27623 +          if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
 1.27624 +          if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
 1.27625 +          if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
 1.27626 +        }
 1.27627 +        if (go_out) {
 1.27628 +          const int
 1.27629 +            deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
 1.27630 +            ndeltax = deltax?deltax:(width>1?1:0),
 1.27631 +            ndeltay = deltay?deltay:(height>1?1:0),
 1.27632 +            ndeltaz = deltaz?deltaz:(depth>1?1:0);
 1.27633 +          x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
 1.27634 +          x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
 1.27635 +          if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
 1.27636 +          if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
 1.27637 +          if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
 1.27638 +          if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
 1.27639 +          if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
 1.27640 +          if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
 1.27641 +        }
 1.27642 +        if (go_left) {
 1.27643 +          const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 1.27644 +          if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
 1.27645 +          else { x1-=x0; x0 = 0; }
 1.27646 +        }
 1.27647 +        if (go_right) {
 1.27648 +          const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 1.27649 +          if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
 1.27650 +          else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
 1.27651 +        }
 1.27652 +        if (go_up) {
 1.27653 +          const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 1.27654 +          if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
 1.27655 +          else { y1-=y0; y0 = 0; }
 1.27656 +        }
 1.27657 +        if (go_down) {
 1.27658 +          const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 1.27659 +          if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
 1.27660 +          else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
 1.27661 +        }
 1.27662 +        if (go_inc) {
 1.27663 +          const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 1.27664 +          if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
 1.27665 +          else { z1-=z0; z0 = 0; }
 1.27666 +        }
 1.27667 +        if (go_dec) {
 1.27668 +          const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 1.27669 +          if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
 1.27670 +          else { z0+=(depth-1-z1); z1 = depth-1; }
 1.27671 +        }
 1.27672 +      }
 1.27673 +      disp.key = key;
 1.27674 +      return *this;
 1.27675 +    }
 1.27676 +
 1.27677 +    //! Simple interface to select a shape from an image.
 1.27678 +    /**
 1.27679 +       \param selection  Array of 6 values containing the selection result
 1.27680 +       \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
 1.27681 +       \param disp       Display window used to make the selection
 1.27682 +       \param XYZ        Initial XYZ position (for volumetric images only)
 1.27683 +       \param color      Color of the shape selector.
 1.27684 +    **/
 1.27685 +    CImg<T>& select(CImgDisplay &disp,
 1.27686 +                    const int select_type=2, unsigned int *const XYZ=0,
 1.27687 +                    const unsigned char *const color=0) {
 1.27688 +      return get_select(disp,select_type,XYZ,color).transfer_to(*this);
 1.27689 +    }
 1.27690 +
 1.27691 +    //! Simple interface to select a shape from an image.
 1.27692 +    CImg<T>& select(const char *const title,
 1.27693 +                    const int select_type=2, unsigned int *const XYZ=0,
 1.27694 +                    const unsigned char *const color=0) {
 1.27695 +      return get_select(title,select_type,XYZ,color).transfer_to(*this);
 1.27696 +    }
 1.27697 +
 1.27698 +    //! Simple interface to select a shape from an image.
 1.27699 +    CImg<intT> get_select(CImgDisplay &disp,
 1.27700 +                          const int select_type=2, unsigned int *const XYZ=0,
 1.27701 +                          const unsigned char *const color=0) const {
 1.27702 +      return _get_select(disp,0,select_type,XYZ,color,0,0,0);
 1.27703 +    }
 1.27704 +
 1.27705 +    //! Simple interface to select a shape from an image.
 1.27706 +    CImg<intT> get_select(const char *const title,
 1.27707 +                          const int select_type=2, unsigned int *const XYZ=0,
 1.27708 +                          const unsigned char *const color=0) const {
 1.27709 +      CImgDisplay disp;
 1.27710 +      return _get_select(disp,title,select_type,XYZ,color,0,0,0);
 1.27711 +    }
 1.27712 +
 1.27713 +    CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
 1.27714 +                           const int coords_type, unsigned int *const XYZ,
 1.27715 +                           const unsigned char *const color,
 1.27716 +                           const int origX, const int origY, const int origZ) const {
 1.27717 +      if (is_empty())
 1.27718 +        throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.27719 +                                    pixel_type(),width,height,depth,dim,data);
 1.27720 +      if (!disp) {
 1.27721 +        char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
 1.27722 +        disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 1.27723 +      }
 1.27724 +
 1.27725 +      const unsigned int
 1.27726 +        old_normalization = disp.normalization,
 1.27727 +        hatch = 0x55555555;
 1.27728 +
 1.27729 +      bool old_is_resized = disp.is_resized;
 1.27730 +      disp.normalization = 0;
 1.27731 +      disp.show().key = 0;
 1.27732 +
 1.27733 +      unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
 1.27734 +      if (color) cimg_std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
 1.27735 +
 1.27736 +      int area = 0, clicked_area = 0, phase = 0,
 1.27737 +        X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
 1.27738 +        X1 =-1, Y1 = -1, Z1 = -1,
 1.27739 +        X = -1, Y = -1, Z = -1,
 1.27740 +        oX = X, oY = Y, oZ = Z;
 1.27741 +      unsigned int old_button = 0, key = 0;
 1.27742 +
 1.27743 +      bool shape_selected = false, text_down = false;
 1.27744 +      CImg<ucharT> visu, visu0;
 1.27745 +      char text[1024] = { 0 };
 1.27746 +
 1.27747 +      while (!key && !disp.is_closed && !shape_selected) {
 1.27748 +
 1.27749 +        // Handle mouse motion and selection
 1.27750 +        oX = X; oY = Y; oZ = Z;
 1.27751 +        int mx = disp.mouse_x, my = disp.mouse_y;
 1.27752 +        const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
 1.27753 +
 1.27754 +        area = 0;
 1.27755 +        if (mX<dimx() && mY<dimy())  { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
 1.27756 +        if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
 1.27757 +        if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
 1.27758 +
 1.27759 +        switch (key = disp.key) {
 1.27760 +        case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 1.27761 +        case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
 1.27762 +        case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
 1.27763 +        case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 1.27764 +          disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 1.27765 +                                     CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 1.27766 +          disp.key = key = 0;
 1.27767 +        } break;
 1.27768 +        case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 1.27769 +          disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 1.27770 +          disp.key = key = 0; visu0.assign();
 1.27771 +        } break;
 1.27772 +        case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 1.27773 +          disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
 1.27774 +          disp.key = key = 0; visu0.assign();
 1.27775 +        } break;
 1.27776 +        case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 1.27777 +          disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
 1.27778 +          disp.key = key = 0; visu0.assign();
 1.27779 +        } break;
 1.27780 +        case cimg::keyS : if (disp.is_keyCTRLLEFT) {
 1.27781 +          static unsigned int snap_number = 0;
 1.27782 +          char filename[32] = { 0 };
 1.27783 +          cimg_std::FILE *file;
 1.27784 +          do {
 1.27785 +            cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 1.27786 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.27787 +          } while (file);
 1.27788 +          if (visu0) {
 1.27789 +            visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
 1.27790 +            visu0.save(filename);
 1.27791 +            visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
 1.27792 +          }
 1.27793 +          disp.key = key = 0;
 1.27794 +        } break;
 1.27795 +        case cimg::keyO : if (disp.is_keyCTRLLEFT) {
 1.27796 +          static unsigned int snap_number = 0;
 1.27797 +          char filename[32] = { 0 };
 1.27798 +          cimg_std::FILE *file;
 1.27799 +          do {
 1.27800 +            cimg_std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
 1.27801 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.27802 +          } while (file);
 1.27803 +          visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
 1.27804 +          save(filename);
 1.27805 +          visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
 1.27806 +          disp.key = key = 0;
 1.27807 +        } break;
 1.27808 +        }
 1.27809 +
 1.27810 +        if (!area) mx = my = X = Y = Z = -1;
 1.27811 +        else {
 1.27812 +          if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
 1.27813 +          if (!(disp.button&1) && phase>=2) {
 1.27814 +            switch (clicked_area) {
 1.27815 +            case 1 : Z1 = Z; break;
 1.27816 +            case 2 : Y1 = Y; break;
 1.27817 +            case 3 : X1 = X; break;
 1.27818 +            }
 1.27819 +          }
 1.27820 +          if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
 1.27821 +          if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
 1.27822 +          if (disp.wheel) {
 1.27823 +            if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
 1.27824 +              switch (area) {
 1.27825 +              case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
 1.27826 +              case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
 1.27827 +              case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
 1.27828 +              }
 1.27829 +              disp.wheel = 0;
 1.27830 +            } else key = ~0U;
 1.27831 +          }
 1.27832 +          if ((disp.button&1)!=old_button) {
 1.27833 +            switch (phase++) {
 1.27834 +            case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
 1.27835 +            case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
 1.27836 +            }
 1.27837 +            old_button = disp.button&1;
 1.27838 +          }
 1.27839 +          if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
 1.27840 +        }
 1.27841 +
 1.27842 +        if (phase) {
 1.27843 +          if (!coords_type) shape_selected = phase?true:false;
 1.27844 +          else {
 1.27845 +            if (depth>1) shape_selected = (phase==3)?true:false;
 1.27846 +            else shape_selected = (phase==2)?true:false;
 1.27847 +          }
 1.27848 +        }
 1.27849 +
 1.27850 +        if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
 1.27851 +        if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
 1.27852 +        if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
 1.27853 +        if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
 1.27854 +
 1.27855 +        // Draw visualization image on the display
 1.27856 +        if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
 1.27857 +          if (!visu0) {
 1.27858 +            CImg<Tuchar> tmp, tmp0;
 1.27859 +            if (depth!=1) {
 1.27860 +              tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
 1.27861 +              tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
 1.27862 +            } else tmp = get_channels(0,cimg::min(2U,dim-1));
 1.27863 +            switch (old_normalization) {
 1.27864 +            case 0 : visu0 = tmp; break;
 1.27865 +            case 3 :
 1.27866 +              if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
 1.27867 +              else {
 1.27868 +                const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
 1.27869 +                visu0.assign(tmp.width,tmp.height,1,tmp.dim);
 1.27870 +                unsigned char *ptrd = visu0.end();
 1.27871 +                cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
 1.27872 +              } break;
 1.27873 +            default : visu0 = tmp.normalize(0,255);
 1.27874 +            }
 1.27875 +            visu0.resize(disp);
 1.27876 +          }
 1.27877 +          visu = visu0;
 1.27878 +          if (!color) {
 1.27879 +            if (visu.mean()<200) {
 1.27880 +              foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
 1.27881 +              background_color[0] = background_color[1] = background_color[2] = 0;
 1.27882 +            } else {
 1.27883 +              foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
 1.27884 +              background_color[0] = background_color[1] = background_color[2] = 255;
 1.27885 +            }
 1.27886 +          }
 1.27887 +
 1.27888 +          const int d = (depth>1)?depth:0;
 1.27889 +          if (phase) switch (coords_type) {
 1.27890 +          case 1 : {
 1.27891 +            const int
 1.27892 +              x0 = (int)((X0+0.5f)*disp.width/(width+d)),
 1.27893 +              y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
 1.27894 +              x1 = (int)((X1+0.5f)*disp.width/(width+d)),
 1.27895 +              y1 = (int)((Y1+0.5f)*disp.height/(height+d));
 1.27896 +            visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
 1.27897 +            if (d) {
 1.27898 +              const int
 1.27899 +                zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
 1.27900 +                zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
 1.27901 +                zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
 1.27902 +                zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
 1.27903 +              visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
 1.27904 +                draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
 1.27905 +            }
 1.27906 +          } break;
 1.27907 +          case 2 : {
 1.27908 +            const int
 1.27909 +              x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
 1.27910 +              x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
 1.27911 +            visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
 1.27912 +            if (d) {
 1.27913 +              const int
 1.27914 +                zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
 1.27915 +                zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
 1.27916 +                zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
 1.27917 +                zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
 1.27918 +              visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
 1.27919 +              visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
 1.27920 +            }
 1.27921 +          } break;
 1.27922 +          case 3 : {
 1.27923 +            const int
 1.27924 +              x0 = X0*disp.width/(width+d),
 1.27925 +              y0 = Y0*disp.height/(height+d),
 1.27926 +              x1 = X1*disp.width/(width+d)-1,
 1.27927 +              y1 = Y1*disp.height/(height+d)-1;
 1.27928 +            visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.2f).
 1.27929 +              draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch);
 1.27930 +            if (d) {
 1.27931 +              const int
 1.27932 +                zx0 = (int)((width+Z0)*disp.width/(width+d)),
 1.27933 +                zy0 = (int)((height+Z0)*disp.height/(height+d)),
 1.27934 +                zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
 1.27935 +                zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
 1.27936 +              visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.2f).
 1.27937 +                draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch).
 1.27938 +                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.2f).
 1.27939 +                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.6f,hatch);
 1.27940 +            }
 1.27941 +          } break;
 1.27942 +          } else {
 1.27943 +            const int
 1.27944 +              x0 = X*disp.width/(width+d),
 1.27945 +              y0 = Y*disp.height/(height+d),
 1.27946 +              x1 = (X+1)*disp.width/(width+d)-1,
 1.27947 +              y1 = (Y+1)*disp.height/(height+d)-1;
 1.27948 +            if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
 1.27949 +          }
 1.27950 +
 1.27951 +          if (my<12) text_down = true;
 1.27952 +          if (my>=visu.dimy()-11) text_down = false;
 1.27953 +          if (!coords_type || !phase) {
 1.27954 +            if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
 1.27955 +              if (depth>1) cimg_std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
 1.27956 +              else cimg_std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
 1.27957 +              char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
 1.27958 +              for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
 1.27959 +                cimg_std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
 1.27960 +                ctext = text + cimg::strlen(text);
 1.27961 +                *(ctext++) = ' '; *ctext = '\0';
 1.27962 +              }
 1.27963 +              cimg_std::sprintf(text + cimg::strlen(text),"]");
 1.27964 +            }
 1.27965 +          } else switch (coords_type) {
 1.27966 +          case 1 : {
 1.27967 +            const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = cimg_std::sqrt(dX*dX+dY*dY+dZ*dZ);
 1.27968 +            if (depth>1) cimg_std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
 1.27969 +                                      origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
 1.27970 +            else cimg_std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
 1.27971 +                              origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
 1.27972 +          } break;
 1.27973 +          case 2 :
 1.27974 +            if (depth>1) cimg_std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
 1.27975 +                                      origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
 1.27976 +                                      origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
 1.27977 +                                      1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
 1.27978 +            else  cimg_std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
 1.27979 +                               origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
 1.27980 +                               1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
 1.27981 +            break;
 1.27982 +          default :
 1.27983 +            if (depth>1) cimg_std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
 1.27984 +                                      origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
 1.27985 +                                      1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
 1.27986 +            else  cimg_std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
 1.27987 +                               origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
 1.27988 +
 1.27989 +          }
 1.27990 +          if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
 1.27991 +          disp.display(visu).wait(25);
 1.27992 +        } else if (!shape_selected) disp.wait();
 1.27993 +
 1.27994 +        if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
 1.27995 +      }
 1.27996 +
 1.27997 +      // Return result
 1.27998 +      CImg<intT> res(1,6,1,1,-1);
 1.27999 +      if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
 1.28000 +      if (shape_selected) {
 1.28001 +        if (coords_type==2) {
 1.28002 +          if (X0>X1) cimg::swap(X0,X1);
 1.28003 +          if (Y0>Y1) cimg::swap(Y0,Y1);
 1.28004 +          if (Z0>Z1) cimg::swap(Z0,Z1);
 1.28005 +        }
 1.28006 +        if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
 1.28007 +        switch (coords_type) {
 1.28008 +        case 1 :
 1.28009 +        case 2 :  res[3] = X1; res[4] = Y1; res[5] = Z1;
 1.28010 +        default : res[0] = X0; res[1] = Y0; res[2] = Z0;
 1.28011 +        }
 1.28012 +      }
 1.28013 +      disp.button = 0;
 1.28014 +      disp.normalization = old_normalization;
 1.28015 +      disp.is_resized = old_is_resized;
 1.28016 +      if (key!=~0U) disp.key = key;
 1.28017 +      return res;
 1.28018 +    }
 1.28019 +
 1.28020 +    //! High-level interface for displaying a 3d object.
 1.28021 +    template<typename tp, typename tf, typename tc, typename to>
 1.28022 +    const CImg<T>& display_object3d(CImgDisplay& disp,
 1.28023 +                                    const CImg<tp>& points, const CImgList<tf>& primitives,
 1.28024 +                                    const CImgList<tc>& colors, const to& opacities,
 1.28025 +                                    const bool centering=true,
 1.28026 +                                    const int render_static=4, const int render_motion=1,
 1.28027 +                                    const bool double_sided=false, const float focale=500,
 1.28028 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28029 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28030 +      return _display_object3d(disp,0,points,points.width,primitives,colors,opacities,centering,render_static,
 1.28031 +                               render_motion,double_sided,focale,specular_light,specular_shine,
 1.28032 +                               display_axes,pose_matrix);
 1.28033 +    }
 1.28034 +
 1.28035 +    //! High-level interface for displaying a 3d object.
 1.28036 +    template<typename tp, typename tf, typename tc, typename to>
 1.28037 +    const CImg<T>& display_object3d(const char *const title,
 1.28038 +                                    const CImg<tp>& points, const CImgList<tf>& primitives,
 1.28039 +                                    const CImgList<tc>& colors, const to& opacities,
 1.28040 +                                    const bool centering=true,
 1.28041 +                                    const int render_static=4, const int render_motion=1,
 1.28042 +                                    const bool double_sided=false, const float focale=500,
 1.28043 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28044 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28045 +      CImgDisplay disp;
 1.28046 +      return _display_object3d(disp,title,points,points.width,primitives,colors,opacities,centering,render_static,
 1.28047 +                               render_motion,double_sided,focale,specular_light,specular_shine,
 1.28048 +                               display_axes,pose_matrix);
 1.28049 +    }
 1.28050 +
 1.28051 +    //! High-level interface for displaying a 3d object.
 1.28052 +    template<typename tp, typename tf, typename tc, typename to>
 1.28053 +    const CImg<T>& display_object3d(CImgDisplay& disp,
 1.28054 +                                    const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.28055 +                                    const CImgList<tc>& colors, const to& opacities,
 1.28056 +                                    const bool centering=true,
 1.28057 +                                    const int render_static=4, const int render_motion=1,
 1.28058 +                                    const bool double_sided=false, const float focale=500,
 1.28059 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28060 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28061 +      return _display_object3d(disp,0,points,points.size,primitives,colors,opacities,centering,render_static,
 1.28062 +                               render_motion,double_sided,focale,specular_light,specular_shine,
 1.28063 +                               display_axes,pose_matrix);
 1.28064 +    }
 1.28065 +
 1.28066 +    //! High-level interface for displaying a 3d object.
 1.28067 +    template<typename tp, typename tf, typename tc, typename to>
 1.28068 +    const CImg<T>& display_object3d(const char *const title,
 1.28069 +                                    const CImgList<tp>& points, const CImgList<tf>& primitives,
 1.28070 +                                    const CImgList<tc>& colors, const to& opacities,
 1.28071 +                                    const bool centering=true,
 1.28072 +                                    const int render_static=4, const int render_motion=1,
 1.28073 +                                    const bool double_sided=false, const float focale=500,
 1.28074 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28075 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28076 +      CImgDisplay disp;
 1.28077 +      return _display_object3d(disp,title,points,points.size,primitives,colors,opacities,centering,render_static,
 1.28078 +                               render_motion,double_sided,focale,specular_light,specular_shine,
 1.28079 +                               display_axes,pose_matrix);
 1.28080 +    }
 1.28081 +
 1.28082 +   //! High-level interface for displaying a 3d object.
 1.28083 +    template<typename tp, typename tf, typename tc>
 1.28084 +    const CImg<T>& display_object3d(CImgDisplay &disp,
 1.28085 +                                    const tp& points, const CImgList<tf>& primitives,
 1.28086 +                                    const CImgList<tc>& colors,
 1.28087 +                                    const bool centering=true,
 1.28088 +                                    const int render_static=4, const int render_motion=1,
 1.28089 +                                    const bool double_sided=false, const float focale=500,
 1.28090 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28091 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28092 +      return display_object3d(disp,points,primitives,colors,CImg<floatT>(),centering,
 1.28093 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28094 +                              display_axes,pose_matrix);
 1.28095 +    }
 1.28096 +
 1.28097 +    //! High-level interface for displaying a 3d object.
 1.28098 +    template<typename tp, typename tf, typename tc>
 1.28099 +    const CImg<T>& display_object3d(const char *const title,
 1.28100 +                                    const tp& points, const CImgList<tf>& primitives,
 1.28101 +                                    const CImgList<tc>& colors,
 1.28102 +                                    const bool centering=true,
 1.28103 +                                    const int render_static=4, const int render_motion=1,
 1.28104 +                                    const bool double_sided=false, const float focale=500,
 1.28105 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28106 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28107 +      return display_object3d(title,points,primitives,colors,CImg<floatT>(),centering,
 1.28108 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28109 +                              display_axes,pose_matrix);
 1.28110 +    }
 1.28111 +
 1.28112 +    //! High-level interface for displaying a 3d object.
 1.28113 +    template<typename tp, typename tf>
 1.28114 +    const CImg<T>& display_object3d(CImgDisplay &disp,
 1.28115 +                                    const tp& points, const CImgList<tf>& primitives,
 1.28116 +                                    const bool centering=true,
 1.28117 +                                    const int render_static=4, const int render_motion=1,
 1.28118 +                                    const bool double_sided=false, const float focale=500,
 1.28119 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28120 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28121 +      return display_object3d(disp,points,primitives,CImgList<T>(),centering,
 1.28122 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28123 +                              display_axes,pose_matrix);
 1.28124 +    }
 1.28125 +
 1.28126 +    //! High-level interface for displaying a 3d object.
 1.28127 +    template<typename tp, typename tf>
 1.28128 +    const CImg<T>& display_object3d(const char *const title,
 1.28129 +                                    const tp& points, const CImgList<tf>& primitives,
 1.28130 +                                    const bool centering=true,
 1.28131 +                                    const int render_static=4, const int render_motion=1,
 1.28132 +                                    const bool double_sided=false, const float focale=500,
 1.28133 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28134 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28135 +      return display_object3d(title,points,primitives,CImgList<T>(),centering,
 1.28136 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28137 +                              display_axes,pose_matrix);
 1.28138 +    }
 1.28139 +
 1.28140 +    //! High-level interface for displaying a 3d object.
 1.28141 +    template<typename tp>
 1.28142 +    const CImg<T>& display_object3d(CImgDisplay &disp,
 1.28143 +                                    const tp& points,
 1.28144 +                                    const bool centering=true,
 1.28145 +                                    const int render_static=4, const int render_motion=1,
 1.28146 +                                    const bool double_sided=false, const float focale=500,
 1.28147 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28148 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28149 +      return display_object3d(disp,points,CImgList<uintT>(),centering,
 1.28150 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28151 +                              display_axes,pose_matrix);
 1.28152 +    }
 1.28153 +
 1.28154 +    //! High-level interface for displaying a 3d object.
 1.28155 +    template<typename tp>
 1.28156 +    const CImg<T>& display_object3d(const char *const title,
 1.28157 +                                    const tp& points,
 1.28158 +                                    const bool centering=true,
 1.28159 +                                    const int render_static=4, const int render_motion=1,
 1.28160 +                                    const bool double_sided=false, const float focale=500,
 1.28161 +                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 1.28162 +                                    const bool display_axes=true, float *const pose_matrix=0) const {
 1.28163 +      return display_object3d(title,points,CImgList<uintT>(),centering,
 1.28164 +                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28165 +                              display_axes,pose_matrix);
 1.28166 +    }
 1.28167 +
 1.28168 +    T _display_object3d_at2(const int i, const int j) const {
 1.28169 +      return atXY(i,j,0,0,0);
 1.28170 +    }
 1.28171 +
 1.28172 +    template<typename tp, typename tf, typename tc, typename to>
 1.28173 +    const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
 1.28174 +                                     const tp& points, const unsigned int Npoints,
 1.28175 +                                     const CImgList<tf>& primitives,
 1.28176 +                                     const CImgList<tc>& colors, const to& opacities,
 1.28177 +                                     const bool centering,
 1.28178 +                                     const int render_static, const int render_motion,
 1.28179 +                                     const bool double_sided, const float focale,
 1.28180 +                                     const float specular_light, const float specular_shine,
 1.28181 +                                     const bool display_axes, float *const pose_matrix) const {
 1.28182 +
 1.28183 +      // Check input arguments
 1.28184 +      if (!points || !Npoints)
 1.28185 +        throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
 1.28186 +                                    pixel_type());
 1.28187 +      if (is_empty()) {
 1.28188 +        if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
 1.28189 +                    _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
 1.28190 +                                     render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28191 +                                     display_axes,pose_matrix);
 1.28192 +        else return CImg<T>(cimg_fitscreen(640,480,1),1,colors[0].size(),0).
 1.28193 +               _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
 1.28194 +                                 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28195 +                                 display_axes,pose_matrix);
 1.28196 +      }
 1.28197 +      if (!primitives) {
 1.28198 +        CImgList<tf> nprimitives(Npoints,1,1,1,1);
 1.28199 +        cimglist_for(nprimitives,l) nprimitives(l,0) = l;
 1.28200 +        return _display_object3d(disp,title,points,Npoints,nprimitives,colors,opacities,
 1.28201 +                                 centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
 1.28202 +                                 display_axes,pose_matrix);
 1.28203 +      }
 1.28204 +      if (!disp) {
 1.28205 +        char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
 1.28206 +        disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
 1.28207 +      }
 1.28208 +
 1.28209 +      CImgList<tc> _colors;
 1.28210 +      if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
 1.28211 +      const CImgList<tc> &ncolors = colors?colors:_colors;
 1.28212 +
 1.28213 +      // Init 3D objects and compute object statistics
 1.28214 +      CImg<floatT>
 1.28215 +        pose, rot_mat, zbuffer,
 1.28216 +        centered_points = centering?CImg<floatT>(Npoints,3):CImg<floatT>(),
 1.28217 +        rotated_points(Npoints,3),
 1.28218 +        bbox_points, rotated_bbox_points,
 1.28219 +        axes_points, rotated_axes_points,
 1.28220 +        bbox_opacities, axes_opacities;
 1.28221 +      CImgList<uintT> bbox_primitives, axes_primitives;
 1.28222 +      CImgList<T> bbox_colors, bbox_colors2, axes_colors;
 1.28223 +      float dx = 0, dy = 0, dz = 0, ratio = 1;
 1.28224 +
 1.28225 +      T minval = (T)0, maxval = (T)255;
 1.28226 +      if (disp.normalization && colors) {
 1.28227 +        minval = colors.minmax(maxval);
 1.28228 +        if (minval==maxval) { minval = (T)0; maxval = (T)255; }
 1.28229 +      }
 1.28230 +      const float meanval = (float)mean();
 1.28231 +      bool color_model = true;
 1.28232 +      if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
 1.28233 +      const CImg<T>
 1.28234 +        background_color(1,1,1,dim,color_model?minval:maxval),
 1.28235 +        foreground_color(1,1,1,dim,color_model?maxval:minval);
 1.28236 +
 1.28237 +      float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
 1.28238 +      for (unsigned int i = 0; i<Npoints; ++i) {
 1.28239 +        const float
 1.28240 +          x = points._display_object3d_at2(i,0),
 1.28241 +          y = points._display_object3d_at2(i,1),
 1.28242 +          z = points._display_object3d_at2(i,2);
 1.28243 +        if (x<xm) xm = x;
 1.28244 +        if (x>xM) xM = x;
 1.28245 +        if (y<ym) ym = y;
 1.28246 +        if (y>yM) yM = y;
 1.28247 +        if (z<zm) zm = z;
 1.28248 +        if (z>zM) zM = z;
 1.28249 +      }
 1.28250 +      const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
 1.28251 +
 1.28252 +      if (display_axes) {
 1.28253 +        rotated_axes_points = axes_points.assign(7,3,1,1,
 1.28254 +                                                 0,20,0,0,22,-6,-6,
 1.28255 +                                                 0,0,20,0,-6,22,-6,
 1.28256 +                                                 0,0,0,20,0,0,22);
 1.28257 +        axes_opacities.assign(3,1,1,1,1);
 1.28258 +        axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
 1.28259 +        axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
 1.28260 +      }
 1.28261 +
 1.28262 +      // Begin user interaction loop
 1.28263 +      CImg<T> visu0(*this), visu;
 1.28264 +      bool init = true, clicked = false, redraw = true;
 1.28265 +      unsigned int key = 0;
 1.28266 +      int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
 1.28267 +      disp.show().flush();
 1.28268 +
 1.28269 +      while (!disp.is_closed && !key) {
 1.28270 +
 1.28271 +        // Init object position and scale if necessary
 1.28272 +        if (init) {
 1.28273 +          ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
 1.28274 +          dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
 1.28275 +          if (centering) {
 1.28276 +            cimg_forX(centered_points,l) {
 1.28277 +              centered_points(l,0) = (float)((points(l,0) - dx)*ratio);
 1.28278 +              centered_points(l,1) = (float)((points(l,1) - dy)*ratio);
 1.28279 +              centered_points(l,2) = (float)((points(l,2) - dz)*ratio);
 1.28280 +            }
 1.28281 +          }
 1.28282 +
 1.28283 +          if (render_static<0 || render_motion<0) {
 1.28284 +            rotated_bbox_points = bbox_points.assign(8,3,1,1,
 1.28285 +                                                     xm,xM,xM,xm,xm,xM,xM,xm,
 1.28286 +                                                     ym,ym,yM,yM,ym,ym,yM,yM,
 1.28287 +                                                     zm,zm,zm,zm,zM,zM,zM,zM);
 1.28288 +            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);
 1.28289 +            bbox_colors.assign(6,dim,1,1,1,background_color[0]);
 1.28290 +            bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
 1.28291 +            bbox_opacities.assign(bbox_colors.size,1,1,1,0.3f);
 1.28292 +          }
 1.28293 +
 1.28294 +          if (!pose) {
 1.28295 +            if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
 1.28296 +            else pose = CImg<floatT>::identity_matrix(4);
 1.28297 +          }
 1.28298 +          init = false;
 1.28299 +          redraw = true;
 1.28300 +        }
 1.28301 +
 1.28302 +        // Rotate and Draw 3D object
 1.28303 +        if (redraw) {
 1.28304 +          const float
 1.28305 +            r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
 1.28306 +            r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
 1.28307 +            r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
 1.28308 +          if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
 1.28309 +            if (centering) cimg_forX(centered_points,l) {
 1.28310 +                const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2);
 1.28311 +                rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
 1.28312 +                rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
 1.28313 +                rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
 1.28314 +              } else for (unsigned int l = 0; l<Npoints; ++l) {
 1.28315 +                const float
 1.28316 +                  x = (float)points._display_object3d_at2(l,0),
 1.28317 +                  y = (float)points._display_object3d_at2(l,1),
 1.28318 +                  z = (float)points._display_object3d_at2(l,2);
 1.28319 +                rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
 1.28320 +                rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
 1.28321 +                rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
 1.28322 +              }
 1.28323 +          } else {
 1.28324 +            if (!centering) cimg_forX(bbox_points,l) {
 1.28325 +                const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2);
 1.28326 +                rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
 1.28327 +                rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
 1.28328 +                rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
 1.28329 +              } else cimg_forX(bbox_points,l) {
 1.28330 +                const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio;
 1.28331 +                rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
 1.28332 +                rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
 1.28333 +                rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
 1.28334 +              }
 1.28335 +          }
 1.28336 +
 1.28337 +          // Draw object
 1.28338 +          visu = visu0;
 1.28339 +          if ((clicked && render_motion<0) || (!clicked && render_static<0))
 1.28340 +            visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
 1.28341 +              draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors2,1,false,focale);
 1.28342 +          else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
 1.28343 +                                  rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 1.28344 +                                  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 1.28345 +                                  (!clicked && render_static>0)?zbuffer.fill(0).ptr():0);
 1.28346 +
 1.28347 +          // Draw axes
 1.28348 +          if (display_axes) {
 1.28349 +            const float Xaxes = 25, Yaxes = visu.height - 35.0f;
 1.28350 +            cimg_forX(axes_points,l) {
 1.28351 +              const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2);
 1.28352 +              rotated_axes_points(l,0) = r00*x + r10*y + r20*z;
 1.28353 +              rotated_axes_points(l,1) = r01*x + r11*y + r21*z;
 1.28354 +              rotated_axes_points(l,2) = r02*x + r12*y + r22*z;
 1.28355 +            }
 1.28356 +            axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f;
 1.28357 +            axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
 1.28358 +            axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
 1.28359 +            visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale).
 1.28360 +              draw_text((int)(Xaxes+rotated_axes_points(4,0)),
 1.28361 +                        (int)(Yaxes+rotated_axes_points(4,1)),
 1.28362 +                        "X",axes_colors[0].data,0,axes_opacities(0,0),11).
 1.28363 +              draw_text((int)(Xaxes+rotated_axes_points(5,0)),
 1.28364 +                        (int)(Yaxes+rotated_axes_points(5,1)),
 1.28365 +                        "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
 1.28366 +              draw_text((int)(Xaxes+rotated_axes_points(6,0)),
 1.28367 +                        (int)(Yaxes+rotated_axes_points(6,1)),
 1.28368 +                        "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
 1.28369 +          }
 1.28370 +          visu.display(disp);
 1.28371 +          if (!clicked || render_motion==render_static) redraw = false;
 1.28372 +        }
 1.28373 +
 1.28374 +        // Handle user interaction
 1.28375 +        disp.wait();
 1.28376 +        if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
 1.28377 +          redraw = true;
 1.28378 +          if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
 1.28379 +          else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
 1.28380 +          if (disp.button&1) {
 1.28381 +            const float
 1.28382 +              R = 0.45f*cimg::min(disp.width,disp.height),
 1.28383 +              R2 = R*R,
 1.28384 +              u0 = (float)(x0-disp.dimx()/2),
 1.28385 +              v0 = (float)(y0-disp.dimy()/2),
 1.28386 +              u1 = (float)(x1-disp.dimx()/2),
 1.28387 +              v1 = (float)(y1-disp.dimy()/2),
 1.28388 +              n0 = (float)cimg_std::sqrt(u0*u0+v0*v0),
 1.28389 +              n1 = (float)cimg_std::sqrt(u1*u1+v1*v1),
 1.28390 +              nu0 = n0>R?(u0*R/n0):u0,
 1.28391 +              nv0 = n0>R?(v0*R/n0):v0,
 1.28392 +              nw0 = (float)cimg_std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
 1.28393 +              nu1 = n1>R?(u1*R/n1):u1,
 1.28394 +              nv1 = n1>R?(v1*R/n1):v1,
 1.28395 +              nw1 = (float)cimg_std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
 1.28396 +              u = nv0*nw1-nw0*nv1,
 1.28397 +              v = nw0*nu1-nu0*nw1,
 1.28398 +              w = nv0*nu1-nu0*nv1,
 1.28399 +              n = (float)cimg_std::sqrt(u*u+v*v+w*w),
 1.28400 +              alpha = (float)cimg_std::asin(n/R2);
 1.28401 +            rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
 1.28402 +            rot_mat *= pose.get_crop(0,0,2,2);
 1.28403 +            pose.draw_image(rot_mat);
 1.28404 +            x0=x1; y0=y1;
 1.28405 +          }
 1.28406 +          if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
 1.28407 +          if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
 1.28408 +          if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
 1.28409 +          if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
 1.28410 +        } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
 1.28411 +
 1.28412 +        switch (key = disp.key) {
 1.28413 +        case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
 1.28414 +        case cimg::keyD: if (disp.is_keyCTRLLEFT) {
 1.28415 +          disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 1.28416 +                                     CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 1.28417 +          disp.key = key = 0;
 1.28418 +        } break;
 1.28419 +        case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 1.28420 +          disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 1.28421 +          disp.key = key = 0;
 1.28422 +        } break;
 1.28423 +        case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 1.28424 +          disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
 1.28425 +          disp.key = key = 0;
 1.28426 +        } break;
 1.28427 +        case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 1.28428 +          disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 1.28429 +          disp.key = key = 0;
 1.28430 +        } break;
 1.28431 +        case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
 1.28432 +          if (zbuffer) zbuffer.assign();
 1.28433 +          else zbuffer.assign(disp.width,disp.height);
 1.28434 +          disp.key = key = 0; redraw = true;
 1.28435 +        } break;
 1.28436 +        case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
 1.28437 +          static unsigned int snap_number = 0;
 1.28438 +          char filename[32] = { 0 };
 1.28439 +          cimg_std::FILE *file;
 1.28440 +          do {
 1.28441 +            cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 1.28442 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.28443 +          } while (file);
 1.28444 +          (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
 1.28445 +          visu.save(filename);
 1.28446 +          visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 1.28447 +          disp.key = key = 0;
 1.28448 +        } break;
 1.28449 +        case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
 1.28450 +          static unsigned int snap_number = 0;
 1.28451 +          char filename[32] = { 0 };
 1.28452 +          cimg_std::FILE *file;
 1.28453 +          do {
 1.28454 +            cimg_std::sprintf(filename,"CImg_%.4u.off",snap_number++);
 1.28455 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.28456 +          } while (file);
 1.28457 +          visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
 1.28458 +          points.save_off(filename,primitives,ncolors);
 1.28459 +          visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 1.28460 +          disp.key = key = 0;
 1.28461 +        } break;
 1.28462 +#ifdef cimg_use_board
 1.28463 +        case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
 1.28464 +          static unsigned int snap_number = 0;
 1.28465 +          char filename[32] = { 0 };
 1.28466 +          cimg_std::FILE *file;
 1.28467 +          do {
 1.28468 +            cimg_std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
 1.28469 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.28470 +          } while (file);
 1.28471 +          visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
 1.28472 +          BoardLib::Board board;
 1.28473 +          (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 1.28474 +                                rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 1.28475 +                                double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 1.28476 +                                zbuffer.fill(0).ptr());
 1.28477 +          board.saveEPS(filename);
 1.28478 +          visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 1.28479 +          disp.key = key = 0;
 1.28480 +        } break;
 1.28481 +        case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
 1.28482 +          static unsigned int snap_number = 0;
 1.28483 +          char filename[32] = { 0 };
 1.28484 +          cimg_std::FILE *file;
 1.28485 +          do {
 1.28486 +            cimg_std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
 1.28487 +            if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.28488 +          } while (file);
 1.28489 +          visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
 1.28490 +          BoardLib::Board board;
 1.28491 +          (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 1.28492 +                                rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 1.28493 +                                double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
 1.28494 +                                zbuffer.fill(0).ptr());
 1.28495 +          board.saveSVG(filename);
 1.28496 +          visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
 1.28497 +          disp.key = key = 0;
 1.28498 +        } break;
 1.28499 +#endif
 1.28500 +        }
 1.28501 +        if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
 1.28502 +      }
 1.28503 +      if (pose_matrix) cimg_std::memcpy(pose_matrix,pose.data,16*sizeof(float));
 1.28504 +      disp.button = 0;
 1.28505 +      disp.key = key;
 1.28506 +      return *this;
 1.28507 +    }
 1.28508 +
 1.28509 +    //! High-level interface for displaying a graph.
 1.28510 +    const CImg<T>& display_graph(CImgDisplay &disp,
 1.28511 +                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
 1.28512 +                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
 1.28513 +                                 const char *const labely=0, const double ymin=0, const double ymax=0) const {
 1.28514 +      if (is_empty())
 1.28515 +        throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.28516 +                                    pixel_type(),width,height,depth,dim,data);
 1.28517 +      const unsigned int siz = width*height*depth, onormalization = disp.normalization;
 1.28518 +      if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
 1.28519 +      disp.show().flush().normalization = 0;
 1.28520 +      double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
 1.28521 +      if (nxmin==nxmax) { nxmin = 0; nxmax = siz - 1.0; }
 1.28522 +      int x0 = 0, x1 = size()/dimv()-1, key = 0;
 1.28523 +
 1.28524 +      for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
 1.28525 +        if (reset_view) { x0 = 0; x1 = size()/dimv()-1; y0 = ymin; y1 = ymax; reset_view = false; }
 1.28526 +        CImg<T> zoom(x1-x0+1,1,1,dimv());
 1.28527 +        cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
 1.28528 +
 1.28529 +        if (y0==y1) y0 = zoom.minmax(y1);
 1.28530 +        if (y0==y1) { --y0; ++y1; }
 1.28531 +        const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
 1.28532 +                                                           labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + x1*(nxmax-nxmin)/siz,
 1.28533 +                                                           labely,y0,y1);
 1.28534 +
 1.28535 +        const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
 1.28536 +        if (selection[0]>=0 && selection[2]>=0) {
 1.28537 +          x1 = x0 + selection[2];
 1.28538 +          x0 += selection[0];
 1.28539 +          if (x0==x1) reset_view = true;
 1.28540 +          if (selection[1]>=0 && selection[3]>=0) {
 1.28541 +            y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
 1.28542 +            y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
 1.28543 +          }
 1.28544 +        } else {
 1.28545 +          bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
 1.28546 +          switch (key = disp.key) {
 1.28547 +          case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
 1.28548 +          case cimg::keyPADADD : go_in = true; key = 0; break;
 1.28549 +          case cimg::keyPADSUB : go_out = true; key = 0; break;
 1.28550 +          case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
 1.28551 +          case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
 1.28552 +          case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
 1.28553 +          case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
 1.28554 +          case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
 1.28555 +          case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
 1.28556 +          case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
 1.28557 +          case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
 1.28558 +          }
 1.28559 +          if (disp.wheel) go_out = !(go_in = disp.wheel>0);
 1.28560 +
 1.28561 +          if (go_in) {
 1.28562 +            const int
 1.28563 +              xsiz = x1 - x0,
 1.28564 +              mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
 1.28565 +              cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
 1.28566 +            if (x1-x0>4) {
 1.28567 +              x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
 1.28568 +              if (disp.is_keyCTRLLEFT) {
 1.28569 +                const double
 1.28570 +                  ysiz = y1 - y0,
 1.28571 +                  my = (mouse_y-16)*ysiz/(disp.dimy()-32),
 1.28572 +                  cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
 1.28573 +                y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
 1.28574 +              } else y0 = y1 = 0;
 1.28575 +            }
 1.28576 +          }
 1.28577 +          if (go_out) {
 1.28578 +            const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
 1.28579 +            x0-=ndeltax; x1+=ndeltax;
 1.28580 +            if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
 1.28581 +            if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
 1.28582 +            if (disp.is_keyCTRLLEFT) {
 1.28583 +              const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
 1.28584 +              y0-=ndeltay; y1+=ndeltay;
 1.28585 +            }
 1.28586 +          }
 1.28587 +          if (go_left) {
 1.28588 +            const int delta = (x1-x0)/5, ndelta = delta?delta:1;
 1.28589 +            if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
 1.28590 +            else { x1-=x0; x0 = 0; }
 1.28591 +            go_left = false;
 1.28592 +          }
 1.28593 +          if (go_right) {
 1.28594 +            const int delta = (x1-x0)/5, ndelta = delta?delta:1;
 1.28595 +            if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
 1.28596 +            else { x0+=(siz-1-x1); x1 = siz-1; }
 1.28597 +            go_right = false;
 1.28598 +          }
 1.28599 +          if (go_up) {
 1.28600 +            const double delta = (y1-y0)/10, ndelta = delta?delta:1;
 1.28601 +            y0+=ndelta; y1+=ndelta;
 1.28602 +            go_up = false;
 1.28603 +          }
 1.28604 +          if (go_down) {
 1.28605 +            const double delta = (y1-y0)/10, ndelta = delta?delta:1;
 1.28606 +            y0-=ndelta; y1-=ndelta;
 1.28607 +            go_down = false;
 1.28608 +          }
 1.28609 +        }
 1.28610 +      }
 1.28611 +      disp.normalization = onormalization;
 1.28612 +      return *this;
 1.28613 +    }
 1.28614 +
 1.28615 +    //! High-level interface for displaying a graph.
 1.28616 +    const CImg<T>& display_graph(const char *const title=0,
 1.28617 +                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
 1.28618 +                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
 1.28619 +                                 const char *const labely=0, const double ymin=0, const double ymax=0) const {
 1.28620 +      if (is_empty())
 1.28621 +        throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.28622 +                                    pixel_type(),width,height,depth,dim,data);
 1.28623 +      char ntitle[64] = { 0 }; if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
 1.28624 +      CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
 1.28625 +      return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
 1.28626 +    }
 1.28627 +
 1.28628 +    //! Select sub-graph in a graph.
 1.28629 +    CImg<intT> get_select_graph(CImgDisplay &disp,
 1.28630 +                                const unsigned int plot_type=1, const unsigned int vertex_type=1,
 1.28631 +                                const char *const labelx=0, const double xmin=0, const double xmax=0,
 1.28632 +                                const char *const labely=0, const double ymin=0, const double ymax=0) const {
 1.28633 +      if (is_empty())
 1.28634 +        throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
 1.28635 +                                    pixel_type(),width,height,depth,dim,data);
 1.28636 +      const unsigned int siz = width*height*depth, onormalization = disp.normalization;
 1.28637 +      if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
 1.28638 +      disp.show().key = disp.normalization = disp.button = disp.wheel = 0;  // Must keep 'key' field unchanged.
 1.28639 +      double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
 1.28640 +      if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
 1.28641 +      if (nymin==nymax) { --nymin; ++nymax; }
 1.28642 +      if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
 1.28643 +
 1.28644 +      const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
 1.28645 +      const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
 1.28646 +      static unsigned int odimv = 0;
 1.28647 +      static CImg<ucharT> palette;
 1.28648 +      if (odimv!=dim) {
 1.28649 +        odimv = dim;
 1.28650 +        palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
 1.28651 +        if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
 1.28652 +        else {
 1.28653 +          palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
 1.28654 +          if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
 1.28655 +          if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
 1.28656 +        }
 1.28657 +      }
 1.28658 +
 1.28659 +      CImg<ucharT> visu0, visu, graph, text, axes;
 1.28660 +      const unsigned int whz = width*height*depth;
 1.28661 +      int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
 1.28662 +      char message[1024] = { 0 };
 1.28663 +      unsigned int okey = 0, obutton = 0;
 1.28664 +      CImg_3x3(I,unsigned char);
 1.28665 +
 1.28666 +      for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
 1.28667 +        const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
 1.28668 +        const unsigned int key = disp.key, button = disp.button;
 1.28669 +
 1.28670 +        // Generate graph representation.
 1.28671 +        if (!visu0) {
 1.28672 +          visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
 1.28673 +          const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
 1.28674 +          if (gdimx>0 && gdimy>0) {
 1.28675 +            graph.assign(gdimx,gdimy,1,3,255);
 1.28676 +            graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
 1.28677 +            cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
 1.28678 +                                                plot_type,vertex_type,nymax,nymin);
 1.28679 +
 1.28680 +            axes.assign(gdimx,gdimy,1,1,0);
 1.28681 +            const float
 1.28682 +              dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
 1.28683 +              px = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0),
 1.28684 +              py = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0);
 1.28685 +            const CImg<Tdouble>
 1.28686 +              seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
 1.28687 +              seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
 1.28688 +            axes.draw_axis(seqx,seqy,white);
 1.28689 +            if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
 1.28690 +            if (nymax<0) axes.draw_axis(seqx,0,gray);
 1.28691 +            if (nxmin>0) axes.draw_axis(0,seqy,gray);
 1.28692 +            if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
 1.28693 +
 1.28694 +            cimg_for3x3(axes,x,y,0,0,I)
 1.28695 +              if (Icc) {
 1.28696 +                if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
 1.28697 +                else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
 1.28698 +              }
 1.28699 +              else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
 1.28700 +
 1.28701 +            visu0.draw_image(16,16,graph);
 1.28702 +            visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
 1.28703 +              draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
 1.28704 +          } else graph.assign();
 1.28705 +          text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
 1.28706 +          visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
 1.28707 +          text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
 1.28708 +          visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
 1.28709 +          visu.assign();
 1.28710 +        }
 1.28711 +
 1.28712 +        // Generate and display current view.
 1.28713 +        if (!visu) {
 1.28714 +          visu.assign(visu0);
 1.28715 +          if (graph && x0>=0 && x1>=0) {
 1.28716 +            const int
 1.28717 +              nx0 = x0<=x1?x0:x1,
 1.28718 +              nx1 = x0<=x1?x1:x0,
 1.28719 +              ny0 = y0<=y1?y0:y1,
 1.28720 +              ny1 = y0<=y1?y1:y0,
 1.28721 +              sx0 = 16 + nx0*(visu.dimx()-32)/whz,
 1.28722 +              sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
 1.28723 +              sy0 = 16 + ny0,
 1.28724 +              sy1 = 16 + ny1;
 1.28725 +
 1.28726 +            if (y0>=0 && y1>=0)
 1.28727 +              visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
 1.28728 +            else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
 1.28729 +                   draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
 1.28730 +                   draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
 1.28731 +          }
 1.28732 +          if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
 1.28733 +            if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
 1.28734 +            const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
 1.28735 +            const double cx = nxmin + x*(nxmax-nxmin)/whz;
 1.28736 +            if (dim>=7)
 1.28737 +              cimg_std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
 1.28738 +                           (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
 1.28739 +                           (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
 1.28740 +            else {
 1.28741 +              cimg_std::sprintf(message,"Value[%g] = ( ",cx);
 1.28742 +              cimg_forV(*this,k) cimg_std::sprintf(message+cimg::strlen(message),"%g ",(double)(*this)(x,0,0,k));
 1.28743 +              cimg_std::sprintf(message+cimg::strlen(message),")");
 1.28744 +            }
 1.28745 +            if (x0>=0 && x1>=0) {
 1.28746 +              const int
 1.28747 +                 nx0 = x0<=x1?x0:x1,
 1.28748 +                 nx1 = x0<=x1?x1:x0,
 1.28749 +                 ny0 = y0<=y1?y0:y1,
 1.28750 +                 ny1 = y0<=y1?y1:y0;
 1.28751 +              const double
 1.28752 +                 cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
 1.28753 +                 cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
 1.28754 +                 cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
 1.28755 +                 cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
 1.28756 +              if (y0>=0 && y1>=0)
 1.28757 +                cimg_std::sprintf(message+cimg::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
 1.28758 +              else
 1.28759 +                cimg_std::sprintf(message+cimg::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
 1.28760 +            }
 1.28761 +            text.assign().draw_text(0,0,message,white,ngray,1);
 1.28762 +            visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
 1.28763 +          }
 1.28764 +          visu.display(disp);
 1.28765 +        }
 1.28766 +
 1.28767 +        // Test keys.
 1.28768 +        switch (okey = key) {
 1.28769 +        case cimg::keyCTRLLEFT : okey = 0; break;
 1.28770 +        case cimg::keyD : if (disp.is_keyCTRLLEFT) {
 1.28771 +          disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
 1.28772 +                                     CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
 1.28773 +          disp.key = okey = 0;
 1.28774 +        } break;
 1.28775 +        case cimg::keyC : if (disp.is_keyCTRLLEFT) {
 1.28776 +          disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 1.28777 +          disp.key = okey = 0;
 1.28778 +        } break;
 1.28779 +        case cimg::keyR : if (disp.is_keyCTRLLEFT) {
 1.28780 +          disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
 1.28781 +          disp.key = okey = 0;
 1.28782 +        } break;
 1.28783 +        case cimg::keyF : if (disp.is_keyCTRLLEFT) {
 1.28784 +          disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 1.28785 +          disp.key = okey = 0;
 1.28786 +        } break;
 1.28787 +        case cimg::keyS : if (disp.is_keyCTRLLEFT) {
 1.28788 +          static unsigned int snap_number = 0;
 1.28789 +          if (visu || visu0) {
 1.28790 +            CImg<ucharT> &screen = visu?visu:visu0;
 1.28791 +            char filename[32] = { 0 };
 1.28792 +            cimg_std::FILE *file;
 1.28793 +            do {
 1.28794 +              cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 1.28795 +              if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
 1.28796 +            } while (file);
 1.28797 +            (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
 1.28798 +            screen.save(filename);
 1.28799 +            screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
 1.28800 +          }
 1.28801 +          disp.key = okey = 0;
 1.28802 +        } break;
 1.28803 +        }
 1.28804 +
 1.28805 +        // Handle mouse motion and mouse buttons
 1.28806 +        if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
 1.28807 +          visu.assign();
 1.28808 +          if (disp.mouse_x>=0 && disp.mouse_y>=0) {
 1.28809 +            const int
 1.28810 +              mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
 1.28811 +              cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
 1.28812 +              my = mouse_y-16,
 1.28813 +              cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
 1.28814 +            if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
 1.28815 +            else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
 1.28816 +            else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
 1.28817 +          } else if (!button && obutton) selected = true;
 1.28818 +          obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
 1.28819 +        }
 1.28820 +        if (disp.is_resized) { disp.resize(false); visu0.assign(); }
 1.28821 +        if (visu && visu0) disp.wait();
 1.28822 +      }
 1.28823 +      disp.normalization = onormalization;
 1.28824 +      if (x1<x0) cimg::swap(x0,x1);
 1.28825 +      if (y1<y0) cimg::swap(y0,y1);
 1.28826 +      disp.key = okey;
 1.28827 +      return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
 1.28828 +    }
 1.28829 +
 1.28830 +    //@}
 1.28831 +    //---------------------------
 1.28832 +    //
 1.28833 +    //! \name Image File Loading
 1.28834 +    //@{
 1.28835 +    //---------------------------
 1.28836 +
 1.28837 +    //! Load an image from a file.
 1.28838 +    /**
 1.28839 +       \param filename is the name of the image file to load.
 1.28840 +       \note The extension of \c filename defines the file format. If no filename
 1.28841 +       extension is provided, CImg<T>::get_load() will try to load a .cimg file.
 1.28842 +    **/
 1.28843 +    CImg<T>& load(const char *const filename) {
 1.28844 +      if (!filename)
 1.28845 +        throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
 1.28846 +                                    pixel_type());
 1.28847 +      const char *ext = cimg::split_filename(filename);
 1.28848 +      const unsigned int odebug = cimg::exception_mode();
 1.28849 +      cimg::exception_mode() = 0;
 1.28850 +      assign();
 1.28851 +      try {
 1.28852 +#ifdef cimg_load_plugin
 1.28853 +        cimg_load_plugin(filename);
 1.28854 +#endif
 1.28855 +#ifdef cimg_load_plugin1
 1.28856 +        cimg_load_plugin1(filename);
 1.28857 +#endif
 1.28858 +#ifdef cimg_load_plugin2
 1.28859 +        cimg_load_plugin2(filename);
 1.28860 +#endif
 1.28861 +#ifdef cimg_load_plugin3
 1.28862 +        cimg_load_plugin3(filename);
 1.28863 +#endif
 1.28864 +#ifdef cimg_load_plugin4
 1.28865 +        cimg_load_plugin4(filename);
 1.28866 +#endif
 1.28867 +#ifdef cimg_load_plugin5
 1.28868 +        cimg_load_plugin5(filename);
 1.28869 +#endif
 1.28870 +#ifdef cimg_load_plugin6
 1.28871 +        cimg_load_plugin6(filename);
 1.28872 +#endif
 1.28873 +#ifdef cimg_load_plugin7
 1.28874 +        cimg_load_plugin7(filename);
 1.28875 +#endif
 1.28876 +#ifdef cimg_load_plugin8
 1.28877 +        cimg_load_plugin8(filename);
 1.28878 +#endif
 1.28879 +        // ASCII formats
 1.28880 +        if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
 1.28881 +        if (!cimg::strcasecmp(ext,"dlm") ||
 1.28882 +            !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
 1.28883 +
 1.28884 +        // 2D binary formats
 1.28885 +        if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
 1.28886 +        if (!cimg::strcasecmp(ext,"jpg") ||
 1.28887 +            !cimg::strcasecmp(ext,"jpeg") ||
 1.28888 +            !cimg::strcasecmp(ext,"jpe") ||
 1.28889 +            !cimg::strcasecmp(ext,"jfif") ||
 1.28890 +            !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
 1.28891 +        if (!cimg::strcasecmp(ext,"png")) load_png(filename);
 1.28892 +        if (!cimg::strcasecmp(ext,"ppm") ||
 1.28893 +            !cimg::strcasecmp(ext,"pgm") ||
 1.28894 +            !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
 1.28895 +        if (!cimg::strcasecmp(ext,"tif") ||
 1.28896 +            !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
 1.28897 +        if (!cimg::strcasecmp(ext,"cr2") ||
 1.28898 +            !cimg::strcasecmp(ext,"crw") ||
 1.28899 +            !cimg::strcasecmp(ext,"dcr") ||
 1.28900 +            !cimg::strcasecmp(ext,"mrw") ||
 1.28901 +            !cimg::strcasecmp(ext,"nef") ||
 1.28902 +            !cimg::strcasecmp(ext,"orf") ||
 1.28903 +            !cimg::strcasecmp(ext,"pix") ||
 1.28904 +            !cimg::strcasecmp(ext,"ptx") ||
 1.28905 +            !cimg::strcasecmp(ext,"raf") ||
 1.28906 +            !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
 1.28907 +
 1.28908 +        // 3D binary formats
 1.28909 +        if (!cimg::strcasecmp(ext,"dcm") ||
 1.28910 +            !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
 1.28911 +        if (!cimg::strcasecmp(ext,"hdr") ||
 1.28912 +            !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
 1.28913 +        if (!cimg::strcasecmp(ext,"par") ||
 1.28914 +            !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
 1.28915 +        if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
 1.28916 +        if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
 1.28917 +        if (!cimg::strcasecmp(ext,"cimg") ||
 1.28918 +            !cimg::strcasecmp(ext,"cimgz") ||
 1.28919 +            *ext=='\0')  return load_cimg(filename);
 1.28920 +
 1.28921 +        // Archive files
 1.28922 +        if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
 1.28923 +
 1.28924 +        // Image sequences
 1.28925 +        if (!cimg::strcasecmp(ext,"avi") ||
 1.28926 +            !cimg::strcasecmp(ext,"mov") ||
 1.28927 +            !cimg::strcasecmp(ext,"asf") ||
 1.28928 +            !cimg::strcasecmp(ext,"divx") ||
 1.28929 +            !cimg::strcasecmp(ext,"flv") ||
 1.28930 +            !cimg::strcasecmp(ext,"mpg") ||
 1.28931 +            !cimg::strcasecmp(ext,"m1v") ||
 1.28932 +            !cimg::strcasecmp(ext,"m2v") ||
 1.28933 +            !cimg::strcasecmp(ext,"m4v") ||
 1.28934 +            !cimg::strcasecmp(ext,"mjp") ||
 1.28935 +            !cimg::strcasecmp(ext,"mkv") ||
 1.28936 +            !cimg::strcasecmp(ext,"mpe") ||
 1.28937 +            !cimg::strcasecmp(ext,"movie") ||
 1.28938 +            !cimg::strcasecmp(ext,"ogm") ||
 1.28939 +            !cimg::strcasecmp(ext,"qt") ||
 1.28940 +            !cimg::strcasecmp(ext,"rm") ||
 1.28941 +            !cimg::strcasecmp(ext,"vob") ||
 1.28942 +            !cimg::strcasecmp(ext,"wmv") ||
 1.28943 +            !cimg::strcasecmp(ext,"xvid") ||
 1.28944 +            !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
 1.28945 +        if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
 1.28946 +      } catch (CImgException& e) {
 1.28947 +        if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
 1.28948 +          cimg::exception_mode() = odebug;
 1.28949 +          throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
 1.28950 +        } else try {
 1.28951 +          const char *const ftype = cimg::file_type(0,filename);
 1.28952 +          assign();
 1.28953 +          if (!cimg::strcmp(ftype,"pnm")) load_pnm(filename);
 1.28954 +          if (!cimg::strcmp(ftype,"bmp")) load_bmp(filename);
 1.28955 +          if (!cimg::strcmp(ftype,"jpeg")) load_jpeg(filename);
 1.28956 +          if (!cimg::strcmp(ftype,"pan")) load_pandore(filename);
 1.28957 +          if (!cimg::strcmp(ftype,"png")) load_png(filename);
 1.28958 +          if (!cimg::strcmp(ftype,"tiff")) load_tiff(filename);
 1.28959 +          if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
 1.28960 +        } catch (CImgException&) {
 1.28961 +          try {
 1.28962 +            load_other(filename);
 1.28963 +          } catch (CImgException&) {
 1.28964 +            assign();
 1.28965 +          }
 1.28966 +        }
 1.28967 +      }
 1.28968 +      cimg::exception_mode() = odebug;
 1.28969 +      if (is_empty())
 1.28970 +        throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
 1.28971 +      return *this;
 1.28972 +    }
 1.28973 +
 1.28974 +    static CImg<T> get_load(const char *const filename) {
 1.28975 +      return CImg<T>().load(filename);
 1.28976 +    }
 1.28977 +
 1.28978 +    //! Load an image from an ASCII file.
 1.28979 +    CImg<T>& load_ascii(const char *const filename) {
 1.28980 +      return _load_ascii(0,filename);
 1.28981 +    }
 1.28982 +
 1.28983 +    static CImg<T> get_load_ascii(const char *const filename) {
 1.28984 +      return CImg<T>().load_ascii(filename);
 1.28985 +    }
 1.28986 +
 1.28987 +    //! Load an image from an ASCII file.
 1.28988 +    CImg<T>& load_ascii(cimg_std::FILE *const file) {
 1.28989 +      return _load_ascii(file,0);
 1.28990 +    }
 1.28991 +
 1.28992 +    static CImg<T> get_load_ascii(cimg_std::FILE *const file) {
 1.28993 +      return CImg<T>().load_ascii(file);
 1.28994 +    }
 1.28995 +
 1.28996 +    CImg<T>& _load_ascii(cimg_std::FILE *const file, const char *const filename) {
 1.28997 +      if (!filename && !file)
 1.28998 +        throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
 1.28999 +                                    pixel_type());
 1.29000 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29001 +      char line[256] = { 0 };
 1.29002 +      int err = cimg_std::fscanf(nfile,"%*[^0-9]%255[^\n]",line);
 1.29003 +      unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
 1.29004 +      cimg_std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
 1.29005 +      err = cimg_std::fscanf(nfile,"%*[^0-9.+-]");
 1.29006 +      if (!dx || !dy || !dz || !dv) {
 1.29007 +        if (!file) cimg::fclose(nfile);
 1.29008 +        throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
 1.29009 +                              pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
 1.29010 +      }
 1.29011 +      assign(dx,dy,dz,dv);
 1.29012 +      const unsigned long siz = size();
 1.29013 +      double val;
 1.29014 +      T *ptr = data;
 1.29015 +      for (err = 1, off = 0; off<siz && err==1; ++off) {
 1.29016 +        err = cimg_std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
 1.29017 +        *(ptr++) = (T)val;
 1.29018 +      }
 1.29019 +      if (err!=1)
 1.29020 +        cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
 1.29021 +                   pixel_type(),filename?filename:"(FILE*)",off-1,siz);
 1.29022 +      if (!file) cimg::fclose(nfile);
 1.29023 +      return *this;
 1.29024 +    }
 1.29025 +
 1.29026 +    //! Load an image from a DLM file.
 1.29027 +    CImg<T>& load_dlm(const char *const filename) {
 1.29028 +      return _load_dlm(0,filename);
 1.29029 +    }
 1.29030 +
 1.29031 +    static CImg<T> get_load_dlm(const char *const filename) {
 1.29032 +      return CImg<T>().load_dlm(filename);
 1.29033 +    }
 1.29034 +
 1.29035 +    //! Load an image from a DLM file.
 1.29036 +    CImg<T>& load_dlm(cimg_std::FILE *const file) {
 1.29037 +      return _load_dlm(file,0);
 1.29038 +    }
 1.29039 +
 1.29040 +    static CImg<T> get_load_dlm(cimg_std::FILE *const file) {
 1.29041 +      return CImg<T>().load_dlm(file);
 1.29042 +    }
 1.29043 +
 1.29044 +    CImg<T>& _load_dlm(cimg_std::FILE *const file, const char *const filename) {
 1.29045 +      if (!filename && !file)
 1.29046 +        throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
 1.29047 +                                    pixel_type());
 1.29048 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
 1.29049 +      assign(256,256);
 1.29050 +      char c, delimiter[256] = { 0 }, tmp[256];
 1.29051 +      unsigned int cdx = 0, dx = 0, dy = 0;
 1.29052 +      int oerr = 0, err;
 1.29053 +      double val;
 1.29054 +      while ((err = cimg_std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
 1.29055 +        oerr = err;
 1.29056 +        if (err>0) (*this)(cdx++,dy) = (T)val;
 1.29057 +        if (cdx>=width) resize(width+256,1,1,1,0);
 1.29058 +        c = 0; if (!cimg_std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
 1.29059 +          dx = cimg::max(cdx,dx);
 1.29060 +          ++dy;
 1.29061 +          if (dy>=height) resize(width,height+256,1,1,0);
 1.29062 +          cdx = 0;
 1.29063 +        }
 1.29064 +      }
 1.29065 +      if (cdx && oerr==1) { dx=cdx; ++dy; }
 1.29066 +      if (!dx || !dy) {
 1.29067 +        if (!file) cimg::fclose(nfile);
 1.29068 +        throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file, specified image dimensions are (%u,%u).",
 1.29069 +                              pixel_type(),filename?filename:"(FILE*)",dx,dy);
 1.29070 +      }
 1.29071 +      resize(dx,dy,1,1,0);
 1.29072 +      if (!file) cimg::fclose(nfile);
 1.29073 +      return *this;
 1.29074 +    }
 1.29075 +
 1.29076 +    //! Load an image from a BMP file.
 1.29077 +    CImg<T>& load_bmp(const char *const filename) {
 1.29078 +      return _load_bmp(0,filename);
 1.29079 +    }
 1.29080 +
 1.29081 +    static CImg<T> get_load_bmp(const char *const filename) {
 1.29082 +      return CImg<T>().load_bmp(filename);
 1.29083 +    }
 1.29084 +
 1.29085 +    //! Load an image from a BMP file.
 1.29086 +    CImg<T>& load_bmp(cimg_std::FILE *const file) {
 1.29087 +      return _load_bmp(file,0);
 1.29088 +    }
 1.29089 +
 1.29090 +    static CImg<T> get_load_bmp(cimg_std::FILE *const file) {
 1.29091 +      return CImg<T>().load_bmp(file);
 1.29092 +    }
 1.29093 +
 1.29094 +    CImg<T>& _load_bmp(cimg_std::FILE *const file, const char *const filename) {
 1.29095 +      if (!filename && !file)
 1.29096 +        throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
 1.29097 +                                    pixel_type());
 1.29098 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29099 +      unsigned char header[64];
 1.29100 +      cimg::fread(header,54,nfile);
 1.29101 +      if (header[0]!='B' || header[1]!='M') {
 1.29102 +        if (!file) cimg::fclose(nfile);
 1.29103 +        throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
 1.29104 +                              pixel_type(),filename?filename:"(FILE*)");
 1.29105 +      }
 1.29106 +      assign();
 1.29107 +
 1.29108 +      // Read header and pixel buffer
 1.29109 +      int
 1.29110 +        file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
 1.29111 +        offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
 1.29112 +        dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
 1.29113 +        dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
 1.29114 +        compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
 1.29115 +        nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
 1.29116 +        bpp = header[0x1C] + (header[0x1D]<<8),
 1.29117 +        *palette = 0;
 1.29118 +      const int
 1.29119 +        dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
 1.29120 +        align = (4-dx_bytes%4)%4,
 1.29121 +        buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
 1.29122 +
 1.29123 +      if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
 1.29124 +      if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
 1.29125 +      const int xoffset = offset-54-4*nb_colors;
 1.29126 +      if (xoffset>0) cimg_std::fseek(nfile,xoffset,SEEK_CUR);
 1.29127 +      unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
 1.29128 +      cimg::fread(buffer,buf_size,nfile);
 1.29129 +      if (!file) cimg::fclose(nfile);
 1.29130 +
 1.29131 +      // Decompress buffer (if necessary)
 1.29132 +      if (compression) {
 1.29133 +        delete[] buffer;
 1.29134 +        if (file) {
 1.29135 +          throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
 1.29136 +                                pixel_type());
 1.29137 +        } else return load_other(filename);
 1.29138 +      }
 1.29139 +
 1.29140 +      // Read pixel data
 1.29141 +      assign(dx,cimg::abs(dy),1,3);
 1.29142 +      switch (bpp) {
 1.29143 +      case 1 : { // Monochrome
 1.29144 +        for (int y=height-1; y>=0; --y) {
 1.29145 +          unsigned char mask = 0x80, val = 0;
 1.29146 +          cimg_forX(*this,x) {
 1.29147 +            if (mask==0x80) val = *(ptrs++);
 1.29148 +            const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
 1.29149 +            (*this)(x,y,2) = (T)*(col++);
 1.29150 +            (*this)(x,y,1) = (T)*(col++);
 1.29151 +            (*this)(x,y,0) = (T)*(col++);
 1.29152 +            mask = cimg::ror(mask);
 1.29153 +          } ptrs+=align; }
 1.29154 +      } break;
 1.29155 +      case 4 : { // 16 colors
 1.29156 +        for (int y=height-1; y>=0; --y) {
 1.29157 +          unsigned char mask = 0xF0, val = 0;
 1.29158 +          cimg_forX(*this,x) {
 1.29159 +            if (mask==0xF0) val = *(ptrs++);
 1.29160 +            const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
 1.29161 +            unsigned char *col = (unsigned char*)(palette+color);
 1.29162 +            (*this)(x,y,2) = (T)*(col++);
 1.29163 +            (*this)(x,y,1) = (T)*(col++);
 1.29164 +            (*this)(x,y,0) = (T)*(col++);
 1.29165 +            mask = cimg::ror(mask,4);
 1.29166 +          } ptrs+=align; }
 1.29167 +      } break;
 1.29168 +      case 8 : { //  256 colors
 1.29169 +        for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 1.29170 +          const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
 1.29171 +          (*this)(x,y,2) = (T)*(col++);
 1.29172 +          (*this)(x,y,1) = (T)*(col++);
 1.29173 +          (*this)(x,y,0) = (T)*(col++);
 1.29174 +        } ptrs+=align; }
 1.29175 +      } break;
 1.29176 +      case 16 : { // 16 bits colors
 1.29177 +        for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 1.29178 +          const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
 1.29179 +          const unsigned short col = (unsigned short)(c1|(c2<<8));
 1.29180 +          (*this)(x,y,2) = (T)(col&0x1F);
 1.29181 +          (*this)(x,y,1) = (T)((col>>5)&0x1F);
 1.29182 +          (*this)(x,y,0) = (T)((col>>10)&0x1F);
 1.29183 +        } ptrs+=align; }
 1.29184 +      } break;
 1.29185 +      case 24 : { // 24 bits colors
 1.29186 +        for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 1.29187 +          (*this)(x,y,2) = (T)*(ptrs++);
 1.29188 +          (*this)(x,y,1) = (T)*(ptrs++);
 1.29189 +          (*this)(x,y,0) = (T)*(ptrs++);
 1.29190 +        } ptrs+=align; }
 1.29191 +      } break;
 1.29192 +      case 32 : { // 32 bits colors
 1.29193 +        for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
 1.29194 +          (*this)(x,y,2) = (T)*(ptrs++);
 1.29195 +          (*this)(x,y,1) = (T)*(ptrs++);
 1.29196 +          (*this)(x,y,0) = (T)*(ptrs++);
 1.29197 +          ++ptrs;
 1.29198 +        } ptrs+=align; }
 1.29199 +      } break;
 1.29200 +      }
 1.29201 +      if (palette) delete[] palette;
 1.29202 +      delete[] buffer;
 1.29203 +      if (dy<0) mirror('y');
 1.29204 +      return *this;
 1.29205 +    }
 1.29206 +
 1.29207 +    //! Load an image from a JPEG file.
 1.29208 +    CImg<T>& load_jpeg(const char *const filename) {
 1.29209 +      return _load_jpeg(0,filename);
 1.29210 +    }
 1.29211 +
 1.29212 +    static CImg<T> get_load_jpeg(const char *const filename) {
 1.29213 +      return CImg<T>().load_jpeg(filename);
 1.29214 +    }
 1.29215 +
 1.29216 +    //! Load an image from a JPEG file.
 1.29217 +    CImg<T>& load_jpeg(cimg_std::FILE *const file) {
 1.29218 +      return _load_jpeg(file,0);
 1.29219 +    }
 1.29220 +
 1.29221 +    static CImg<T> get_load_jpeg(cimg_std::FILE *const file) {
 1.29222 +      return CImg<T>().load_jpeg(file);
 1.29223 +    }
 1.29224 +
 1.29225 +    CImg<T>& _load_jpeg(cimg_std::FILE *const file, const char *const filename) {
 1.29226 +      if (!filename && !file)
 1.29227 +        throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
 1.29228 +                                    pixel_type());
 1.29229 +#ifndef cimg_use_jpeg
 1.29230 +      if (file)
 1.29231 +        throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
 1.29232 +                              pixel_type());
 1.29233 +      else return load_other(filename);
 1.29234 +#else
 1.29235 +      struct jpeg_decompress_struct cinfo;
 1.29236 +      struct jpeg_error_mgr jerr;
 1.29237 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29238 +
 1.29239 +      cinfo.err = jpeg_std_error(&jerr);
 1.29240 +      jpeg_create_decompress(&cinfo);
 1.29241 +      jpeg_stdio_src(&cinfo,nfile);
 1.29242 +      jpeg_read_header(&cinfo,TRUE);
 1.29243 +      jpeg_start_decompress(&cinfo);
 1.29244 +
 1.29245 +      if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
 1.29246 +        cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
 1.29247 +                   pixel_type(),filename?filename:"(FILE*)");
 1.29248 +        if (!file) return load_other(filename);
 1.29249 +        else {
 1.29250 +          if (!file) cimg::fclose(nfile);
 1.29251 +          throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
 1.29252 +                                pixel_type(),filename?filename:"(FILE*)");
 1.29253 +        }
 1.29254 +      }
 1.29255 +
 1.29256 +      const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
 1.29257 +      unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
 1.29258 +      JSAMPROW row_pointer[1];
 1.29259 +      while (cinfo.output_scanline < cinfo.output_height) {
 1.29260 +        row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
 1.29261 +        jpeg_read_scanlines(&cinfo,row_pointer,1);
 1.29262 +      }
 1.29263 +      jpeg_finish_decompress(&cinfo);
 1.29264 +      jpeg_destroy_decompress(&cinfo);
 1.29265 +      if (!file) cimg::fclose(nfile);
 1.29266 +
 1.29267 +      assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
 1.29268 +      switch (dim) {
 1.29269 +      case 1 : {
 1.29270 +        T *ptr_g = data;
 1.29271 +        cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
 1.29272 +      } break;
 1.29273 +      case 3 : {
 1.29274 +        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 1.29275 +        cimg_forXY(*this,x,y) {
 1.29276 +          *(ptr_r++) = (T)*(buf2++);
 1.29277 +          *(ptr_g++) = (T)*(buf2++);
 1.29278 +          *(ptr_b++) = (T)*(buf2++);
 1.29279 +        }
 1.29280 +      } break;
 1.29281 +      case 4 : {
 1.29282 +        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
 1.29283 +          *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
 1.29284 +        cimg_forXY(*this,x,y) {
 1.29285 +          *(ptr_r++) = (T)*(buf2++);
 1.29286 +          *(ptr_g++) = (T)*(buf2++);
 1.29287 +          *(ptr_b++) = (T)*(buf2++);
 1.29288 +          *(ptr_a++) = (T)*(buf2++);
 1.29289 +        }
 1.29290 +      } break;
 1.29291 +      }
 1.29292 +      delete[] buf;
 1.29293 +      return *this;
 1.29294 +#endif
 1.29295 +    }
 1.29296 +
 1.29297 +    //! Load an image from a file, using Magick++ library.
 1.29298 +    // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
 1.29299 +    //   This is experimental code, not much tested, use with care.
 1.29300 +    CImg<T>& load_magick(const char *const filename) {
 1.29301 +      if (!filename)
 1.29302 +        throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
 1.29303 +                                    pixel_type());
 1.29304 +#ifdef cimg_use_magick
 1.29305 +      Magick::Image image(filename);
 1.29306 +      const unsigned int W = image.size().width(), H = image.size().height();
 1.29307 +      switch (image.type()) {
 1.29308 +      case Magick::PaletteMatteType :
 1.29309 +      case Magick::TrueColorMatteType :
 1.29310 +      case Magick::ColorSeparationType : {
 1.29311 +        assign(W,H,1,4);
 1.29312 +        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);
 1.29313 +        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 1.29314 +        for (unsigned int off = W*H; off; --off) {
 1.29315 +          *(rdata++) = (T)(pixels->red);
 1.29316 +          *(gdata++) = (T)(pixels->green);
 1.29317 +          *(bdata++) = (T)(pixels->blue);
 1.29318 +          *(adata++) = (T)(pixels->opacity);
 1.29319 +          ++pixels;
 1.29320 +        }
 1.29321 +      } break;
 1.29322 +      case Magick::PaletteType :
 1.29323 +      case Magick::TrueColorType : {
 1.29324 +        assign(W,H,1,3);
 1.29325 +        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 1.29326 +        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 1.29327 +        for (unsigned int off = W*H; off; --off) {
 1.29328 +          *(rdata++) = (T)(pixels->red);
 1.29329 +          *(gdata++) = (T)(pixels->green);
 1.29330 +          *(bdata++) = (T)(pixels->blue);
 1.29331 +          ++pixels;
 1.29332 +        }
 1.29333 +      } break;
 1.29334 +      case Magick::GrayscaleMatteType : {
 1.29335 +        assign(W,H,1,2);
 1.29336 +        T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
 1.29337 +        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 1.29338 +        for (unsigned int off = W*H; off; --off) {
 1.29339 +          *(data++) = (T)(pixels->red);
 1.29340 +          *(adata++) = (T)(pixels->opacity);
 1.29341 +          ++pixels;
 1.29342 +        }
 1.29343 +      } break;
 1.29344 +      default : {
 1.29345 +        assign(W,H,1,1);
 1.29346 +        T *data = ptr(0,0,0,0);
 1.29347 +        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 1.29348 +        for (unsigned int off = W*H; off; --off) {
 1.29349 +          *(data++) = (T)(pixels->red);
 1.29350 +          ++pixels;
 1.29351 +        }
 1.29352 +      }
 1.29353 +      }
 1.29354 +#else
 1.29355 +      throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
 1.29356 +                            pixel_type(),filename);
 1.29357 +#endif
 1.29358 +      return *this;
 1.29359 +    }
 1.29360 +
 1.29361 +    static CImg<T> get_load_magick(const char *const filename) {
 1.29362 +      return CImg<T>().load_magick(filename);
 1.29363 +    }
 1.29364 +
 1.29365 +    //! Load an image from a PNG file.
 1.29366 +    CImg<T>& load_png(const char *const filename) {
 1.29367 +      return _load_png(0,filename);
 1.29368 +    }
 1.29369 +
 1.29370 +    static CImg<T> get_load_png(const char *const filename) {
 1.29371 +      return CImg<T>().load_png(filename);
 1.29372 +    }
 1.29373 +
 1.29374 +    //! Load an image from a PNG file.
 1.29375 +    CImg<T>& load_png(cimg_std::FILE *const file) {
 1.29376 +      return _load_png(file,0);
 1.29377 +    }
 1.29378 +
 1.29379 +    static CImg<T> get_load_png(cimg_std::FILE *const file) {
 1.29380 +      return CImg<T>().load_png(file);
 1.29381 +    }
 1.29382 +
 1.29383 +    // (Note : Most of this function has been written by Eric Fausett)
 1.29384 +    CImg<T>& _load_png(cimg_std::FILE *const file, const char *const filename) {
 1.29385 +      if (!filename && !file)
 1.29386 +        throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
 1.29387 +                                    pixel_type());
 1.29388 +#ifndef cimg_use_png
 1.29389 +      if (file)
 1.29390 +        throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
 1.29391 +                              pixel_type());
 1.29392 +      else return load_other(filename);
 1.29393 +#else
 1.29394 +      // Open file and check for PNG validity
 1.29395 +      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 1.29396 +      cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
 1.29397 +
 1.29398 +      unsigned char pngCheck[8];
 1.29399 +      cimg::fread(pngCheck,8,(cimg_std::FILE*)nfile);
 1.29400 +      if (png_sig_cmp(pngCheck,0,8)) {
 1.29401 +        if (!file) cimg::fclose(nfile);
 1.29402 +        throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
 1.29403 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.29404 +      }
 1.29405 +
 1.29406 +      // Setup PNG structures for read
 1.29407 +      png_voidp user_error_ptr = 0;
 1.29408 +      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
 1.29409 +      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
 1.29410 +      if (!png_ptr) {
 1.29411 +        if (!file) cimg::fclose(nfile);
 1.29412 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
 1.29413 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.29414 +      }
 1.29415 +      png_infop info_ptr = png_create_info_struct(png_ptr);
 1.29416 +      if (!info_ptr) {
 1.29417 +        if (!file) cimg::fclose(nfile);
 1.29418 +        png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
 1.29419 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
 1.29420 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.29421 +      }
 1.29422 +      png_infop end_info = png_create_info_struct(png_ptr);
 1.29423 +      if (!end_info) {
 1.29424 +        if (!file) cimg::fclose(nfile);
 1.29425 +        png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
 1.29426 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
 1.29427 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.29428 +      }
 1.29429 +
 1.29430 +      // Error handling callback for png file reading
 1.29431 +      if (setjmp(png_jmpbuf(png_ptr))) {
 1.29432 +        if (!file) cimg::fclose((cimg_std::FILE*)nfile);
 1.29433 +        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
 1.29434 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
 1.29435 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.29436 +      }
 1.29437 +      png_init_io(png_ptr, nfile);
 1.29438 +      png_set_sig_bytes(png_ptr, 8);
 1.29439 +
 1.29440 +      // Get PNG Header Info up to data block
 1.29441 +      png_read_info(png_ptr,info_ptr);
 1.29442 +      png_uint_32 W, H;
 1.29443 +      int bit_depth, color_type, interlace_type;
 1.29444 +      png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
 1.29445 +      int new_bit_depth = bit_depth;
 1.29446 +      int new_color_type = color_type;
 1.29447 +
 1.29448 +      // Transforms to unify image data
 1.29449 +      if (new_color_type == PNG_COLOR_TYPE_PALETTE){
 1.29450 +        png_set_palette_to_rgb(png_ptr);
 1.29451 +        new_color_type -= PNG_COLOR_MASK_PALETTE;
 1.29452 +        new_bit_depth = 8;
 1.29453 +      }
 1.29454 +      if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
 1.29455 +        png_set_gray_1_2_4_to_8(png_ptr);
 1.29456 +        new_bit_depth = 8;
 1.29457 +      }
 1.29458 +      if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
 1.29459 +        png_set_tRNS_to_alpha(png_ptr);
 1.29460 +      if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
 1.29461 +        png_set_gray_to_rgb(png_ptr);
 1.29462 +        new_color_type |= PNG_COLOR_MASK_COLOR;
 1.29463 +      }
 1.29464 +      if (new_color_type == PNG_COLOR_TYPE_RGB)
 1.29465 +        png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
 1.29466 +      png_read_update_info(png_ptr,info_ptr);
 1.29467 +      if (!(new_bit_depth==8 || new_bit_depth==16)) {
 1.29468 +        if (!file) cimg::fclose(nfile);
 1.29469 +        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
 1.29470 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
 1.29471 +                              pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
 1.29472 +      }
 1.29473 +      const int byte_depth = new_bit_depth>>3;
 1.29474 +
 1.29475 +      // Allocate Memory for Image Read
 1.29476 +      png_bytep *imgData = new png_bytep[H];
 1.29477 +      for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
 1.29478 +      png_read_image(png_ptr,imgData);
 1.29479 +      png_read_end(png_ptr,end_info);
 1.29480 +
 1.29481 +      // Read pixel data
 1.29482 +      if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
 1.29483 +        if (!file) cimg::fclose(nfile);
 1.29484 +        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
 1.29485 +        throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
 1.29486 +                              pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
 1.29487 +      }
 1.29488 +      const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
 1.29489 +      assign(W,H,1,no_alpha_channel?3:4);
 1.29490 +      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);
 1.29491 +      switch (new_bit_depth) {
 1.29492 +      case 8 : {
 1.29493 +        cimg_forY(*this,y){
 1.29494 +          const unsigned char *ptrs = (unsigned char*)imgData[y];
 1.29495 +          cimg_forX(*this,x){
 1.29496 +            *(ptr1++) = (T)*(ptrs++);
 1.29497 +            *(ptr2++) = (T)*(ptrs++);
 1.29498 +            *(ptr3++) = (T)*(ptrs++);
 1.29499 +            if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
 1.29500 +          }
 1.29501 +        }
 1.29502 +      } break;
 1.29503 +      case 16 : {
 1.29504 +        cimg_forY(*this,y){
 1.29505 +          const unsigned short *ptrs = (unsigned short*)(imgData[y]);
 1.29506 +          if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
 1.29507 +          cimg_forX(*this,x){
 1.29508 +            *(ptr1++) = (T)*(ptrs++);
 1.29509 +            *(ptr2++) = (T)*(ptrs++);
 1.29510 +            *(ptr3++) = (T)*(ptrs++);
 1.29511 +            if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
 1.29512 +          }
 1.29513 +        }
 1.29514 +      } break;
 1.29515 +      }
 1.29516 +      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 1.29517 +
 1.29518 +      // Deallocate Image Read Memory
 1.29519 +      cimg_forY(*this,n) delete[] imgData[n];
 1.29520 +      delete[] imgData;
 1.29521 +      if (!file) cimg::fclose(nfile);
 1.29522 +      return *this;
 1.29523 +#endif
 1.29524 +    }
 1.29525 +
 1.29526 +    //! Load an image from a PNM file.
 1.29527 +    CImg<T>& load_pnm(const char *const filename) {
 1.29528 +      return _load_pnm(0,filename);
 1.29529 +    }
 1.29530 +
 1.29531 +    static CImg<T> get_load_pnm(const char *const filename) {
 1.29532 +      return CImg<T>().load_pnm(filename);
 1.29533 +    }
 1.29534 +
 1.29535 +    //! Load an image from a PNM file.
 1.29536 +    CImg<T>& load_pnm(cimg_std::FILE *const file) {
 1.29537 +      return _load_pnm(file,0);
 1.29538 +    }
 1.29539 +
 1.29540 +    static CImg<T> get_load_pnm(cimg_std::FILE *const file) {
 1.29541 +      return CImg<T>().load_pnm(file);
 1.29542 +    }
 1.29543 +
 1.29544 +    CImg<T>& _load_pnm(cimg_std::FILE *const file, const char *const filename) {
 1.29545 +      if (!filename && !file)
 1.29546 +        throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
 1.29547 +                                    pixel_type());
 1.29548 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29549 +      unsigned int ppm_type, W, H, colormax = 255;
 1.29550 +      char item[1024] = { 0 };
 1.29551 +      int err, rval, gval, bval;
 1.29552 +      const int cimg_iobuffer = 12*1024*1024;
 1.29553 +      while ((err=cimg_std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 1.29554 +      if (cimg_std::sscanf(item," P%u",&ppm_type)!=1) {
 1.29555 +        if (!file) cimg::fclose(nfile);
 1.29556 +        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
 1.29557 +                              pixel_type(),filename?filename:"(FILE*)");
 1.29558 +      }
 1.29559 +      while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 1.29560 +      if ((err=cimg_std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
 1.29561 +        if (!file) cimg::fclose(nfile);
 1.29562 +        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
 1.29563 +                              pixel_type(),filename?filename:"(FILE*)");
 1.29564 +      }
 1.29565 +      if (err==2) {
 1.29566 +        while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
 1.29567 +        if (cimg_std::sscanf(item,"%u",&colormax)!=1)
 1.29568 +          cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
 1.29569 +                     pixel_type(),filename?filename:"(FILE*)");
 1.29570 +      }
 1.29571 +      cimg_std::fgetc(nfile);
 1.29572 +      assign();
 1.29573 +
 1.29574 +      switch (ppm_type) {
 1.29575 +      case 2 : { // Grey Ascii
 1.29576 +        assign(W,H,1,1);
 1.29577 +        T* rdata = data;
 1.29578 +        cimg_foroff(*this,off) { if (cimg_std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
 1.29579 +      } break;
 1.29580 +      case 3 : { // Color Ascii
 1.29581 +        assign(W,H,1,3);
 1.29582 +        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 1.29583 +        cimg_forXY(*this,x,y) {
 1.29584 +          if (cimg_std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
 1.29585 +          else break;
 1.29586 +        }
 1.29587 +      } break;
 1.29588 +      case 5 : { // Grey Binary
 1.29589 +        if (colormax<256) { // 8 bits
 1.29590 +          CImg<ucharT> raw;
 1.29591 +          assign(W,H,1,1);
 1.29592 +          T *ptrd = ptr(0,0,0,0);
 1.29593 +          for (int toread = (int)size(); toread>0; ) {
 1.29594 +            raw.assign(cimg::min(toread,cimg_iobuffer));
 1.29595 +            cimg::fread(raw.data,raw.width,nfile);
 1.29596 +            toread-=raw.width;
 1.29597 +            const unsigned char *ptrs = raw.data;
 1.29598 +            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 1.29599 +          }
 1.29600 +        } else { // 16 bits
 1.29601 +          CImg<ushortT> raw;
 1.29602 +          assign(W,H,1,1);
 1.29603 +          T *ptrd = ptr(0,0,0,0);
 1.29604 +          for (int toread = (int)size(); toread>0; ) {
 1.29605 +            raw.assign(cimg::min(toread,cimg_iobuffer/2));
 1.29606 +            cimg::fread(raw.data,raw.width,nfile);
 1.29607 +            if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
 1.29608 +            toread-=raw.width;
 1.29609 +            const unsigned short *ptrs = raw.data;
 1.29610 +            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 1.29611 +          }
 1.29612 +        }
 1.29613 +      } break;
 1.29614 +      case 6 : { // Color Binary
 1.29615 +        if (colormax<256) { // 8 bits
 1.29616 +          CImg<ucharT> raw;
 1.29617 +          assign(W,H,1,3);
 1.29618 +          T
 1.29619 +            *ptr_r = ptr(0,0,0,0),
 1.29620 +            *ptr_g = ptr(0,0,0,1),
 1.29621 +            *ptr_b = ptr(0,0,0,2);
 1.29622 +          for (int toread = (int)size(); toread>0; ) {
 1.29623 +            raw.assign(cimg::min(toread,cimg_iobuffer));
 1.29624 +            cimg::fread(raw.data,raw.width,nfile);
 1.29625 +            toread-=raw.width;
 1.29626 +            const unsigned char *ptrs = raw.data;
 1.29627 +            for (unsigned int off = raw.width/3; off; --off) {
 1.29628 +              *(ptr_r++) = (T)*(ptrs++);
 1.29629 +              *(ptr_g++) = (T)*(ptrs++);
 1.29630 +              *(ptr_b++) = (T)*(ptrs++);
 1.29631 +            }
 1.29632 +          }
 1.29633 +        } else { // 16 bits
 1.29634 +          CImg<ushortT> raw;
 1.29635 +          assign(W,H,1,3);
 1.29636 +          T
 1.29637 +            *ptr_r = ptr(0,0,0,0),
 1.29638 +            *ptr_g = ptr(0,0,0,1),
 1.29639 +            *ptr_b = ptr(0,0,0,2);
 1.29640 +          for (int toread = (int)size(); toread>0; ) {
 1.29641 +            raw.assign(cimg::min(toread,cimg_iobuffer/2));
 1.29642 +            cimg::fread(raw.data,raw.width,nfile);
 1.29643 +            if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
 1.29644 +            toread-=raw.width;
 1.29645 +            const unsigned short *ptrs = raw.data;
 1.29646 +            for (unsigned int off = raw.width/3; off; --off) {
 1.29647 +              *(ptr_r++) = (T)*(ptrs++);
 1.29648 +              *(ptr_g++) = (T)*(ptrs++);
 1.29649 +              *(ptr_b++) = (T)*(ptrs++);
 1.29650 +            }
 1.29651 +          }
 1.29652 +        }
 1.29653 +      } break;
 1.29654 +      default :
 1.29655 +        if (!file) cimg::fclose(nfile);
 1.29656 +        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
 1.29657 +                              pixel_type(),filename?filename:"(FILE*)",ppm_type);
 1.29658 +      }
 1.29659 +      if (!file) cimg::fclose(nfile);
 1.29660 +      return *this;
 1.29661 +    }
 1.29662 +
 1.29663 +    //! Load an image from a RGB file.
 1.29664 +    CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 1.29665 +      return _load_rgb(0,filename,dimw,dimh);
 1.29666 +    }
 1.29667 +
 1.29668 +    static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 1.29669 +      return CImg<T>().load_rgb(filename,dimw,dimh);
 1.29670 +    }
 1.29671 +
 1.29672 +    //! Load an image from a RGB file.
 1.29673 +    CImg<T>& load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 1.29674 +      return _load_rgb(file,0,dimw,dimh);
 1.29675 +    }
 1.29676 +
 1.29677 +    static CImg<T> get_load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 1.29678 +      return CImg<T>().load_rgb(file,dimw,dimh);
 1.29679 +    }
 1.29680 +
 1.29681 +    CImg<T>& _load_rgb(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 1.29682 +      if (!filename && !file)
 1.29683 +        throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
 1.29684 +                                    pixel_type());
 1.29685 +      if (!dimw || !dimh) return assign();
 1.29686 +      const int cimg_iobuffer = 12*1024*1024;
 1.29687 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29688 +      CImg<ucharT> raw;
 1.29689 +      assign(dimw,dimh,1,3);
 1.29690 +      T
 1.29691 +        *ptr_r = ptr(0,0,0,0),
 1.29692 +        *ptr_g = ptr(0,0,0,1),
 1.29693 +        *ptr_b = ptr(0,0,0,2);
 1.29694 +      for (int toread = (int)size(); toread>0; ) {
 1.29695 +        raw.assign(cimg::min(toread,cimg_iobuffer));
 1.29696 +        cimg::fread(raw.data,raw.width,nfile);
 1.29697 +        toread-=raw.width;
 1.29698 +        const unsigned char *ptrs = raw.data;
 1.29699 +        for (unsigned int off = raw.width/3; off; --off) {
 1.29700 +          *(ptr_r++) = (T)*(ptrs++);
 1.29701 +          *(ptr_g++) = (T)*(ptrs++);
 1.29702 +          *(ptr_b++) = (T)*(ptrs++);
 1.29703 +        }
 1.29704 +      }
 1.29705 +      if (!file) cimg::fclose(nfile);
 1.29706 +      return *this;
 1.29707 +    }
 1.29708 +
 1.29709 +    //! Load an image from a RGBA file.
 1.29710 +    CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 1.29711 +      return _load_rgba(0,filename,dimw,dimh);
 1.29712 +    }
 1.29713 +
 1.29714 +    static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 1.29715 +      return CImg<T>().load_rgba(filename,dimw,dimh);
 1.29716 +    }
 1.29717 +
 1.29718 +    //! Load an image from a RGBA file.
 1.29719 +    CImg<T>& load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 1.29720 +      return _load_rgba(file,0,dimw,dimh);
 1.29721 +    }
 1.29722 +
 1.29723 +    static CImg<T> get_load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 1.29724 +      return CImg<T>().load_rgba(file,dimw,dimh);
 1.29725 +    }
 1.29726 +
 1.29727 +    CImg<T>& _load_rgba(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 1.29728 +      if (!filename && !file)
 1.29729 +        throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
 1.29730 +                                    pixel_type());
 1.29731 +      if (!dimw || !dimh) return assign();
 1.29732 +      const int cimg_iobuffer = 12*1024*1024;
 1.29733 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.29734 +      CImg<ucharT> raw;
 1.29735 +      assign(dimw,dimh,1,4);
 1.29736 +      T
 1.29737 +        *ptr_r = ptr(0,0,0,0),
 1.29738 +        *ptr_g = ptr(0,0,0,1),
 1.29739 +        *ptr_b = ptr(0,0,0,2),
 1.29740 +        *ptr_a = ptr(0,0,0,3);
 1.29741 +      for (int toread = (int)size(); toread>0; ) {
 1.29742 +        raw.assign(cimg::min(toread,cimg_iobuffer));
 1.29743 +        cimg::fread(raw.data,raw.width,nfile);
 1.29744 +        toread-=raw.width;
 1.29745 +        const unsigned char *ptrs = raw.data;
 1.29746 +        for (unsigned int off = raw.width/4; off; --off) {
 1.29747 +          *(ptr_r++) = (T)*(ptrs++);
 1.29748 +          *(ptr_g++) = (T)*(ptrs++);
 1.29749 +          *(ptr_b++) = (T)*(ptrs++);
 1.29750 +          *(ptr_a++) = (T)*(ptrs++);
 1.29751 +        }
 1.29752 +      }
 1.29753 +      if (!file) cimg::fclose(nfile);
 1.29754 +      return *this;
 1.29755 +    }
 1.29756 +
 1.29757 +    //! Load an image from a TIFF file.
 1.29758 +    CImg<T>& load_tiff(const char *const filename,
 1.29759 +                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.29760 +                       const unsigned int step_frame=1) {
 1.29761 +      if (!filename)
 1.29762 +        throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
 1.29763 +                                    pixel_type());
 1.29764 +      const unsigned int
 1.29765 +        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 1.29766 +        nstep_frame = step_frame?step_frame:1;
 1.29767 +      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 1.29768 +
 1.29769 +#ifndef cimg_use_tiff
 1.29770 +      if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
 1.29771 +        throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 1.29772 +                                    "('cimg_use_tiff' must be defined).",
 1.29773 +                                    pixel_type(),filename);
 1.29774 +      return load_other(filename);
 1.29775 +#else
 1.29776 +      TIFF *tif = TIFFOpen(filename,"r");
 1.29777 +      if (tif) {
 1.29778 +        unsigned int nb_images = 0;
 1.29779 +        do ++nb_images; while (TIFFReadDirectory(tif));
 1.29780 +        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 1.29781 +          cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 1.29782 +                     pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 1.29783 +        if (nfirst_frame>=nb_images) return assign();
 1.29784 +        if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 1.29785 +        TIFFSetDirectory(tif,0);
 1.29786 +        CImg<T> frame;
 1.29787 +        for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
 1.29788 +          frame._load_tiff(tif,l);
 1.29789 +          if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
 1.29790 +          if (frame.width>width || frame.height>height || frame.dim>dim)
 1.29791 +            resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
 1.29792 +          draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
 1.29793 +        }
 1.29794 +        TIFFClose(tif);
 1.29795 +      } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
 1.29796 +                                 pixel_type(),filename);
 1.29797 +      return *this;
 1.29798 +#endif
 1.29799 +    }
 1.29800 +
 1.29801 +    static CImg<T> get_load_tiff(const char *const filename,
 1.29802 +                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.29803 +                                 const unsigned int step_frame=1) {
 1.29804 +      return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 1.29805 +    }
 1.29806 +
 1.29807 +    // (Original contribution by Jerome Boulanger).
 1.29808 +#ifdef cimg_use_tiff
 1.29809 +    CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
 1.29810 +      if (!TIFFSetDirectory(tif,directory)) return assign();
 1.29811 +      uint16 samplesperpixel, bitspersample;
 1.29812 +      uint32 nx,ny;
 1.29813 +      const char *const filename = TIFFFileName(tif);
 1.29814 +      TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
 1.29815 +      TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
 1.29816 +      TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
 1.29817 +      if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
 1.29818 +        cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
 1.29819 +                   pixel_type(),filename);
 1.29820 +        samplesperpixel = 1;
 1.29821 +      }
 1.29822 +      TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
 1.29823 +      assign(nx,ny,1,samplesperpixel);
 1.29824 +      if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
 1.29825 +        uint16 photo, config;
 1.29826 +        TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
 1.29827 +        TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
 1.29828 +        if (TIFFIsTiled(tif)) {
 1.29829 +          uint32 tw, th;
 1.29830 +          TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
 1.29831 +          TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
 1.29832 +          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 1.29833 +            case 8 : {
 1.29834 +              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 1.29835 +              if (buf) {
 1.29836 +                for (unsigned int row = 0; row<ny; row+=th)
 1.29837 +                  for (unsigned int col = 0; col<nx; col+=tw) {
 1.29838 +                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 1.29839 +                      _TIFFfree(buf); TIFFClose(tif);
 1.29840 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29841 +                                          pixel_type(),filename);
 1.29842 +                    } else {
 1.29843 +                      unsigned char *ptr = buf;
 1.29844 +                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29845 +                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29846 +                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29847 +                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 1.29848 +                    }
 1.29849 +                  }
 1.29850 +                _TIFFfree(buf);
 1.29851 +              }
 1.29852 +            } break;
 1.29853 +            case 16 : {
 1.29854 +              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 1.29855 +              if (buf) {
 1.29856 +                for (unsigned int row = 0; row<ny; row+=th)
 1.29857 +                  for (unsigned int col = 0; col<nx; col+=tw) {
 1.29858 +                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 1.29859 +                      _TIFFfree(buf); TIFFClose(tif);
 1.29860 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29861 +                                          pixel_type(),filename);
 1.29862 +                    } else {
 1.29863 +                      unsigned short *ptr = buf;
 1.29864 +                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29865 +                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29866 +                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29867 +                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 1.29868 +                    }
 1.29869 +                  }
 1.29870 +                _TIFFfree(buf);
 1.29871 +              }
 1.29872 +            } break;
 1.29873 +            case 32 : {
 1.29874 +              float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 1.29875 +              if (buf) {
 1.29876 +                for (unsigned int row = 0; row<ny; row+=th)
 1.29877 +                  for (unsigned int col = 0; col<nx; col+=tw) {
 1.29878 +                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 1.29879 +                      _TIFFfree(buf); TIFFClose(tif);
 1.29880 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29881 +                                          pixel_type(),filename);
 1.29882 +                    } else {
 1.29883 +                      float *ptr = buf;
 1.29884 +                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29885 +                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29886 +                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29887 +                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 1.29888 +                    }
 1.29889 +                  }
 1.29890 +                _TIFFfree(buf);
 1.29891 +              }
 1.29892 +            } break;
 1.29893 +            } else switch (bitspersample) {
 1.29894 +            case 8 : {
 1.29895 +              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 1.29896 +              if (buf) {
 1.29897 +                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29898 +                  for (unsigned int row = 0; row<ny; row+=th)
 1.29899 +                    for (unsigned int col = 0; col<nx; col+=tw) {
 1.29900 +                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 1.29901 +                        _TIFFfree(buf); TIFFClose(tif);
 1.29902 +                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29903 +                                            pixel_type(),filename);
 1.29904 +                      } else {
 1.29905 +                        unsigned char *ptr = buf;
 1.29906 +                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29907 +                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29908 +                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 1.29909 +                      }
 1.29910 +                    }
 1.29911 +                _TIFFfree(buf);
 1.29912 +              }
 1.29913 +            } break;
 1.29914 +            case 16 : {
 1.29915 +              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 1.29916 +              if (buf) {
 1.29917 +                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29918 +                  for (unsigned int row = 0; row<ny; row+=th)
 1.29919 +                    for (unsigned int col = 0; col<nx; col+=tw) {
 1.29920 +                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 1.29921 +                        _TIFFfree(buf); TIFFClose(tif);
 1.29922 +                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29923 +                                            pixel_type(),filename);
 1.29924 +                      } else {
 1.29925 +                        unsigned short *ptr = buf;
 1.29926 +                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29927 +                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29928 +                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 1.29929 +                      }
 1.29930 +                    }
 1.29931 +                _TIFFfree(buf);
 1.29932 +              }
 1.29933 +            } break;
 1.29934 +            case 32 : {
 1.29935 +              float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 1.29936 +              if (buf) {
 1.29937 +                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.29938 +                  for (unsigned int row = 0; row<ny; row+=th)
 1.29939 +                    for (unsigned int col = 0; col<nx; col+=tw) {
 1.29940 +                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
 1.29941 +                        _TIFFfree(buf); TIFFClose(tif);
 1.29942 +                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 1.29943 +                                            pixel_type(),filename);
 1.29944 +                      } else {
 1.29945 +                        float *ptr = buf;
 1.29946 +                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 1.29947 +                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 1.29948 +                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
 1.29949 +                      }
 1.29950 +                    }
 1.29951 +                _TIFFfree(buf);
 1.29952 +              }
 1.29953 +            } break;
 1.29954 +            }
 1.29955 +        } else {
 1.29956 +          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 1.29957 +            case 8 : {
 1.29958 +              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 1.29959 +              if (buf) {
 1.29960 +                uint32 row, rowsperstrip = (uint32)-1;
 1.29961 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.29962 +                for (row = 0; row<ny; row+= rowsperstrip) {
 1.29963 +                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.29964 +                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 1.29965 +                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.29966 +                    _TIFFfree(buf); TIFFClose(tif);
 1.29967 +                    throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
 1.29968 +                                        pixel_type(),filename);
 1.29969 +                  }
 1.29970 +                  unsigned char *ptr = buf;
 1.29971 +                  for (unsigned int rr = 0; rr<nrow; ++rr)
 1.29972 +                    for (unsigned int cc = 0; cc<nx; ++cc)
 1.29973 +                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.29974 +                }
 1.29975 +                _TIFFfree(buf);
 1.29976 +              }
 1.29977 +            } break;
 1.29978 +            case 16 : {
 1.29979 +              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 1.29980 +              if (buf) {
 1.29981 +                uint32 row, rowsperstrip = (uint32)-1;
 1.29982 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.29983 +                for (row = 0; row<ny; row+= rowsperstrip) {
 1.29984 +                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.29985 +                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 1.29986 +                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.29987 +                    _TIFFfree(buf); TIFFClose(tif);
 1.29988 +                    throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 1.29989 +                                        pixel_type(),filename);
 1.29990 +                  }
 1.29991 +                  unsigned short *ptr = buf;
 1.29992 +                  for (unsigned int rr = 0; rr<nrow; ++rr)
 1.29993 +                    for (unsigned int cc = 0; cc<nx; ++cc)
 1.29994 +                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.29995 +                }
 1.29996 +                _TIFFfree(buf);
 1.29997 +              }
 1.29998 +            } break;
 1.29999 +            case 32 : {
 1.30000 +              float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 1.30001 +              if (buf) {
 1.30002 +                uint32 row, rowsperstrip = (uint32)-1;
 1.30003 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.30004 +                for (row = 0; row<ny; row+= rowsperstrip) {
 1.30005 +                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.30006 +                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 1.30007 +                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.30008 +                    _TIFFfree(buf); TIFFClose(tif);
 1.30009 +                    throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 1.30010 +                                        pixel_type(),filename);
 1.30011 +                  }
 1.30012 +                  float *ptr = buf;
 1.30013 +                  for (unsigned int rr = 0; rr<nrow; ++rr)
 1.30014 +                    for (unsigned int cc = 0; cc<nx; ++cc)
 1.30015 +                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.30016 +                }
 1.30017 +                _TIFFfree(buf);
 1.30018 +              }
 1.30019 +            } break;
 1.30020 +            } else switch (bitspersample){
 1.30021 +            case 8 : {
 1.30022 +              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 1.30023 +              if (buf) {
 1.30024 +                uint32 row, rowsperstrip = (uint32)-1;
 1.30025 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.30026 +                for (unsigned int vv=0; vv<samplesperpixel; ++vv)
 1.30027 +                  for (row = 0; row<ny; row+= rowsperstrip) {
 1.30028 +                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.30029 +                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 1.30030 +                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.30031 +                      _TIFFfree(buf); TIFFClose(tif);
 1.30032 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
 1.30033 +                                          pixel_type(),filename);
 1.30034 +                    }
 1.30035 +                    unsigned char *ptr = buf;
 1.30036 +                    for (unsigned int rr = 0;rr<nrow; ++rr)
 1.30037 +                      for (unsigned int cc = 0; cc<nx; ++cc)
 1.30038 +                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.30039 +                  }
 1.30040 +                _TIFFfree(buf);
 1.30041 +              }
 1.30042 +            } break;
 1.30043 +            case 16 : {
 1.30044 +              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 1.30045 +              if (buf) {
 1.30046 +                uint32 row, rowsperstrip = (uint32)-1;
 1.30047 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.30048 +                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.30049 +                  for (row = 0; row<ny; row+= rowsperstrip) {
 1.30050 +                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.30051 +                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 1.30052 +                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.30053 +                      _TIFFfree(buf); TIFFClose(tif);
 1.30054 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 1.30055 +                                          pixel_type(),filename);
 1.30056 +                    }
 1.30057 +                    unsigned short *ptr = buf;
 1.30058 +                    for (unsigned int rr = 0; rr<nrow; ++rr)
 1.30059 +                      for (unsigned int cc = 0; cc<nx; ++cc)
 1.30060 +                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.30061 +                  }
 1.30062 +                _TIFFfree(buf);
 1.30063 +              }
 1.30064 +            } break;
 1.30065 +            case 32 : {
 1.30066 +              float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 1.30067 +              if (buf) {
 1.30068 +                uint32 row, rowsperstrip = (uint32)-1;
 1.30069 +                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 1.30070 +                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 1.30071 +                  for (row = 0; row<ny; row+= rowsperstrip) {
 1.30072 +                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 1.30073 +                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
 1.30074 +                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 1.30075 +                      _TIFFfree(buf); TIFFClose(tif);
 1.30076 +                      throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 1.30077 +                                          pixel_type(),filename);
 1.30078 +                    }
 1.30079 +                    float *ptr = buf;
 1.30080 +                    for (unsigned int rr = 0; rr<nrow; ++rr)  for (unsigned int cc = 0; cc<nx; ++cc)
 1.30081 +                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 1.30082 +                  }
 1.30083 +                _TIFFfree(buf);
 1.30084 +              }
 1.30085 +            } break;
 1.30086 +            }
 1.30087 +        }
 1.30088 +      } else {
 1.30089 +        uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
 1.30090 +        if (!raster) {
 1.30091 +          _TIFFfree(raster); TIFFClose(tif);
 1.30092 +          throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
 1.30093 +                              pixel_type(),filename);
 1.30094 +        }
 1.30095 +        TIFFReadRGBAImage(tif,nx,ny,raster,0);
 1.30096 +        switch (samplesperpixel) {
 1.30097 +        case 1 : {
 1.30098 +          cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
 1.30099 +        } break;
 1.30100 +        case 3 : {
 1.30101 +          cimg_forXY(*this,x,y) {
 1.30102 +            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 1.30103 +            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 1.30104 +            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 1.30105 +          }
 1.30106 +        } break;
 1.30107 +        case 4 : {
 1.30108 +          cimg_forXY(*this,x,y) {
 1.30109 +            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 1.30110 +            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 1.30111 +            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 1.30112 +            (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
 1.30113 +          }
 1.30114 +        } break;
 1.30115 +        }
 1.30116 +        _TIFFfree(raster);
 1.30117 +      }
 1.30118 +      return *this;
 1.30119 +    }
 1.30120 +#endif
 1.30121 +
 1.30122 +    //! Load an image from an ANALYZE7.5/NIFTI file.
 1.30123 +    CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
 1.30124 +      return _load_analyze(0,filename,voxsize);
 1.30125 +    }
 1.30126 +
 1.30127 +    static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
 1.30128 +      return CImg<T>().load_analyze(filename,voxsize);
 1.30129 +    }
 1.30130 +
 1.30131 +    //! Load an image from an ANALYZE7.5/NIFTI file.
 1.30132 +    CImg<T>& load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
 1.30133 +      return _load_analyze(file,0,voxsize);
 1.30134 +    }
 1.30135 +
 1.30136 +    static CImg<T> get_load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
 1.30137 +      return CImg<T>().load_analyze(file,voxsize);
 1.30138 +    }
 1.30139 +
 1.30140 +    CImg<T>& _load_analyze(cimg_std::FILE *const file, const char *const filename, float *const voxsize=0) {
 1.30141 +      if (!filename && !file)
 1.30142 +        throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
 1.30143 +                                    pixel_type());
 1.30144 +      cimg_std::FILE *nfile_header = 0, *nfile = 0;
 1.30145 +      if (!file) {
 1.30146 +        char body[1024];
 1.30147 +        const char *ext = cimg::split_filename(filename,body);
 1.30148 +        if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
 1.30149 +          nfile_header = cimg::fopen(filename,"rb");
 1.30150 +          cimg_std::sprintf(body+cimg::strlen(body),".img");
 1.30151 +          nfile = cimg::fopen(body,"rb");
 1.30152 +        } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
 1.30153 +          nfile = cimg::fopen(filename,"rb");
 1.30154 +          cimg_std::sprintf(body+cimg::strlen(body),".hdr");
 1.30155 +          nfile_header = cimg::fopen(body,"rb");
 1.30156 +        } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
 1.30157 +      } else nfile_header = nfile = file; // File is a Niftii file.
 1.30158 +      if (!nfile || !nfile_header)
 1.30159 +        throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
 1.30160 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30161 +
 1.30162 +      // Read header.
 1.30163 +      bool endian = false;
 1.30164 +      unsigned int header_size;
 1.30165 +      cimg::fread(&header_size,1,nfile_header);
 1.30166 +      if (!header_size)
 1.30167 +        throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
 1.30168 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30169 +      if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
 1.30170 +      unsigned char *header = new unsigned char[header_size];
 1.30171 +      cimg::fread(header+4,header_size-4,nfile_header);
 1.30172 +      if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
 1.30173 +      if (endian) {
 1.30174 +        cimg::invert_endianness((short*)(header+40),5);
 1.30175 +        cimg::invert_endianness((short*)(header+70),1);
 1.30176 +        cimg::invert_endianness((short*)(header+72),1);
 1.30177 +        cimg::invert_endianness((float*)(header+76),4);
 1.30178 +        cimg::invert_endianness((float*)(header+112),1);
 1.30179 +      }
 1.30180 +      unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
 1.30181 +      if (!dim[0])
 1.30182 +        cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
 1.30183 +                   pixel_type(),filename?filename:"(FILE*)");
 1.30184 +      if (dim[0]>4)
 1.30185 +        cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
 1.30186 +                   pixel_type(),filename?filename:"(FILE*)",dim[0]);
 1.30187 +      if (dim[0]>=1) dimx = dim[1];
 1.30188 +      if (dim[0]>=2) dimy = dim[2];
 1.30189 +      if (dim[0]>=3) dimz = dim[3];
 1.30190 +      if (dim[0]>=4) dimv = dim[4];
 1.30191 +      float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
 1.30192 +      const unsigned short datatype = *(short*)(header+70);
 1.30193 +      if (voxsize) {
 1.30194 +        const float *vsize = (float*)(header+76);
 1.30195 +        voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
 1.30196 +      }
 1.30197 +      delete[] header;
 1.30198 +
 1.30199 +      // Read pixel data.
 1.30200 +      assign(dimx,dimy,dimz,dimv);
 1.30201 +      switch (datatype) {
 1.30202 +      case 2 : {
 1.30203 +        unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
 1.30204 +        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 1.30205 +        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 1.30206 +        delete[] buffer;
 1.30207 +      } break;
 1.30208 +      case 4 : {
 1.30209 +        short *buffer = new short[dimx*dimy*dimz*dimv];
 1.30210 +        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 1.30211 +        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 1.30212 +        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 1.30213 +        delete[] buffer;
 1.30214 +      } break;
 1.30215 +      case 8 : {
 1.30216 +        int *buffer = new int[dimx*dimy*dimz*dimv];
 1.30217 +        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 1.30218 +        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 1.30219 +        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 1.30220 +        delete[] buffer;
 1.30221 +      } break;
 1.30222 +      case 16 : {
 1.30223 +        float *buffer = new float[dimx*dimy*dimz*dimv];
 1.30224 +        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 1.30225 +        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 1.30226 +        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 1.30227 +        delete[] buffer;
 1.30228 +      } break;
 1.30229 +      case 64 : {
 1.30230 +        double *buffer = new double[dimx*dimy*dimz*dimv];
 1.30231 +        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 1.30232 +        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 1.30233 +        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 1.30234 +        delete[] buffer;
 1.30235 +      } break;
 1.30236 +      default :
 1.30237 +        if (!file) cimg::fclose(nfile);
 1.30238 +        throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
 1.30239 +                              pixel_type(),filename?filename:"(FILE*)",datatype);
 1.30240 +      }
 1.30241 +      if (!file) cimg::fclose(nfile);
 1.30242 +      return *this;
 1.30243 +    }
 1.30244 +
 1.30245 +    //! Load an image (list) from a .cimg file.
 1.30246 +    CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
 1.30247 +      CImgList<T> list;
 1.30248 +      list.load_cimg(filename);
 1.30249 +      if (list.size==1) return list[0].transfer_to(*this);
 1.30250 +      return assign(list.get_append(axis,align));
 1.30251 +    }
 1.30252 +
 1.30253 +    static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
 1.30254 +      return CImg<T>().load_cimg(filename,axis,align);
 1.30255 +    }
 1.30256 +
 1.30257 +    //! Load an image (list) from a .cimg file.
 1.30258 +    CImg<T>& load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
 1.30259 +      CImgList<T> list;
 1.30260 +      list.load_cimg(file);
 1.30261 +      if (list.size==1) return list[0].transfer_to(*this);
 1.30262 +      return assign(list.get_append(axis,align));
 1.30263 +    }
 1.30264 +
 1.30265 +    static CImg<T> get_load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
 1.30266 +      return CImg<T>().load_cimg(file,axis,align);
 1.30267 +    }
 1.30268 +
 1.30269 +    //! Load a sub-image (list) from a .cimg file.
 1.30270 +    CImg<T>& load_cimg(const char *const filename,
 1.30271 +                       const unsigned int n0, const unsigned int n1,
 1.30272 +                       const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.30273 +                       const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 1.30274 +                       const char axis='z', const char align='p') {
 1.30275 +      CImgList<T> list;
 1.30276 +      list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.30277 +      if (list.size==1) return list[0].transfer_to(*this);
 1.30278 +      return assign(list.get_append(axis,align));
 1.30279 +    }
 1.30280 +
 1.30281 +    static CImg<T> get_load_cimg(const char *const filename,
 1.30282 +                                 const unsigned int n0, const unsigned int n1,
 1.30283 +                                 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.30284 +                                 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 1.30285 +                                 const char axis='z', const char align='p') {
 1.30286 +      return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 1.30287 +    }
 1.30288 +
 1.30289 +    //! Load a sub-image (list) from a non-compressed .cimg file.
 1.30290 +    CImg<T>& load_cimg(cimg_std::FILE *const file,
 1.30291 +                       const unsigned int n0, const unsigned int n1,
 1.30292 +                       const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.30293 +                       const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 1.30294 +                       const char axis='z', const char align='p') {
 1.30295 +      CImgList<T> list;
 1.30296 +      list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.30297 +      if (list.size==1) return list[0].transfer_to(*this);
 1.30298 +      return assign(list.get_append(axis,align));
 1.30299 +    }
 1.30300 +
 1.30301 +    static CImg<T> get_load_cimg(cimg_std::FILE *const file,
 1.30302 +                                 const unsigned int n0, const unsigned int n1,
 1.30303 +                                 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.30304 +                                 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 1.30305 +                                 const char axis='z', const char align='p') {
 1.30306 +      return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 1.30307 +    }
 1.30308 +
 1.30309 +    //! Load an image from an INRIMAGE-4 file.
 1.30310 +    CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
 1.30311 +      return _load_inr(0,filename,voxsize);
 1.30312 +    }
 1.30313 +
 1.30314 +    static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
 1.30315 +      return CImg<T>().load_inr(filename,voxsize);
 1.30316 +    }
 1.30317 +
 1.30318 +    //! Load an image from an INRIMAGE-4 file.
 1.30319 +    CImg<T>& load_inr(cimg_std::FILE *const file, float *const voxsize=0) {
 1.30320 +      return _load_inr(file,0,voxsize);
 1.30321 +    }
 1.30322 +
 1.30323 +    static CImg<T> get_load_inr(cimg_std::FILE *const file, float *voxsize=0) {
 1.30324 +      return CImg<T>().load_inr(file,voxsize);
 1.30325 +    }
 1.30326 +
 1.30327 +    // Load an image from an INRIMAGE-4 file (internal).
 1.30328 +    static void _load_inr_header(cimg_std::FILE *file, int out[8], float *const voxsize) {
 1.30329 +      char item[1024], tmp1[64], tmp2[64];
 1.30330 +      out[0] = cimg_std::fscanf(file,"%63s",item);
 1.30331 +      out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
 1.30332 +      if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
 1.30333 +        throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
 1.30334 +                              "(INRIMAGE-4 identifier not found)",
 1.30335 +                              pixel_type());
 1.30336 +      while (cimg_std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
 1.30337 +        cimg_std::sscanf(item," XDIM%*[^0-9]%d",out);
 1.30338 +        cimg_std::sscanf(item," YDIM%*[^0-9]%d",out+1);
 1.30339 +        cimg_std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
 1.30340 +        cimg_std::sscanf(item," VDIM%*[^0-9]%d",out+3);
 1.30341 +        cimg_std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
 1.30342 +        if (voxsize) {
 1.30343 +          cimg_std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
 1.30344 +          cimg_std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
 1.30345 +          cimg_std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
 1.30346 +        }
 1.30347 +        if (cimg_std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
 1.30348 +        switch (cimg_std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
 1.30349 +        case 0 : break;
 1.30350 +        case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; cimg_std::strcpy(tmp1,tmp2);
 1.30351 +        case 1 :
 1.30352 +          if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4] = 0;
 1.30353 +          if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
 1.30354 +          if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4] = 2;
 1.30355 +          if (out[4]>=0) break;
 1.30356 +        default :
 1.30357 +          throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
 1.30358 +        }
 1.30359 +      }
 1.30360 +      if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
 1.30361 +        throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
 1.30362 +                              pixel_type(),out[0],out[1],out[2],out[3]);
 1.30363 +      if(out[4]<0 || out[5]<0)
 1.30364 +        throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
 1.30365 +                              pixel_type());
 1.30366 +      if(out[6]<0)
 1.30367 +        throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
 1.30368 +                              pixel_type());
 1.30369 +      if(out[7]<0)
 1.30370 +        throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
 1.30371 +                              pixel_type());
 1.30372 +    }
 1.30373 +
 1.30374 +    CImg<T>& _load_inr(cimg_std::FILE *const file, const char *const filename, float *const voxsize) {
 1.30375 +#define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
 1.30376 +     if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
 1.30377 +        Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
 1.30378 +        cimg_forYZ(*this,y,z) { \
 1.30379 +            cimg::fread(val,fopt[0]*fopt[3],nfile); \
 1.30380 +            if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
 1.30381 +            xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
 1.30382 +          } \
 1.30383 +        delete[] val; \
 1.30384 +        loaded = true; \
 1.30385 +      }
 1.30386 +
 1.30387 +      if (!filename && !file)
 1.30388 +        throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
 1.30389 +                                    pixel_type());
 1.30390 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.30391 +      int fopt[8], endian=cimg::endianness()?1:0;
 1.30392 +      bool loaded = false;
 1.30393 +      if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
 1.30394 +      _load_inr_header(nfile,fopt,voxsize);
 1.30395 +      assign(fopt[0],fopt[1],fopt[2],fopt[3]);
 1.30396 +      _cimg_load_inr_case(0,0,8, unsigned char);
 1.30397 +      _cimg_load_inr_case(0,1,8, char);
 1.30398 +      _cimg_load_inr_case(0,0,16,unsigned short);
 1.30399 +      _cimg_load_inr_case(0,1,16,short);
 1.30400 +      _cimg_load_inr_case(0,0,32,unsigned int);
 1.30401 +      _cimg_load_inr_case(0,1,32,int);
 1.30402 +      _cimg_load_inr_case(1,0,32,float);
 1.30403 +      _cimg_load_inr_case(1,1,32,float);
 1.30404 +      _cimg_load_inr_case(1,0,64,double);
 1.30405 +      _cimg_load_inr_case(1,1,64,double);
 1.30406 +      if (!loaded) {
 1.30407 +        if (!file) cimg::fclose(nfile);
 1.30408 +        throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
 1.30409 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30410 +      }
 1.30411 +      if (!file) cimg::fclose(nfile);
 1.30412 +      return *this;
 1.30413 +    }
 1.30414 +
 1.30415 +    //! Load an image from a PANDORE file.
 1.30416 +    CImg<T>& load_pandore(const char *const filename) {
 1.30417 +      return _load_pandore(0,filename);
 1.30418 +    }
 1.30419 +
 1.30420 +    static CImg<T> get_load_pandore(const char *const filename) {
 1.30421 +      return CImg<T>().load_pandore(filename);
 1.30422 +    }
 1.30423 +
 1.30424 +    //! Load an image from a PANDORE file.
 1.30425 +    CImg<T>& load_pandore(cimg_std::FILE *const file) {
 1.30426 +      return _load_pandore(file,0);
 1.30427 +    }
 1.30428 +
 1.30429 +    static CImg<T> get_load_pandore(cimg_std::FILE *const file) {
 1.30430 +      return CImg<T>().load_pandore(file);
 1.30431 +    }
 1.30432 +
 1.30433 +    CImg<T>& _load_pandore(cimg_std::FILE *const file, const char *const filename) {
 1.30434 +#define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
 1.30435 +        cimg::fread(dims,nbdim,nfile); \
 1.30436 +        if (endian) cimg::invert_endianness(dims,nbdim); \
 1.30437 +        assign(nwidth,nheight,ndepth,ndim); \
 1.30438 +        const unsigned int siz = size(); \
 1.30439 +        stype *buffer = new stype[siz]; \
 1.30440 +        cimg::fread(buffer,siz,nfile); \
 1.30441 +        if (endian) cimg::invert_endianness(buffer,siz); \
 1.30442 +        T *ptrd = data; \
 1.30443 +        cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
 1.30444 +        buffer-=siz; \
 1.30445 +        delete[] buffer
 1.30446 +
 1.30447 +#define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
 1.30448 +        if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
 1.30449 +        else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
 1.30450 +        else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
 1.30451 +        else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
 1.30452 +                                   pixel_type(),filename?filename:"(FILE*)"); }
 1.30453 +
 1.30454 +      if (!filename && !file)
 1.30455 +        throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
 1.30456 +                                    pixel_type());
 1.30457 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.30458 +      typedef unsigned char uchar;
 1.30459 +      typedef unsigned short ushort;
 1.30460 +      typedef unsigned int uint;
 1.30461 +      typedef unsigned long ulong;
 1.30462 +      char header[32];
 1.30463 +      cimg::fread(header,12,nfile);
 1.30464 +      if (cimg::strncasecmp("PANDORE",header,7)) {
 1.30465 +        if (!file) cimg::fclose(nfile);
 1.30466 +        throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
 1.30467 +                              "(PANDORE identifier not found).",
 1.30468 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30469 +      }
 1.30470 +      unsigned int imageid, dims[8];
 1.30471 +      cimg::fread(&imageid,1,nfile);
 1.30472 +      const bool endian = (imageid>255);
 1.30473 +      if (endian) cimg::invert_endianness(imageid);
 1.30474 +      cimg::fread(header,20,nfile);
 1.30475 +
 1.30476 +      switch (imageid) {
 1.30477 +      case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
 1.30478 +      case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
 1.30479 +      case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
 1.30480 +      case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
 1.30481 +      case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
 1.30482 +      case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
 1.30483 +      case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
 1.30484 +      case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
 1.30485 +      case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
 1.30486 +      case 11 : { // Region 1D
 1.30487 +        cimg::fread(dims,3,nfile);
 1.30488 +        if (endian) cimg::invert_endianness(dims,3);
 1.30489 +        assign(dims[1],1,1,1);
 1.30490 +        const unsigned siz = size();
 1.30491 +        if (dims[2]<256) {
 1.30492 +          unsigned char *buffer = new unsigned char[siz];
 1.30493 +          cimg::fread(buffer,siz,nfile);
 1.30494 +          T *ptrd = data;
 1.30495 +          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30496 +          buffer-=siz;
 1.30497 +          delete[] buffer;
 1.30498 +        } else {
 1.30499 +          if (dims[2]<65536) {
 1.30500 +            unsigned short *buffer = new unsigned short[siz];
 1.30501 +            cimg::fread(buffer,siz,nfile);
 1.30502 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30503 +            T *ptrd = data;
 1.30504 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30505 +            buffer-=siz;
 1.30506 +            delete[] buffer;
 1.30507 +          } else {
 1.30508 +            unsigned int *buffer = new unsigned int[siz];
 1.30509 +            cimg::fread(buffer,siz,nfile);
 1.30510 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30511 +            T *ptrd = data;
 1.30512 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30513 +            buffer-=siz;
 1.30514 +            delete[] buffer;
 1.30515 +          }
 1.30516 +        }
 1.30517 +      }
 1.30518 +        break;
 1.30519 +      case 12 : { // Region 2D
 1.30520 +        cimg::fread(dims,4,nfile);
 1.30521 +        if (endian) cimg::invert_endianness(dims,4);
 1.30522 +        assign(dims[2],dims[1],1,1);
 1.30523 +        const unsigned int siz = size();
 1.30524 +        if (dims[3]<256) {
 1.30525 +          unsigned char *buffer = new unsigned char[siz];
 1.30526 +          cimg::fread(buffer,siz,nfile);
 1.30527 +          T *ptrd = data;
 1.30528 +          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30529 +          buffer-=siz;
 1.30530 +          delete[] buffer;
 1.30531 +        } else {
 1.30532 +          if (dims[3]<65536) {
 1.30533 +            unsigned short *buffer = new unsigned short[siz];
 1.30534 +            cimg::fread(buffer,siz,nfile);
 1.30535 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30536 +            T *ptrd = data;
 1.30537 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30538 +            buffer-=siz;
 1.30539 +            delete[] buffer;
 1.30540 +          } else {
 1.30541 +            unsigned long *buffer = new unsigned long[siz];
 1.30542 +            cimg::fread(buffer,siz,nfile);
 1.30543 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30544 +            T *ptrd = data;
 1.30545 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30546 +            buffer-=siz;
 1.30547 +            delete[] buffer;
 1.30548 +          }
 1.30549 +        }
 1.30550 +      }
 1.30551 +        break;
 1.30552 +      case 13 : { // Region 3D
 1.30553 +        cimg::fread(dims,5,nfile);
 1.30554 +        if (endian) cimg::invert_endianness(dims,5);
 1.30555 +        assign(dims[3],dims[2],dims[1],1);
 1.30556 +        const unsigned int siz = size();
 1.30557 +        if (dims[4]<256) {
 1.30558 +          unsigned char *buffer = new unsigned char[siz];
 1.30559 +          cimg::fread(buffer,siz,nfile);
 1.30560 +          T *ptrd = data;
 1.30561 +          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30562 +          buffer-=siz;
 1.30563 +          delete[] buffer;
 1.30564 +        } else {
 1.30565 +          if (dims[4]<65536) {
 1.30566 +            unsigned short *buffer = new unsigned short[siz];
 1.30567 +            cimg::fread(buffer,siz,nfile);
 1.30568 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30569 +            T *ptrd = data;
 1.30570 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30571 +            buffer-=siz;
 1.30572 +            delete[] buffer;
 1.30573 +          } else {
 1.30574 +            unsigned int *buffer = new unsigned int[siz];
 1.30575 +            cimg::fread(buffer,siz,nfile);
 1.30576 +            if (endian) cimg::invert_endianness(buffer,siz);
 1.30577 +            T *ptrd = data;
 1.30578 +            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
 1.30579 +            buffer-=siz;
 1.30580 +            delete[] buffer;
 1.30581 +          }
 1.30582 +        }
 1.30583 +      }
 1.30584 +        break;
 1.30585 +      case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
 1.30586 +      case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
 1.30587 +      case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
 1.30588 +      case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
 1.30589 +      case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
 1.30590 +      case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
 1.30591 +      case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
 1.30592 +      case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
 1.30593 +      case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
 1.30594 +      case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
 1.30595 +      case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
 1.30596 +      case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
 1.30597 +      case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
 1.30598 +      case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
 1.30599 +      case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
 1.30600 +      case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
 1.30601 +      case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
 1.30602 +      case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
 1.30603 +      case 34 : { // Points 1D
 1.30604 +        int ptbuf[4];
 1.30605 +        cimg::fread(ptbuf,1,nfile);
 1.30606 +        if (endian) cimg::invert_endianness(ptbuf,1);
 1.30607 +        assign(1); (*this)(0) = (T)ptbuf[0];
 1.30608 +      } break;
 1.30609 +      case 35 : { // Points 2D
 1.30610 +        int ptbuf[4];
 1.30611 +        cimg::fread(ptbuf,2,nfile);
 1.30612 +        if (endian) cimg::invert_endianness(ptbuf,2);
 1.30613 +        assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
 1.30614 +      } break;
 1.30615 +      case 36 : { // Points 3D
 1.30616 +        int ptbuf[4];
 1.30617 +        cimg::fread(ptbuf,3,nfile);
 1.30618 +        if (endian) cimg::invert_endianness(ptbuf,3);
 1.30619 +        assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
 1.30620 +      } break;
 1.30621 +      default :
 1.30622 +        if (!file) cimg::fclose(nfile);
 1.30623 +        throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
 1.30624 +                              pixel_type(),filename?filename:"(FILE*)",imageid);
 1.30625 +      }
 1.30626 +      if (!file) cimg::fclose(nfile);
 1.30627 +      return *this;
 1.30628 +    }
 1.30629 +
 1.30630 +    //! Load an image from a PAR-REC (Philips) file.
 1.30631 +    CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
 1.30632 +      CImgList<T> list;
 1.30633 +      list.load_parrec(filename);
 1.30634 +      if (list.size==1) return list[0].transfer_to(*this);
 1.30635 +      return assign(list.get_append(axis,align));
 1.30636 +    }
 1.30637 +
 1.30638 +    static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
 1.30639 +      return CImg<T>().load_parrec(filename,axis,align);
 1.30640 +    }
 1.30641 +
 1.30642 +    //! Load an image from a .RAW file.
 1.30643 +    CImg<T>& load_raw(const char *const filename,
 1.30644 +                      const unsigned int sizex, const unsigned int sizey=1,
 1.30645 +                      const unsigned int sizez=1, const unsigned int sizev=1,
 1.30646 +                      const bool multiplexed=false, const bool invert_endianness=false) {
 1.30647 +      return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 1.30648 +    }
 1.30649 +
 1.30650 +    static CImg<T> get_load_raw(const char *const filename,
 1.30651 +                                const unsigned int sizex, const unsigned int sizey=1,
 1.30652 +                                const unsigned int sizez=1, const unsigned int sizev=1,
 1.30653 +                                const bool multiplexed=false, const bool invert_endianness=false) {
 1.30654 +      return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 1.30655 +    }
 1.30656 +
 1.30657 +    //! Load an image from a .RAW file.
 1.30658 +    CImg<T>& load_raw(cimg_std::FILE *const file,
 1.30659 +                      const unsigned int sizex, const unsigned int sizey=1,
 1.30660 +                      const unsigned int sizez=1, const unsigned int sizev=1,
 1.30661 +                      const bool multiplexed=false, const bool invert_endianness=false) {
 1.30662 +      return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 1.30663 +    }
 1.30664 +
 1.30665 +    static CImg<T> get_load_raw(cimg_std::FILE *const file,
 1.30666 +                                const unsigned int sizex, const unsigned int sizey=1,
 1.30667 +                                const unsigned int sizez=1, const unsigned int sizev=1,
 1.30668 +                                const bool multiplexed=false, const bool invert_endianness=false) {
 1.30669 +      return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 1.30670 +    }
 1.30671 +
 1.30672 +    CImg<T>& _load_raw(cimg_std::FILE *const file, const char *const filename,
 1.30673 +                       const unsigned int sizex, const unsigned int sizey,
 1.30674 +                       const unsigned int sizez, const unsigned int sizev,
 1.30675 +                       const bool multiplexed, const bool invert_endianness) {
 1.30676 +      if (!filename && !file)
 1.30677 +        throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
 1.30678 +                                    pixel_type());
 1.30679 +      assign(sizex,sizey,sizez,sizev,0);
 1.30680 +      const unsigned int siz = size();
 1.30681 +      if (siz) {
 1.30682 +        cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.30683 +        if (!multiplexed) {
 1.30684 +          cimg::fread(data,siz,nfile);
 1.30685 +          if (invert_endianness) cimg::invert_endianness(data,siz);
 1.30686 +        }
 1.30687 +        else {
 1.30688 +          CImg<T> buf(1,1,1,sizev);
 1.30689 +          cimg_forXYZ(*this,x,y,z) {
 1.30690 +            cimg::fread(buf.data,sizev,nfile);
 1.30691 +            if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
 1.30692 +            set_vector_at(buf,x,y,z); }
 1.30693 +        }
 1.30694 +        if (!file) cimg::fclose(nfile);
 1.30695 +      }
 1.30696 +      return *this;
 1.30697 +    }
 1.30698 +
 1.30699 +    //! Load a video sequence using FFMPEG av's libraries.
 1.30700 +    CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30701 +                         const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 1.30702 +                         const char axis='z', const char align='p') {
 1.30703 +      return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
 1.30704 +    }
 1.30705 +
 1.30706 +    static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30707 +                                   const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 1.30708 +                                   const char axis='z', const char align='p') {
 1.30709 +      return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
 1.30710 +    }
 1.30711 +
 1.30712 +    //! Load an image sequence from a YUV file.
 1.30713 +    CImg<T>& load_yuv(const char *const filename,
 1.30714 +                      const unsigned int sizex, const unsigned int sizey=1,
 1.30715 +                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30716 +                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 1.30717 +      return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 1.30718 +    }
 1.30719 +
 1.30720 +    static CImg<T> get_load_yuv(const char *const filename,
 1.30721 +                                const unsigned int sizex, const unsigned int sizey=1,
 1.30722 +                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30723 +                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 1.30724 +      return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 1.30725 +    }
 1.30726 +
 1.30727 +    //! Load an image sequence from a YUV file.
 1.30728 +    CImg<T>& load_yuv(cimg_std::FILE *const file,
 1.30729 +                      const unsigned int sizex, const unsigned int sizey=1,
 1.30730 +                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30731 +                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 1.30732 +      return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 1.30733 +    }
 1.30734 +
 1.30735 +    static CImg<T> get_load_yuv(cimg_std::FILE *const file,
 1.30736 +                                const unsigned int sizex, const unsigned int sizey=1,
 1.30737 +                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.30738 +                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 1.30739 +      return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 1.30740 +    }
 1.30741 +
 1.30742 +    //! Load a 3D object from a .OFF file.
 1.30743 +    template<typename tf, typename tc>
 1.30744 +    CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 1.30745 +      return _load_off(0,filename,primitives,colors,invert_faces);
 1.30746 +    }
 1.30747 +
 1.30748 +    template<typename tf, typename tc>
 1.30749 +    static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
 1.30750 +                                const bool invert_faces=false) {
 1.30751 +      return CImg<T>().load_off(filename,primitives,colors,invert_faces);
 1.30752 +    }
 1.30753 +
 1.30754 +    //! Load a 3D object from a .OFF file.
 1.30755 +    template<typename tf, typename tc>
 1.30756 +    CImg<T>& load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 1.30757 +      return _load_off(file,0,primitives,colors,invert_faces);
 1.30758 +    }
 1.30759 +
 1.30760 +    template<typename tf, typename tc>
 1.30761 +    static CImg<T> get_load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
 1.30762 +                                const bool invert_faces=false) {
 1.30763 +      return CImg<T>().load_off(file,primitives,colors,invert_faces);
 1.30764 +    }
 1.30765 +
 1.30766 +    template<typename tf, typename tc>
 1.30767 +    CImg<T>& _load_off(cimg_std::FILE *const file, const char *const filename,
 1.30768 +                       CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
 1.30769 +      if (!filename && !file)
 1.30770 +        throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
 1.30771 +                                    pixel_type());
 1.30772 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
 1.30773 +      unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
 1.30774 +      char line[256] = { 0 };
 1.30775 +      int err;
 1.30776 +
 1.30777 +      // Skip comments, and read magic string OFF
 1.30778 +      do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 1.30779 +      if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
 1.30780 +        if (!file) cimg::fclose(nfile);
 1.30781 +        throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
 1.30782 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30783 +      }
 1.30784 +      do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 1.30785 +      if ((err = cimg_std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
 1.30786 +        if (!file) cimg::fclose(nfile);
 1.30787 +        throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
 1.30788 +                              pixel_type(),filename?filename:"(FILE*)");
 1.30789 +      }
 1.30790 +
 1.30791 +      // Read points data
 1.30792 +      assign(nb_points,3);
 1.30793 +      float X = 0, Y = 0, Z = 0;
 1.30794 +      cimg_forX(*this,l) {
 1.30795 +        do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 1.30796 +        if ((err = cimg_std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
 1.30797 +          if (!file) cimg::fclose(nfile);
 1.30798 +          throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
 1.30799 +                                pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
 1.30800 +        }
 1.30801 +        (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
 1.30802 +      }
 1.30803 +
 1.30804 +      // Read primitive data
 1.30805 +      primitives.assign();
 1.30806 +      colors.assign();
 1.30807 +      bool stopflag = false;
 1.30808 +      while (!stopflag) {
 1.30809 +        float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
 1.30810 +        unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
 1.30811 +        line[0]='\0';
 1.30812 +        if ((err = cimg_std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
 1.30813 +        else {
 1.30814 +          ++nb_read;
 1.30815 +          switch (prim) {
 1.30816 +          case 1 : {
 1.30817 +            if ((err = cimg_std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
 1.30818 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30819 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30820 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30821 +            } else {
 1.30822 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30823 +              primitives.insert(CImg<tf>::vector(i0));
 1.30824 +              colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 1.30825 +            }
 1.30826 +          } break;
 1.30827 +          case 2 : {
 1.30828 +            if ((err = cimg_std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
 1.30829 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30830 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30831 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30832 +            } else {
 1.30833 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30834 +              primitives.insert(CImg<tf>::vector(i0,i1));
 1.30835 +              colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 1.30836 +            }
 1.30837 +          } break;
 1.30838 +          case 3 : {
 1.30839 +            if ((err = cimg_std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
 1.30840 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30841 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30842 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30843 +            } else {
 1.30844 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30845 +              if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
 1.30846 +              else primitives.insert(CImg<tf>::vector(i0,i2,i1));
 1.30847 +              colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
 1.30848 +            }
 1.30849 +          } break;
 1.30850 +          case 4 : {
 1.30851 +            if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
 1.30852 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30853 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30854 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30855 +            } else {
 1.30856 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30857 +              if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 1.30858 +              else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 1.30859 +              colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 1.30860 +            }
 1.30861 +          } break;
 1.30862 +          case 5 : {
 1.30863 +            if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
 1.30864 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30865 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30866 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30867 +            } else {
 1.30868 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30869 +              if (invert_faces) {
 1.30870 +                primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 1.30871 +                primitives.insert(CImg<tf>::vector(i0,i3,i4));
 1.30872 +              }
 1.30873 +              else {
 1.30874 +                primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 1.30875 +                primitives.insert(CImg<tf>::vector(i0,i4,i3));
 1.30876 +              }
 1.30877 +              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 1.30878 +              ++nb_primitives;
 1.30879 +            }
 1.30880 +          } break;
 1.30881 +          case 6 : {
 1.30882 +            if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
 1.30883 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30884 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30885 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30886 +            } else {
 1.30887 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30888 +              if (invert_faces) {
 1.30889 +                primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 1.30890 +                primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
 1.30891 +              }
 1.30892 +              else {
 1.30893 +                primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 1.30894 +                primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
 1.30895 +              }
 1.30896 +              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 1.30897 +              ++nb_primitives;
 1.30898 +            }
 1.30899 +          } break;
 1.30900 +          case 7 : {
 1.30901 +            if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
 1.30902 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30903 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30904 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30905 +            } else {
 1.30906 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30907 +              if (invert_faces) {
 1.30908 +                primitives.insert(CImg<tf>::vector(i0,i1,i3,i4));
 1.30909 +                primitives.insert(CImg<tf>::vector(i0,i4,i5,i6));
 1.30910 +                primitives.insert(CImg<tf>::vector(i1,i2,i3));
 1.30911 +              }
 1.30912 +              else {
 1.30913 +                primitives.insert(CImg<tf>::vector(i0,i4,i3,i1));
 1.30914 +                primitives.insert(CImg<tf>::vector(i0,i6,i5,i4));
 1.30915 +                primitives.insert(CImg<tf>::vector(i3,i2,i1));
 1.30916 +              }
 1.30917 +              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 1.30918 +              ++(++nb_primitives);
 1.30919 +            }
 1.30920 +          } break;
 1.30921 +          case 8 : {
 1.30922 +            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) {
 1.30923 +              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
 1.30924 +                         pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
 1.30925 +              err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30926 +            } else {
 1.30927 +              err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
 1.30928 +              if (invert_faces) {
 1.30929 +                primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
 1.30930 +                primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
 1.30931 +                primitives.insert(CImg<tf>::vector(i0,i5,i6,i7));
 1.30932 +              }
 1.30933 +              else {
 1.30934 +                primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
 1.30935 +                primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
 1.30936 +                primitives.insert(CImg<tf>::vector(i0,i7,i6,i5));
 1.30937 +              }
 1.30938 +              colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
 1.30939 +              ++(++nb_primitives);
 1.30940 +            }
 1.30941 +          } break;
 1.30942 +          default :
 1.30943 +            cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
 1.30944 +                       pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
 1.30945 +            err = cimg_std::fscanf(nfile,"%*[^\n] ");
 1.30946 +          }
 1.30947 +        }
 1.30948 +      }
 1.30949 +      if (!file) cimg::fclose(nfile);
 1.30950 +      if (primitives.size!=nb_primitives)
 1.30951 +        cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
 1.30952 +                   pixel_type(),filename?filename:"(FILE*)",primitives.size,nb_primitives);
 1.30953 +      return *this;
 1.30954 +    }
 1.30955 +
 1.30956 +    //! Load a video sequence using FFMPEG's external tool 'ffmpeg'.
 1.30957 +    CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 1.30958 +      return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
 1.30959 +    }
 1.30960 +
 1.30961 +    static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 1.30962 +      return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
 1.30963 +    }
 1.30964 +
 1.30965 +    //! Load an image using GraphicsMagick's external tool 'gm'.
 1.30966 +    CImg<T>& load_graphicsmagick_external(const char *const filename) {
 1.30967 +      if (!filename)
 1.30968 +        throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
 1.30969 +                                    pixel_type());
 1.30970 +      char command[1024], filetmp[512];
 1.30971 +      cimg_std::FILE *file = 0;
 1.30972 +#if cimg_OS==1
 1.30973 +      cimg_std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
 1.30974 +      file = popen(command,"r");
 1.30975 +      if (file) { load_pnm(file); pclose(file); return *this; }
 1.30976 +#endif
 1.30977 +      do {
 1.30978 +        cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.30979 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.30980 +      } while (file);
 1.30981 +      cimg_std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
 1.30982 +      cimg::system(command,cimg::graphicsmagick_path());
 1.30983 +      if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 1.30984 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.30985 +        throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
 1.30986 +                              "Path of 'GraphicsMagick's gm' : \"%s\"\n"
 1.30987 +                              "Path of temporary filename : \"%s\"",
 1.30988 +                              pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 1.30989 +      } else cimg::fclose(file);
 1.30990 +      load_pnm(filetmp);
 1.30991 +      cimg_std::remove(filetmp);
 1.30992 +      return *this;
 1.30993 +    }
 1.30994 +
 1.30995 +    static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
 1.30996 +      return CImg<T>().load_graphicsmagick_external(filename);
 1.30997 +    }
 1.30998 +
 1.30999 +    //! Load a gzipped image file, using external tool 'gunzip'.
 1.31000 +    CImg<T>& load_gzip_external(const char *const filename) {
 1.31001 +      if (!filename)
 1.31002 +        throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
 1.31003 +                              pixel_type());
 1.31004 +      char command[1024], filetmp[512], body[512];
 1.31005 +      const char
 1.31006 +        *ext = cimg::split_filename(filename,body),
 1.31007 +        *ext2 = cimg::split_filename(body,0);
 1.31008 +      cimg_std::FILE *file = 0;
 1.31009 +      do {
 1.31010 +        if (!cimg::strcasecmp(ext,"gz")) {
 1.31011 +          if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.31012 +                                  cimg::filenamerand(),ext2);
 1.31013 +          else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.31014 +                                  cimg::filenamerand());
 1.31015 +        } else {
 1.31016 +           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.31017 +                                  cimg::filenamerand(),ext);
 1.31018 +           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.31019 +                             cimg::filenamerand());
 1.31020 +        }
 1.31021 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.31022 +      } while (file);
 1.31023 +      cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 1.31024 +      cimg::system(command);
 1.31025 +      if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 1.31026 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.31027 +        throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
 1.31028 +                              pixel_type(),filename);
 1.31029 +      } else cimg::fclose(file);
 1.31030 +      load(filetmp);
 1.31031 +      cimg_std::remove(filetmp);
 1.31032 +      return *this;
 1.31033 +    }
 1.31034 +
 1.31035 +    static CImg<T> get_load_gzip_external(const char *const filename) {
 1.31036 +      return CImg<T>().load_gzip_external(filename);
 1.31037 +    }
 1.31038 +
 1.31039 +    //! Load an image using ImageMagick's external tool 'convert'.
 1.31040 +    CImg<T>& load_imagemagick_external(const char *const filename) {
 1.31041 +      if (!filename)
 1.31042 +        throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
 1.31043 +                                    pixel_type());
 1.31044 +      char command[1024], filetmp[512];
 1.31045 +      cimg_std::FILE *file = 0;
 1.31046 +#if cimg_OS==1
 1.31047 +      cimg_std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
 1.31048 +      file = popen(command,"r");
 1.31049 +      if (file) { load_pnm(file); pclose(file); return *this; }
 1.31050 +#endif
 1.31051 +      do {
 1.31052 +        cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.31053 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.31054 +      } while (file);
 1.31055 +      cimg_std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
 1.31056 +      cimg::system(command,cimg::imagemagick_path());
 1.31057 +      if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 1.31058 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.31059 +        throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
 1.31060 +                              "Path of 'ImageMagick's convert' : \"%s\"\n"
 1.31061 +                              "Path of temporary filename : \"%s\"",
 1.31062 +                              pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 1.31063 +      } else cimg::fclose(file);
 1.31064 +      load_pnm(filetmp);
 1.31065 +      cimg_std::remove(filetmp);
 1.31066 +      return *this;
 1.31067 +    }
 1.31068 +
 1.31069 +    static CImg<T> get_load_imagemagick_external(const char *const filename) {
 1.31070 +      return CImg<T>().load_imagemagick_external(filename);
 1.31071 +    }
 1.31072 +
 1.31073 +    //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
 1.31074 +    CImg<T>& load_medcon_external(const char *const filename) {
 1.31075 +      if (!filename)
 1.31076 +        throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
 1.31077 +                                    pixel_type());
 1.31078 +      char command[1024], filetmp[512], body[512];
 1.31079 +      cimg::fclose(cimg::fopen(filename,"r"));
 1.31080 +      cimg_std::FILE *file = 0;
 1.31081 +      do {
 1.31082 +        cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
 1.31083 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.31084 +      } while (file);
 1.31085 +      cimg_std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
 1.31086 +      cimg::system(command);
 1.31087 +      cimg::split_filename(filetmp,body);
 1.31088 +      cimg_std::sprintf(command,"m000-%s.hdr",body);
 1.31089 +      file = cimg_std::fopen(command,"rb");
 1.31090 +      if (!file) {
 1.31091 +        throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
 1.31092 +                              "Path of 'medcon' : \"%s\"\n"
 1.31093 +                              "Path of temporary filename : \"%s\"",
 1.31094 +                              pixel_type(),filename,cimg::medcon_path(),filetmp);
 1.31095 +      } else cimg::fclose(file);
 1.31096 +      load_analyze(command);
 1.31097 +      cimg_std::remove(command);
 1.31098 +      cimg_std::sprintf(command,"m000-%s.img",body);
 1.31099 +      cimg_std::remove(command);
 1.31100 +      return *this;
 1.31101 +    }
 1.31102 +
 1.31103 +    static CImg<T> get_load_medcon_external(const char *const filename) {
 1.31104 +      return CImg<T>().load_medcon_external(filename);
 1.31105 +    }
 1.31106 +
 1.31107 +    //! Load a RAW Color Camera image file, using external tool 'dcraw'.
 1.31108 +    CImg<T>& load_dcraw_external(const char *const filename) {
 1.31109 +      if (!filename)
 1.31110 +        throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
 1.31111 +                                    pixel_type());
 1.31112 +      char command[1024], filetmp[512];
 1.31113 +      cimg_std::FILE *file = 0;
 1.31114 +#if cimg_OS==1
 1.31115 +      cimg_std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
 1.31116 +      file = popen(command,"r");
 1.31117 +      if (file) { load_pnm(file); pclose(file); return *this; }
 1.31118 +#endif
 1.31119 +      do {
 1.31120 +        cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.31121 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.31122 +      } while (file);
 1.31123 +      cimg_std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
 1.31124 +      cimg::system(command,cimg::dcraw_path());
 1.31125 +      if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 1.31126 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.31127 +        throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
 1.31128 +                              "Path of 'dcraw' : \"%s\"\n"
 1.31129 +                              "Path of temporary filename : \"%s\"",
 1.31130 +                              pixel_type(),filename,cimg::dcraw_path(),filetmp);
 1.31131 +      } else cimg::fclose(file);
 1.31132 +      load_pnm(filetmp);
 1.31133 +      cimg_std::remove(filetmp);
 1.31134 +      return *this;
 1.31135 +    }
 1.31136 +
 1.31137 +    static CImg<T> get_load_dcraw_external(const char *const filename) {
 1.31138 +      return CImg<T>().load_dcraw_external(filename);
 1.31139 +    }
 1.31140 +
 1.31141 +    //! Load an image using ImageMagick's or GraphicsMagick's executables.
 1.31142 +    CImg<T>& load_other(const char *const filename) {
 1.31143 +      if (!filename)
 1.31144 +        throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
 1.31145 +                                    pixel_type());
 1.31146 +      const unsigned int odebug = cimg::exception_mode();
 1.31147 +      cimg::exception_mode() = 0;
 1.31148 +      try { load_magick(filename); }
 1.31149 +      catch (CImgException&) {
 1.31150 +        try { load_imagemagick_external(filename); }
 1.31151 +        catch (CImgException&) {
 1.31152 +          try { load_graphicsmagick_external(filename); }
 1.31153 +          catch (CImgException&) {
 1.31154 +            assign();
 1.31155 +          }
 1.31156 +        }
 1.31157 +      }
 1.31158 +      cimg::exception_mode() = odebug;
 1.31159 +      if (is_empty())
 1.31160 +        throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
 1.31161 +                              pixel_type(),filename);
 1.31162 +      return *this;
 1.31163 +    }
 1.31164 +
 1.31165 +    static CImg<T> get_load_other(const char *const filename) {
 1.31166 +      return CImg<T>().load_other(filename);
 1.31167 +    }
 1.31168 +
 1.31169 +    //@}
 1.31170 +    //---------------------------
 1.31171 +    //
 1.31172 +    //! \name Image File Saving
 1.31173 +    //@{
 1.31174 +    //---------------------------
 1.31175 +
 1.31176 +    //! Save the image as a file.
 1.31177 +    /**
 1.31178 +       The used file format is defined by the file extension in the filename \p filename.
 1.31179 +       Parameter \p number can be used to add a 6-digit number to the filename before saving.
 1.31180 +    **/
 1.31181 +    const CImg<T>& save(const char *const filename, const int number=-1) const {
 1.31182 +      if (is_empty())
 1.31183 +        throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31184 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.31185 +      if (!filename)
 1.31186 +        throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
 1.31187 +                                    pixel_type(),width,height,depth,dim,data);
 1.31188 +      const char *ext = cimg::split_filename(filename);
 1.31189 +      char nfilename[1024];
 1.31190 +      const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
 1.31191 +#ifdef cimg_save_plugin
 1.31192 +      cimg_save_plugin(fn);
 1.31193 +#endif
 1.31194 +#ifdef cimg_save_plugin1
 1.31195 +      cimg_save_plugin1(fn);
 1.31196 +#endif
 1.31197 +#ifdef cimg_save_plugin2
 1.31198 +      cimg_save_plugin2(fn);
 1.31199 +#endif
 1.31200 +#ifdef cimg_save_plugin3
 1.31201 +      cimg_save_plugin3(fn);
 1.31202 +#endif
 1.31203 +#ifdef cimg_save_plugin4
 1.31204 +      cimg_save_plugin4(fn);
 1.31205 +#endif
 1.31206 +#ifdef cimg_save_plugin5
 1.31207 +      cimg_save_plugin5(fn);
 1.31208 +#endif
 1.31209 +#ifdef cimg_save_plugin6
 1.31210 +      cimg_save_plugin6(fn);
 1.31211 +#endif
 1.31212 +#ifdef cimg_save_plugin7
 1.31213 +      cimg_save_plugin7(fn);
 1.31214 +#endif
 1.31215 +#ifdef cimg_save_plugin8
 1.31216 +      cimg_save_plugin8(fn);
 1.31217 +#endif
 1.31218 +      // ASCII formats
 1.31219 +      if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
 1.31220 +      if (!cimg::strcasecmp(ext,"dlm") ||
 1.31221 +          !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
 1.31222 +      if (!cimg::strcasecmp(ext,"cpp") ||
 1.31223 +          !cimg::strcasecmp(ext,"hpp") ||
 1.31224 +          !cimg::strcasecmp(ext,"h") ||
 1.31225 +          !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
 1.31226 +
 1.31227 +      // 2D binary formats
 1.31228 +      if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
 1.31229 +      if (!cimg::strcasecmp(ext,"jpg") ||
 1.31230 +          !cimg::strcasecmp(ext,"jpeg") ||
 1.31231 +          !cimg::strcasecmp(ext,"jpe") ||
 1.31232 +          !cimg::strcasecmp(ext,"jfif") ||
 1.31233 +          !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
 1.31234 +      if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
 1.31235 +      if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
 1.31236 +      if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
 1.31237 +      if (!cimg::strcasecmp(ext,"pgm") ||
 1.31238 +          !cimg::strcasecmp(ext,"ppm") ||
 1.31239 +          !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
 1.31240 +      if (!cimg::strcasecmp(ext,"tif") ||
 1.31241 +          !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
 1.31242 +
 1.31243 +      // 3D binary formats
 1.31244 +      if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 1.31245 +      if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
 1.31246 +      if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
 1.31247 +      if (!cimg::strcasecmp(ext,"hdr") ||
 1.31248 +          !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
 1.31249 +      if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
 1.31250 +      if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
 1.31251 +      if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
 1.31252 +
 1.31253 +      // Archive files
 1.31254 +      if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 1.31255 +
 1.31256 +      // Image sequences
 1.31257 +      if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 1.31258 +      if (!cimg::strcasecmp(ext,"avi") ||
 1.31259 +          !cimg::strcasecmp(ext,"mov") ||
 1.31260 +          !cimg::strcasecmp(ext,"asf") ||
 1.31261 +          !cimg::strcasecmp(ext,"divx") ||
 1.31262 +          !cimg::strcasecmp(ext,"flv") ||
 1.31263 +          !cimg::strcasecmp(ext,"mpg") ||
 1.31264 +          !cimg::strcasecmp(ext,"m1v") ||
 1.31265 +          !cimg::strcasecmp(ext,"m2v") ||
 1.31266 +          !cimg::strcasecmp(ext,"m4v") ||
 1.31267 +          !cimg::strcasecmp(ext,"mjp") ||
 1.31268 +          !cimg::strcasecmp(ext,"mkv") ||
 1.31269 +          !cimg::strcasecmp(ext,"mpe") ||
 1.31270 +          !cimg::strcasecmp(ext,"movie") ||
 1.31271 +          !cimg::strcasecmp(ext,"ogm") ||
 1.31272 +          !cimg::strcasecmp(ext,"qt") ||
 1.31273 +          !cimg::strcasecmp(ext,"rm") ||
 1.31274 +          !cimg::strcasecmp(ext,"vob") ||
 1.31275 +          !cimg::strcasecmp(ext,"wmv") ||
 1.31276 +          !cimg::strcasecmp(ext,"xvid") ||
 1.31277 +          !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
 1.31278 +      return save_other(fn);
 1.31279 +    }
 1.31280 +
 1.31281 +    // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
 1.31282 +    const CImg<T>& _save_ascii(cimg_std::FILE *const file, const char *const filename) const {
 1.31283 +      if (is_empty())
 1.31284 +        throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31285 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31286 +      if (!file && !filename)
 1.31287 +        throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31288 +                                    pixel_type(),width,height,depth,dim,data);
 1.31289 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 1.31290 +      cimg_std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
 1.31291 +      const T* ptrs = data;
 1.31292 +      cimg_forYZV(*this,y,z,v) {
 1.31293 +        cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g ",(double)*(ptrs++));
 1.31294 +        cimg_std::fputc('\n',nfile);
 1.31295 +      }
 1.31296 +      if (!file) cimg::fclose(nfile);
 1.31297 +      return *this;
 1.31298 +    }
 1.31299 +
 1.31300 +    //! Save the image as an ASCII file (ASCII Raw + simple header).
 1.31301 +    const CImg<T>& save_ascii(const char *const filename) const {
 1.31302 +      return _save_ascii(0,filename);
 1.31303 +    }
 1.31304 +
 1.31305 +    //! Save the image as an ASCII file (ASCII Raw + simple header).
 1.31306 +    const CImg<T>& save_ascii(cimg_std::FILE *const file) const {
 1.31307 +      return _save_ascii(file,0);
 1.31308 +    }
 1.31309 +
 1.31310 +    // Save the image as a C or CPP source file (internal).
 1.31311 +    const CImg<T>& _save_cpp(cimg_std::FILE *const file, const char *const filename) const {
 1.31312 +      if (!file && !filename)
 1.31313 +        throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31314 +                                    pixel_type(),width,height,depth,dim,data);
 1.31315 +      if (is_empty())
 1.31316 +        throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31317 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31318 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 1.31319 +      char varname[1024] = { 0 };
 1.31320 +      if (filename) cimg_std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
 1.31321 +      if (varname[0]=='\0') cimg_std::sprintf(varname,"unnamed");
 1.31322 +      cimg_std::fprintf(nfile,
 1.31323 +                   "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
 1.31324 +                   "%s data_%s[] = { \n  ",
 1.31325 +                   varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
 1.31326 +      for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
 1.31327 +        cimg_std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
 1.31328 +        if (off==siz) cimg_std::fprintf(nfile," };\n");
 1.31329 +        else if (!((off+1)%16)) cimg_std::fprintf(nfile,",\n  ");
 1.31330 +        else cimg_std::fprintf(nfile,", ");
 1.31331 +      }
 1.31332 +      if (!file) cimg::fclose(nfile);
 1.31333 +      return *this;
 1.31334 +    }
 1.31335 +
 1.31336 +    //! Save the image as a CPP source file.
 1.31337 +    const CImg<T>& save_cpp(const char *const filename) const {
 1.31338 +      return _save_cpp(0,filename);
 1.31339 +    }
 1.31340 +
 1.31341 +    //! Save the image as a CPP source file.
 1.31342 +    const CImg<T>& save_cpp(cimg_std::FILE *const file) const {
 1.31343 +      return _save_cpp(file,0);
 1.31344 +    }
 1.31345 +
 1.31346 +    // Save the image as a DLM file (internal).
 1.31347 +    const CImg<T>& _save_dlm(cimg_std::FILE *const file, const char *const filename) const {
 1.31348 +      if (is_empty())
 1.31349 +        throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31350 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31351 +      if (!file && !filename)
 1.31352 +        throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31353 +                                    pixel_type(),width,height,depth,dim,data);
 1.31354 +      if (depth>1)
 1.31355 +        cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
 1.31356 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31357 +      if (dim>1)
 1.31358 +        cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
 1.31359 +                   "Pixel values along V will be unrolled.",
 1.31360 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31361 +
 1.31362 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 1.31363 +      const T* ptrs = data;
 1.31364 +      cimg_forYZV(*this,y,z,v) {
 1.31365 +        cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
 1.31366 +        cimg_std::fputc('\n',nfile);
 1.31367 +      }
 1.31368 +      if (!file) cimg::fclose(nfile);
 1.31369 +      return *this;
 1.31370 +    }
 1.31371 +
 1.31372 +    //! Save the image as a DLM file.
 1.31373 +    const CImg<T>& save_dlm(const char *const filename) const {
 1.31374 +      return _save_dlm(0,filename);
 1.31375 +    }
 1.31376 +
 1.31377 +    //! Save the image as a DLM file.
 1.31378 +    const CImg<T>& save_dlm(cimg_std::FILE *const file) const {
 1.31379 +      return _save_dlm(file,0);
 1.31380 +    }
 1.31381 +
 1.31382 +   // Save the image as a BMP file (internal).
 1.31383 +    const CImg<T>& _save_bmp(cimg_std::FILE *const file, const char *const filename) const {
 1.31384 +      if (is_empty())
 1.31385 +        throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31386 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31387 +      if (!file && !filename)
 1.31388 +        throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31389 +                                    pixel_type(),width,height,depth,dim,data);
 1.31390 +      if (depth>1)
 1.31391 +        cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 1.31392 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31393 +      if (dim>3)
 1.31394 +        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.",
 1.31395 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31396 +
 1.31397 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.31398 +      unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
 1.31399 +      const unsigned int
 1.31400 +        align = (4 - (3*width)%4)%4,
 1.31401 +        buf_size = (3*width+align)*dimy(),
 1.31402 +        file_size = 54 + buf_size;
 1.31403 +      header[0] = 'B'; header[1] = 'M';
 1.31404 +      header[0x02] = file_size&0xFF;
 1.31405 +      header[0x03] = (file_size>>8)&0xFF;
 1.31406 +      header[0x04] = (file_size>>16)&0xFF;
 1.31407 +      header[0x05] = (file_size>>24)&0xFF;
 1.31408 +      header[0x0A] = 0x36;
 1.31409 +      header[0x0E] = 0x28;
 1.31410 +      header[0x12] = width&0xFF;
 1.31411 +      header[0x13] = (width>>8)&0xFF;
 1.31412 +      header[0x14] = (width>>16)&0xFF;
 1.31413 +      header[0x15] = (width>>24)&0xFF;
 1.31414 +      header[0x16] = height&0xFF;
 1.31415 +      header[0x17] = (height>>8)&0xFF;
 1.31416 +      header[0x18] = (height>>16)&0xFF;
 1.31417 +      header[0x19] = (height>>24)&0xFF;
 1.31418 +      header[0x1A] = 1;
 1.31419 +      header[0x1B] = 0;
 1.31420 +      header[0x1C] = 24;
 1.31421 +      header[0x1D] = 0;
 1.31422 +      header[0x22] = buf_size&0xFF;
 1.31423 +      header[0x23] = (buf_size>>8)&0xFF;
 1.31424 +      header[0x24] = (buf_size>>16)&0xFF;
 1.31425 +      header[0x25] = (buf_size>>24)&0xFF;
 1.31426 +      header[0x27] = 0x1;
 1.31427 +      header[0x2B] = 0x1;
 1.31428 +      cimg::fwrite(header,54,nfile);
 1.31429 +
 1.31430 +      const T
 1.31431 +        *pR = ptr(0,height-1,0,0),
 1.31432 +        *pG = (dim>=2)?ptr(0,height-1,0,1):0,
 1.31433 +        *pB = (dim>=3)?ptr(0,height-1,0,2):0;
 1.31434 +
 1.31435 +      switch (dim) {
 1.31436 +      case 1 : {
 1.31437 +        cimg_forY(*this,y) { cimg_forX(*this,x) {
 1.31438 +          const unsigned char val = (unsigned char)*(pR++);
 1.31439 +          cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile);
 1.31440 +        }
 1.31441 +        cimg::fwrite(align_buf,align,nfile);
 1.31442 +        pR-=2*width;
 1.31443 +        }} break;
 1.31444 +      case 2 : {
 1.31445 +        cimg_forY(*this,y) { cimg_forX(*this,x) {
 1.31446 +          cimg_std::fputc(0,nfile);
 1.31447 +          cimg_std::fputc((unsigned char)(*(pG++)),nfile);
 1.31448 +          cimg_std::fputc((unsigned char)(*(pR++)),nfile);
 1.31449 +        }
 1.31450 +        cimg::fwrite(align_buf,align,nfile);
 1.31451 +        pR-=2*width; pG-=2*width;
 1.31452 +        }} break;
 1.31453 +      default : {
 1.31454 +        cimg_forY(*this,y) { cimg_forX(*this,x) {
 1.31455 +          cimg_std::fputc((unsigned char)(*(pB++)),nfile);
 1.31456 +          cimg_std::fputc((unsigned char)(*(pG++)),nfile);
 1.31457 +          cimg_std::fputc((unsigned char)(*(pR++)),nfile);
 1.31458 +        }
 1.31459 +        cimg::fwrite(align_buf,align,nfile);
 1.31460 +        pR-=2*width; pG-=2*width; pB-=2*width;
 1.31461 +        }
 1.31462 +      }
 1.31463 +      }
 1.31464 +      if (!file) cimg::fclose(nfile);
 1.31465 +      return *this;
 1.31466 +    }
 1.31467 +
 1.31468 +    //! Save the image as a BMP file.
 1.31469 +    const CImg<T>& save_bmp(const char *const filename) const {
 1.31470 +      return _save_bmp(0,filename);
 1.31471 +    }
 1.31472 +
 1.31473 +    //! Save the image as a BMP file.
 1.31474 +    const CImg<T>& save_bmp(cimg_std::FILE *const file) const {
 1.31475 +      return _save_bmp(file,0);
 1.31476 +    }
 1.31477 +
 1.31478 +    // Save a file in JPEG format (internal).
 1.31479 +    const CImg<T>& _save_jpeg(cimg_std::FILE *const file, const char *const filename, const unsigned int quality) const {
 1.31480 +      if (is_empty())
 1.31481 +        throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31482 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31483 +      if (!file && !filename)
 1.31484 +        throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.31485 +                                    pixel_type(),width,height,depth,dim,data);
 1.31486 +      if (depth>1)
 1.31487 +        cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 1.31488 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31489 +#ifndef cimg_use_jpeg
 1.31490 +      if (!file) return save_other(filename,quality);
 1.31491 +      else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
 1.31492 +                                 pixel_type());
 1.31493 +#else
 1.31494 +      // Fill pixel buffer
 1.31495 +      unsigned char *buf;
 1.31496 +      unsigned int dimbuf = 0;
 1.31497 +      J_COLOR_SPACE colortype = JCS_RGB;
 1.31498 +      switch (dim) {
 1.31499 +      case 1 : { // Greyscale images
 1.31500 +        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
 1.31501 +        colortype = JCS_GRAYSCALE;
 1.31502 +        const T *ptr_g = data;
 1.31503 +        cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
 1.31504 +      } break;
 1.31505 +      case 2 : { // RG images
 1.31506 +        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 1.31507 +        const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
 1.31508 +        colortype = JCS_RGB;
 1.31509 +        cimg_forXY(*this,x,y) {
 1.31510 +          *(buf2++) = (unsigned char)*(ptr_r++);
 1.31511 +          *(buf2++) = (unsigned char)*(ptr_g++);
 1.31512 +          *(buf2++) = 0;
 1.31513 +        }
 1.31514 +      } break;
 1.31515 +      case 3 : { // RGB images
 1.31516 +        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 1.31517 +        const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 1.31518 +        colortype = JCS_RGB;
 1.31519 +        cimg_forXY(*this,x,y) {
 1.31520 +          *(buf2++) = (unsigned char)*(ptr_r++);
 1.31521 +          *(buf2++) = (unsigned char)*(ptr_g++);
 1.31522 +          *(buf2++) = (unsigned char)*(ptr_b++);
 1.31523 +        }
 1.31524 +      } break;
 1.31525 +      default : { // CMYK images
 1.31526 +        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
 1.31527 +        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);
 1.31528 +        colortype = JCS_CMYK;
 1.31529 +        cimg_forXY(*this,x,y) {
 1.31530 +          *(buf2++) = (unsigned char)*(ptr_r++);
 1.31531 +          *(buf2++) = (unsigned char)*(ptr_g++);
 1.31532 +          *(buf2++) = (unsigned char)*(ptr_b++);
 1.31533 +          *(buf2++) = (unsigned char)*(ptr_a++);
 1.31534 +        }
 1.31535 +      }
 1.31536 +      }
 1.31537 +
 1.31538 +      // Call libjpeg functions
 1.31539 +      struct jpeg_compress_struct cinfo;
 1.31540 +      struct jpeg_error_mgr jerr;
 1.31541 +      cinfo.err = jpeg_std_error(&jerr);
 1.31542 +      jpeg_create_compress(&cinfo);
 1.31543 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.31544 +      jpeg_stdio_dest(&cinfo,nfile);
 1.31545 +      cinfo.image_width = width;
 1.31546 +      cinfo.image_height = height;
 1.31547 +      cinfo.input_components = dimbuf;
 1.31548 +      cinfo.in_color_space = colortype;
 1.31549 +      jpeg_set_defaults(&cinfo);
 1.31550 +      jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
 1.31551 +      jpeg_start_compress(&cinfo,TRUE);
 1.31552 +
 1.31553 +      const unsigned int row_stride = width*dimbuf;
 1.31554 +      JSAMPROW row_pointer[1];
 1.31555 +      while (cinfo.next_scanline < cinfo.image_height) {
 1.31556 +        row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
 1.31557 +        jpeg_write_scanlines(&cinfo,row_pointer,1);
 1.31558 +      }
 1.31559 +      jpeg_finish_compress(&cinfo);
 1.31560 +
 1.31561 +      delete[] buf;
 1.31562 +      if (!file) cimg::fclose(nfile);
 1.31563 +      jpeg_destroy_compress(&cinfo);
 1.31564 +      return *this;
 1.31565 +#endif
 1.31566 +    }
 1.31567 +
 1.31568 +    //! Save a file in JPEG format.
 1.31569 +    const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
 1.31570 +      return _save_jpeg(0,filename,quality);
 1.31571 +    }
 1.31572 +
 1.31573 +    //! Save a file in JPEG format.
 1.31574 +    const CImg<T>& save_jpeg(cimg_std::FILE *const file, const unsigned int quality=100) const {
 1.31575 +      return _save_jpeg(file,0,quality);
 1.31576 +    }
 1.31577 +
 1.31578 +    //! Save the image using built-in ImageMagick++ library.
 1.31579 +    const CImg<T>& save_magick(const char *const filename) const {
 1.31580 +      if (is_empty())
 1.31581 +        throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31582 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.31583 +      if (!filename)
 1.31584 +        throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31585 +                                    pixel_type(),width,height,depth,dim,data);
 1.31586 +#ifdef cimg_use_magick
 1.31587 +      Magick::Image image(Magick::Geometry(width,height),"black");
 1.31588 +      image.type(Magick::TrueColorType);
 1.31589 +      const T
 1.31590 +        *rdata = ptr(0,0,0,0),
 1.31591 +        *gdata = dim>1?ptr(0,0,0,1):0,
 1.31592 +        *bdata = dim>2?ptr(0,0,0,2):0;
 1.31593 +      Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
 1.31594 +      switch (dim) {
 1.31595 +      case 1 : // Scalar images
 1.31596 +        for (unsigned int off = width*height; off; --off) {
 1.31597 +          pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 1.31598 +          ++pixels;
 1.31599 +        }
 1.31600 +        break;
 1.31601 +      case 2 : // RG images
 1.31602 +        for (unsigned int off = width*height; off; --off) {
 1.31603 +          pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 1.31604 +          pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 1.31605 +          pixels->blue = 0;
 1.31606 +          ++pixels;
 1.31607 +        }
 1.31608 +        break;
 1.31609 +      default : // RGB images
 1.31610 +        for (unsigned int off = width*height; off; --off) {
 1.31611 +          pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 1.31612 +          pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 1.31613 +          pixels->blue = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
 1.31614 +          ++pixels;
 1.31615 +        }
 1.31616 +      }
 1.31617 +      image.syncPixels();
 1.31618 +      image.write(filename);
 1.31619 +#else
 1.31620 +      throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
 1.31621 +                            pixel_type(),filename);
 1.31622 +#endif
 1.31623 +      return *this;
 1.31624 +    }
 1.31625 +
 1.31626 +    // Save an image to a PNG file (internal).
 1.31627 +    // Most of this function has been written by Eric Fausett
 1.31628 +    const CImg<T>& _save_png(cimg_std::FILE *const file, const char *const filename) const {
 1.31629 +      if (is_empty())
 1.31630 +        throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31631 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31632 +      if (!filename)
 1.31633 +        throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.31634 +                                    pixel_type(),width,height,depth,dim,data);
 1.31635 +      if (depth>1)
 1.31636 +        cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 1.31637 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31638 +#ifndef cimg_use_png
 1.31639 +      if (!file) return save_other(filename);
 1.31640 +      else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
 1.31641 +                                 pixel_type());
 1.31642 +#else
 1.31643 +      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 1.31644 +      cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
 1.31645 +
 1.31646 +      // Setup PNG structures for write
 1.31647 +      png_voidp user_error_ptr = 0;
 1.31648 +      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
 1.31649 +      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
 1.31650 +      if(!png_ptr){
 1.31651 +        if (!file) cimg::fclose(nfile);
 1.31652 +        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
 1.31653 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.31654 +      }
 1.31655 +      png_infop info_ptr = png_create_info_struct(png_ptr);
 1.31656 +      if (!info_ptr) {
 1.31657 +        png_destroy_write_struct(&png_ptr,(png_infopp)0);
 1.31658 +        if (!file) cimg::fclose(nfile);
 1.31659 +        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
 1.31660 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.31661 +      }
 1.31662 +      if (setjmp(png_jmpbuf(png_ptr))) {
 1.31663 +        png_destroy_write_struct(&png_ptr, &info_ptr);
 1.31664 +        if (!file) cimg::fclose(nfile);
 1.31665 +        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 1.31666 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.31667 +      }
 1.31668 +      png_init_io(png_ptr, nfile);
 1.31669 +      png_uint_32 width = dimx(), height = dimy();
 1.31670 +      float vmin, vmax = (float)maxmin(vmin);
 1.31671 +      const int bit_depth = (vmin<0 || vmax>=256)?16:8;
 1.31672 +      int color_type;
 1.31673 +      switch (dimv()) {
 1.31674 +      case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
 1.31675 +      case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
 1.31676 +      case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
 1.31677 +      default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 1.31678 +      }
 1.31679 +      const int interlace_type = PNG_INTERLACE_NONE;
 1.31680 +      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
 1.31681 +      const int filter_method = PNG_FILTER_TYPE_DEFAULT;
 1.31682 +      png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
 1.31683 +      png_write_info(png_ptr, info_ptr);
 1.31684 +      const int byte_depth = bit_depth>>3;
 1.31685 +      const int numChan = dimv()>4?4:dimv();
 1.31686 +      const int pixel_bit_depth_flag = numChan * (bit_depth-1);
 1.31687 +
 1.31688 +      // Allocate Memory for Image Save and Fill pixel data
 1.31689 +      png_bytep *imgData = new png_byte*[height];
 1.31690 +      for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
 1.31691 +      const T *pC0 = ptr(0,0,0,0);
 1.31692 +      switch (pixel_bit_depth_flag) {
 1.31693 +      case 7 :  { // Gray 8-bit
 1.31694 +        cimg_forY(*this,y) {
 1.31695 +          unsigned char *ptrd = imgData[y];
 1.31696 +          cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
 1.31697 +        }
 1.31698 +      } break;
 1.31699 +      case 14 : { // Gray w/ Alpha 8-bit
 1.31700 +        const T *pC1 = ptr(0,0,0,1);
 1.31701 +        cimg_forY(*this,y) {
 1.31702 +          unsigned char *ptrd = imgData[y];
 1.31703 +          cimg_forX(*this,x) {
 1.31704 +            *(ptrd++) = (unsigned char)*(pC0++);
 1.31705 +            *(ptrd++) = (unsigned char)*(pC1++);
 1.31706 +          }
 1.31707 +        }
 1.31708 +      } break;
 1.31709 +      case 21 :  { // RGB 8-bit
 1.31710 +        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 1.31711 +        cimg_forY(*this,y) {
 1.31712 +          unsigned char *ptrd = imgData[y];
 1.31713 +          cimg_forX(*this,x) {
 1.31714 +            *(ptrd++) = (unsigned char)*(pC0++);
 1.31715 +            *(ptrd++) = (unsigned char)*(pC1++);
 1.31716 +            *(ptrd++) = (unsigned char)*(pC2++);
 1.31717 +          }
 1.31718 +        }
 1.31719 +      } break;
 1.31720 +      case 28 : { // RGB x/ Alpha 8-bit
 1.31721 +        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 1.31722 +        cimg_forY(*this,y){
 1.31723 +          unsigned char *ptrd = imgData[y];
 1.31724 +          cimg_forX(*this,x){
 1.31725 +            *(ptrd++) = (unsigned char)*(pC0++);
 1.31726 +            *(ptrd++) = (unsigned char)*(pC1++);
 1.31727 +            *(ptrd++) = (unsigned char)*(pC2++);
 1.31728 +            *(ptrd++) = (unsigned char)*(pC3++);
 1.31729 +          }
 1.31730 +        }
 1.31731 +      } break;
 1.31732 +      case 15 : { // Gray 16-bit
 1.31733 +        cimg_forY(*this,y){
 1.31734 +          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 1.31735 +          cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
 1.31736 +          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
 1.31737 +        }
 1.31738 +      } break;
 1.31739 +      case 30 : { // Gray w/ Alpha 16-bit
 1.31740 +        const T *pC1 = ptr(0,0,0,1);
 1.31741 +        cimg_forY(*this,y){
 1.31742 +          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 1.31743 +          cimg_forX(*this,x) {
 1.31744 +            *(ptrd++) = (unsigned short)*(pC0++);
 1.31745 +            *(ptrd++) = (unsigned short)*(pC1++);
 1.31746 +          }
 1.31747 +          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
 1.31748 +        }
 1.31749 +      } break;
 1.31750 +      case 45 : { // RGB 16-bit
 1.31751 +        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 1.31752 +        cimg_forY(*this,y) {
 1.31753 +          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 1.31754 +          cimg_forX(*this,x) {
 1.31755 +            *(ptrd++) = (unsigned short)*(pC0++);
 1.31756 +            *(ptrd++) = (unsigned short)*(pC1++);
 1.31757 +            *(ptrd++) = (unsigned short)*(pC2++);
 1.31758 +          }
 1.31759 +          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
 1.31760 +        }
 1.31761 +      } break;
 1.31762 +      case 60 : { // RGB w/ Alpha 16-bit
 1.31763 +        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 1.31764 +        cimg_forY(*this,y) {
 1.31765 +          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 1.31766 +          cimg_forX(*this,x) {
 1.31767 +            *(ptrd++) = (unsigned short)*(pC0++);
 1.31768 +            *(ptrd++) = (unsigned short)*(pC1++);
 1.31769 +            *(ptrd++) = (unsigned short)*(pC2++);
 1.31770 +            *(ptrd++) = (unsigned short)*(pC3++);
 1.31771 +          }
 1.31772 +          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
 1.31773 +        }
 1.31774 +      } break;
 1.31775 +      default :
 1.31776 +        if (!file) cimg::fclose(nfile);
 1.31777 +        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 1.31778 +                              pixel_type(),nfilename?nfilename:"(FILE*)");
 1.31779 +      }
 1.31780 +      png_write_image(png_ptr, imgData);
 1.31781 +      png_write_end(png_ptr, info_ptr);
 1.31782 +      png_destroy_write_struct(&png_ptr, &info_ptr);
 1.31783 +
 1.31784 +      // Deallocate Image Write Memory
 1.31785 +      cimg_forY(*this,n) delete[] imgData[n];
 1.31786 +      delete[] imgData;
 1.31787 +      if (!file) cimg::fclose(nfile);
 1.31788 +      return *this;
 1.31789 +#endif
 1.31790 +    }
 1.31791 +
 1.31792 +    //! Save a file in PNG format
 1.31793 +    const CImg<T>& save_png(const char *const filename) const {
 1.31794 +      return _save_png(0,filename);
 1.31795 +    }
 1.31796 +
 1.31797 +    //! Save a file in PNG format
 1.31798 +    const CImg<T>& save_png(cimg_std::FILE *const file) const {
 1.31799 +      return _save_png(file,0);
 1.31800 +    }
 1.31801 +
 1.31802 +    // Save the image as a PNM file (internal function).
 1.31803 +    const CImg<T>& _save_pnm(cimg_std::FILE *const file, const char *const filename) const {
 1.31804 +      if (!file && !filename)
 1.31805 +        throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31806 +                                    pixel_type(),width,height,depth,dim,data);
 1.31807 +      if (is_empty())
 1.31808 +        throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31809 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31810 +      double stmin, stmax = (double)maxmin(stmin);
 1.31811 +      if (depth>1)
 1.31812 +        cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
 1.31813 +                 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31814 +      if (dim>3)
 1.31815 +        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.",
 1.31816 +                 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31817 +      if (stmin<0 || stmax>65535)
 1.31818 +        cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
 1.31819 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
 1.31820 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.31821 +      const T
 1.31822 +        *ptrR = ptr(0,0,0,0),
 1.31823 +        *ptrG = (dim>=2)?ptr(0,0,0,1):0,
 1.31824 +        *ptrB = (dim>=3)?ptr(0,0,0,2):0;
 1.31825 +      const unsigned int buf_size = width*height*(dim==1?1:3);
 1.31826 +
 1.31827 +      cimg_std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
 1.31828 +                   (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
 1.31829 +
 1.31830 +      switch (dim) {
 1.31831 +      case 1 : { // Scalar image
 1.31832 +        if (stmax<256) { // Binary PGM 8 bits
 1.31833 +          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 1.31834 +          cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
 1.31835 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31836 +          delete[] ptrd;
 1.31837 +        } else {             // Binary PGM 16 bits
 1.31838 +          unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 1.31839 +          cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
 1.31840 +          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 1.31841 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31842 +          delete[] ptrd;
 1.31843 +        }
 1.31844 +      } break;
 1.31845 +      case 2 : { // RG image
 1.31846 +        if (stmax<256) { // Binary PPM 8 bits
 1.31847 +          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 1.31848 +          cimg_forXY(*this,x,y) {
 1.31849 +            *(xptrd++) = (unsigned char)*(ptrR++);
 1.31850 +            *(xptrd++) = (unsigned char)*(ptrG++);
 1.31851 +            *(xptrd++) = 0;
 1.31852 +          }
 1.31853 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31854 +          delete[] ptrd;
 1.31855 +        } else {             // Binary PPM 16 bits
 1.31856 +          unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 1.31857 +          cimg_forXY(*this,x,y) {
 1.31858 +            *(xptrd++) = (unsigned short)*(ptrR++);
 1.31859 +            *(xptrd++) = (unsigned short)*(ptrG++);
 1.31860 +            *(xptrd++) = 0;
 1.31861 +          }
 1.31862 +          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 1.31863 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31864 +          delete[] ptrd;
 1.31865 +        }
 1.31866 +      } break;
 1.31867 +      default : { // RGB image
 1.31868 +        if (stmax<256) { // Binary PPM 8 bits
 1.31869 +          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 1.31870 +          cimg_forXY(*this,x,y) {
 1.31871 +            *(xptrd++) = (unsigned char)*(ptrR++);
 1.31872 +            *(xptrd++) = (unsigned char)*(ptrG++);
 1.31873 +            *(xptrd++) = (unsigned char)*(ptrB++);
 1.31874 +          }
 1.31875 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31876 +          delete[] ptrd;
 1.31877 +        } else {             // Binary PPM 16 bits
 1.31878 +          unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 1.31879 +          cimg_forXY(*this,x,y) {
 1.31880 +            *(xptrd++) = (unsigned short)*(ptrR++);
 1.31881 +            *(xptrd++) = (unsigned short)*(ptrG++);
 1.31882 +            *(xptrd++) = (unsigned short)*(ptrB++);
 1.31883 +          }
 1.31884 +          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 1.31885 +          cimg::fwrite(ptrd,buf_size,nfile);
 1.31886 +          delete[] ptrd;
 1.31887 +        }
 1.31888 +      }
 1.31889 +      }
 1.31890 +      if (!file) cimg::fclose(nfile);
 1.31891 +      return *this;
 1.31892 +    }
 1.31893 +
 1.31894 +    //! Save the image as a PNM file.
 1.31895 +    const CImg<T>& save_pnm(const char *const filename) const {
 1.31896 +      return _save_pnm(0,filename);
 1.31897 +    }
 1.31898 +
 1.31899 +    //! Save the image as a PNM file.
 1.31900 +    const CImg<T>& save_pnm(cimg_std::FILE *const file) const {
 1.31901 +      return _save_pnm(file,0);
 1.31902 +    }
 1.31903 +
 1.31904 +    // Save the image as a RGB file (internal).
 1.31905 +    const CImg<T>& _save_rgb(cimg_std::FILE *const file, const char *const filename) const {
 1.31906 +      if (is_empty())
 1.31907 +        throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31908 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31909 +      if (!file && !filename)
 1.31910 +        throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31911 +                                    pixel_type(),width,height,depth,dim,data);
 1.31912 +      if (dim!=3)
 1.31913 +        cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
 1.31914 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31915 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.31916 +      const unsigned int wh = width*height;
 1.31917 +      unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
 1.31918 +      const T
 1.31919 +        *ptr1 = ptr(0,0,0,0),
 1.31920 +        *ptr2 = dim>1?ptr(0,0,0,1):0,
 1.31921 +        *ptr3 = dim>2?ptr(0,0,0,2):0;
 1.31922 +      switch (dim) {
 1.31923 +      case 1 : { // Scalar image
 1.31924 +        for (unsigned int k=0; k<wh; ++k) {
 1.31925 +          const unsigned char val = (unsigned char)*(ptr1++);
 1.31926 +          *(nbuffer++) = val;
 1.31927 +          *(nbuffer++) = val;
 1.31928 +          *(nbuffer++) = val;
 1.31929 +        }} break;
 1.31930 +      case 2 : { // RG image
 1.31931 +        for (unsigned int k=0; k<wh; ++k) {
 1.31932 +          *(nbuffer++) = (unsigned char)(*(ptr1++));
 1.31933 +          *(nbuffer++) = (unsigned char)(*(ptr2++));
 1.31934 +          *(nbuffer++) = 0;
 1.31935 +        }} break;
 1.31936 +      default : { // RGB image
 1.31937 +        for (unsigned int k=0; k<wh; ++k) {
 1.31938 +          *(nbuffer++) = (unsigned char)(*(ptr1++));
 1.31939 +          *(nbuffer++) = (unsigned char)(*(ptr2++));
 1.31940 +          *(nbuffer++) = (unsigned char)(*(ptr3++));
 1.31941 +        }
 1.31942 +      }
 1.31943 +      }
 1.31944 +      cimg::fwrite(buffer,3*wh,nfile);
 1.31945 +      if (!file) cimg::fclose(nfile);
 1.31946 +      delete[] buffer;
 1.31947 +      return *this;
 1.31948 +    }
 1.31949 +
 1.31950 +    //! Save the image as a RGB file.
 1.31951 +    const CImg<T>& save_rgb(const char *const filename) const {
 1.31952 +      return _save_rgb(0,filename);
 1.31953 +    }
 1.31954 +
 1.31955 +    //! Save the image as a RGB file.
 1.31956 +    const CImg<T>& save_rgb(cimg_std::FILE *const file) const {
 1.31957 +      return _save_rgb(file,0);
 1.31958 +    }
 1.31959 +
 1.31960 +    // Save the image as a RGBA file (internal).
 1.31961 +    const CImg<T>& _save_rgba(cimg_std::FILE *const file, const char *const filename) const {
 1.31962 +      if (is_empty())
 1.31963 +        throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.31964 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31965 +      if (!file && !filename)
 1.31966 +        throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.31967 +                                    pixel_type(),width,height,depth,dim,data);
 1.31968 +      if (dim!=4)
 1.31969 +        cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
 1.31970 +                   pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.31971 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.31972 +      const unsigned int wh = width*height;
 1.31973 +      unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
 1.31974 +      const T
 1.31975 +        *ptr1 = ptr(0,0,0,0),
 1.31976 +        *ptr2 = dim>1?ptr(0,0,0,1):0,
 1.31977 +        *ptr3 = dim>2?ptr(0,0,0,2):0,
 1.31978 +        *ptr4 = dim>3?ptr(0,0,0,3):0;
 1.31979 +      switch (dim) {
 1.31980 +      case 1 : { // Scalar images
 1.31981 +        for (unsigned int k=0; k<wh; ++k) {
 1.31982 +          const unsigned char val = (unsigned char)*(ptr1++);
 1.31983 +          *(nbuffer++) = val;
 1.31984 +          *(nbuffer++) = val;
 1.31985 +          *(nbuffer++) = val;
 1.31986 +          *(nbuffer++) = 255;
 1.31987 +        }} break;
 1.31988 +      case 2 : { // RG images
 1.31989 +        for (unsigned int k=0; k<wh; ++k) {
 1.31990 +          *(nbuffer++) = (unsigned char)(*(ptr1++));
 1.31991 +          *(nbuffer++) = (unsigned char)(*(ptr2++));
 1.31992 +          *(nbuffer++) = 0;
 1.31993 +          *(nbuffer++) = 255;
 1.31994 +        }} break;
 1.31995 +      case 3 : { // RGB images
 1.31996 +        for (unsigned int k=0; k<wh; ++k) {
 1.31997 +          *(nbuffer++) = (unsigned char)(*(ptr1++));
 1.31998 +          *(nbuffer++) = (unsigned char)(*(ptr2++));
 1.31999 +          *(nbuffer++) = (unsigned char)(*(ptr3++));
 1.32000 +          *(nbuffer++) = 255;
 1.32001 +        }} break;
 1.32002 +      default : { // RGBA images
 1.32003 +        for (unsigned int k=0; k<wh; ++k) {
 1.32004 +          *(nbuffer++) = (unsigned char)(*(ptr1++));
 1.32005 +          *(nbuffer++) = (unsigned char)(*(ptr2++));
 1.32006 +          *(nbuffer++) = (unsigned char)(*(ptr3++));
 1.32007 +          *(nbuffer++) = (unsigned char)(*(ptr4++));
 1.32008 +        }
 1.32009 +      }
 1.32010 +      }
 1.32011 +      cimg::fwrite(buffer,4*wh,nfile);
 1.32012 +      if (!file) cimg::fclose(nfile);
 1.32013 +      delete[] buffer;
 1.32014 +      return *this;
 1.32015 +    }
 1.32016 +
 1.32017 +    //! Save the image as a RGBA file.
 1.32018 +    const CImg<T>& save_rgba(const char *const filename) const {
 1.32019 +      return _save_rgba(0,filename);
 1.32020 +    }
 1.32021 +
 1.32022 +    //! Save the image as a RGBA file.
 1.32023 +    const CImg<T>& save_rgba(cimg_std::FILE *const file) const {
 1.32024 +      return _save_rgba(file,0);
 1.32025 +    }
 1.32026 +
 1.32027 +    // Save a plane into a tiff file
 1.32028 +#ifdef cimg_use_tiff
 1.32029 +    const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
 1.32030 +      if (is_empty() || !tif) return *this;
 1.32031 +      const char *const filename = TIFFFileName(tif);
 1.32032 +      uint32 rowsperstrip = (uint32)-1;
 1.32033 +      uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
 1.32034 +      if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
 1.32035 +      else photometric = PHOTOMETRIC_MINISBLACK;
 1.32036 +      TIFFSetDirectory(tif,directory);
 1.32037 +      TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
 1.32038 +      TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
 1.32039 +      TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
 1.32040 +      TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
 1.32041 +      if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
 1.32042 +      else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
 1.32043 +      else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
 1.32044 +      TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
 1.32045 +      TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
 1.32046 +      TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
 1.32047 +      TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
 1.32048 +      rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
 1.32049 +      TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
 1.32050 +      TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
 1.32051 +      TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
 1.32052 +      T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
 1.32053 +      if (buf){
 1.32054 +        for (unsigned int row = 0; row<height; row+=rowsperstrip) {
 1.32055 +          uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
 1.32056 +          tstrip_t strip = TIFFComputeStrip(tif,row,0);
 1.32057 +          tsize_t i = 0;
 1.32058 +          for (unsigned int rr = 0; rr<nrow; ++rr)
 1.32059 +            for (unsigned int cc = 0; cc<width; ++cc)
 1.32060 +              for (unsigned int vv = 0; vv<spp; ++vv)
 1.32061 +                buf[i++] = (*this)(cc,row+rr,vv);
 1.32062 +          if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
 1.32063 +            throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occured while writing a strip.",
 1.32064 +                                pixel_type(),filename?filename:"(FILE*)");
 1.32065 +        }
 1.32066 +        _TIFFfree(buf);
 1.32067 +      }
 1.32068 +      TIFFWriteDirectory(tif);
 1.32069 +      return (*this);
 1.32070 +    }
 1.32071 +#endif
 1.32072 +
 1.32073 +    //! Save a file in TIFF format.
 1.32074 +    const CImg<T>& save_tiff(const char *const filename) const {
 1.32075 +      if (is_empty())
 1.32076 +        throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32077 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32078 +      if (!filename)
 1.32079 +        throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
 1.32080 +                                    pixel_type(),width,height,depth,dim,data);
 1.32081 +#ifdef cimg_use_tiff
 1.32082 +      TIFF *tif = TIFFOpen(filename,"w");
 1.32083 +      if (tif) {
 1.32084 +        cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
 1.32085 +        TIFFClose(tif);
 1.32086 +      } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
 1.32087 +                                 pixel_type(),filename);
 1.32088 +#else
 1.32089 +      return save_other(filename);
 1.32090 +#endif
 1.32091 +      return *this;
 1.32092 +    }
 1.32093 +
 1.32094 +    //! Save the image as an ANALYZE7.5 or NIFTI file.
 1.32095 +    const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
 1.32096 +      if (is_empty())
 1.32097 +        throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32098 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32099 +      if (!filename)
 1.32100 +        throw CImgArgumentException("CImg<%s>::save_analyze() :  Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32101 +                                    pixel_type(),width,height,depth,dim,data);
 1.32102 +      cimg_std::FILE *file;
 1.32103 +      char header[348], hname[1024], iname[1024];
 1.32104 +      const char *ext = cimg::split_filename(filename);
 1.32105 +      short datatype=-1;
 1.32106 +      cimg_std::memset(header,0,348);
 1.32107 +      if (!ext[0]) { cimg_std::sprintf(hname,"%s.hdr",filename); cimg_std::sprintf(iname,"%s.img",filename); }
 1.32108 +      if (!cimg::strncasecmp(ext,"hdr",3)) {
 1.32109 +        cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(iname+cimg::strlen(iname)-3,"img");
 1.32110 +      }
 1.32111 +      if (!cimg::strncasecmp(ext,"img",3)) {
 1.32112 +        cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
 1.32113 +      }
 1.32114 +      if (!cimg::strncasecmp(ext,"nii",3)) {
 1.32115 +        cimg_std::strcpy(hname,filename); iname[0] = 0;
 1.32116 +      }
 1.32117 +      ((int*)(header))[0] = 348;
 1.32118 +      cimg_std::sprintf(header+4,"CImg");
 1.32119 +      cimg_std::sprintf(header+14," ");
 1.32120 +      ((short*)(header+36))[0] = 4096;
 1.32121 +      ((char*)(header+38))[0] = 114;
 1.32122 +      ((short*)(header+40))[0] = 4;
 1.32123 +      ((short*)(header+40))[1] = width;
 1.32124 +      ((short*)(header+40))[2] = height;
 1.32125 +      ((short*)(header+40))[3] = depth;
 1.32126 +      ((short*)(header+40))[4] = dim;
 1.32127 +      if (!cimg::strcasecmp(pixel_type(),"bool"))           datatype = 2;
 1.32128 +      if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
 1.32129 +      if (!cimg::strcasecmp(pixel_type(),"char"))           datatype = 2;
 1.32130 +      if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
 1.32131 +      if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
 1.32132 +      if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   datatype = 8;
 1.32133 +      if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
 1.32134 +      if (!cimg::strcasecmp(pixel_type(),"unsigned long"))  datatype = 8;
 1.32135 +      if (!cimg::strcasecmp(pixel_type(),"long"))           datatype = 8;
 1.32136 +      if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
 1.32137 +      if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
 1.32138 +      if (datatype<0)
 1.32139 +        throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
 1.32140 +                              "is not handled in Analyze7.5 specifications.\n",
 1.32141 +                              pixel_type(),filename,pixel_type());
 1.32142 +      ((short*)(header+70))[0] = datatype;
 1.32143 +      ((short*)(header+72))[0] = sizeof(T);
 1.32144 +      ((float*)(header+112))[0] = 1;
 1.32145 +      ((float*)(header+76))[0] = 0;
 1.32146 +      if (voxsize) {
 1.32147 +        ((float*)(header+76))[1] = voxsize[0];
 1.32148 +        ((float*)(header+76))[2] = voxsize[1];
 1.32149 +        ((float*)(header+76))[3] = voxsize[2];
 1.32150 +      } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
 1.32151 +      file = cimg::fopen(hname,"wb");
 1.32152 +      cimg::fwrite(header,348,file);
 1.32153 +      if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
 1.32154 +      cimg::fwrite(data,size(),file);
 1.32155 +      cimg::fclose(file);
 1.32156 +      return *this;
 1.32157 +    }
 1.32158 +
 1.32159 +    //! Save the image as a .cimg file.
 1.32160 +    const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
 1.32161 +      CImgList<T>(*this,true).save_cimg(filename,compress);
 1.32162 +      return *this;
 1.32163 +    }
 1.32164 +
 1.32165 +    // Save the image as a .cimg file.
 1.32166 +    const CImg<T>& save_cimg(cimg_std::FILE *const file, const bool compress=false) const {
 1.32167 +      CImgList<T>(*this,true).save_cimg(file,compress);
 1.32168 +      return *this;
 1.32169 +    }
 1.32170 +
 1.32171 +    //! Insert the image into an existing .cimg file, at specified coordinates.
 1.32172 +    const CImg<T>& save_cimg(const char *const filename,
 1.32173 +                             const unsigned int n0,
 1.32174 +                             const unsigned int x0, const unsigned int y0,
 1.32175 +                             const unsigned int z0, const unsigned int v0) const {
 1.32176 +      CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
 1.32177 +      return *this;
 1.32178 +    }
 1.32179 +
 1.32180 +    //! Insert the image into an existing .cimg file, at specified coordinates.
 1.32181 +    const CImg<T>& save_cimg(cimg_std::FILE *const file,
 1.32182 +                             const unsigned int n0,
 1.32183 +                             const unsigned int x0, const unsigned int y0,
 1.32184 +                             const unsigned int z0, const unsigned int v0) const {
 1.32185 +      CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
 1.32186 +      return *this;
 1.32187 +    }
 1.32188 +
 1.32189 +    //! Save an empty .cimg file with specified dimensions.
 1.32190 +    static void save_empty_cimg(const char *const filename,
 1.32191 +                                const unsigned int dx, const unsigned int dy=1,
 1.32192 +                                const unsigned int dz=1, const unsigned int dv=1) {
 1.32193 +      return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
 1.32194 +    }
 1.32195 +
 1.32196 +    //! Save an empty .cimg file with specified dimensions.
 1.32197 +    static void save_empty_cimg(cimg_std::FILE *const file,
 1.32198 +                                const unsigned int dx, const unsigned int dy=1,
 1.32199 +                                const unsigned int dz=1, const unsigned int dv=1) {
 1.32200 +      return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
 1.32201 +    }
 1.32202 +
 1.32203 +    // Save the image as an INRIMAGE-4 file (internal).
 1.32204 +    const CImg<T>& _save_inr(cimg_std::FILE *const file, const char *const filename, const float *const voxsize) const {
 1.32205 +      if (is_empty())
 1.32206 +        throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32207 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.32208 +      if (!filename)
 1.32209 +        throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.32210 +                                    pixel_type(),width,height,depth,dim,data);
 1.32211 +      int inrpixsize=-1;
 1.32212 +      const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
 1.32213 +      if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
 1.32214 +      if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
 1.32215 +      if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
 1.32216 +      if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
 1.32217 +      if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
 1.32218 +      if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
 1.32219 +      if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
 1.32220 +      if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
 1.32221 +      if (inrpixsize<=0)
 1.32222 +        throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
 1.32223 +                              pixel_type(),pixel_type());
 1.32224 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.32225 +      char header[257];
 1.32226 +      int err = cimg_std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
 1.32227 +      if (voxsize) err += cimg_std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
 1.32228 +      err += cimg_std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
 1.32229 +      cimg_std::memset(header+err,'\n',252-err);
 1.32230 +      cimg_std::memcpy(header+252,"##}\n",4);
 1.32231 +      cimg::fwrite(header,256,nfile);
 1.32232 +      cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
 1.32233 +      if (!file) cimg::fclose(nfile);
 1.32234 +      return *this;
 1.32235 +    }
 1.32236 +
 1.32237 +    //! Save the image as an INRIMAGE-4 file.
 1.32238 +    const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
 1.32239 +      return _save_inr(0,filename,voxsize);
 1.32240 +    }
 1.32241 +
 1.32242 +    //! Save the image as an INRIMAGE-4 file.
 1.32243 +    const CImg<T>& save_inr(cimg_std::FILE *const file, const float *const voxsize=0) const {
 1.32244 +      return _save_inr(file,0,voxsize);
 1.32245 +    }
 1.32246 +
 1.32247 +    // Save the image as a PANDORE-5 file (internal).
 1.32248 +    unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
 1.32249 +      unsigned int nbdims = 0;
 1.32250 +      if (id==2 || id==3 || id==4)    { dims[0] = 1;   dims[1] = width;  nbdims = 2; }
 1.32251 +      if (id==5 || id==6 || id==7)    { dims[0] = 1;   dims[1] = height; dims[2] = width;  nbdims=3; }
 1.32252 +      if (id==8 || id==9 || id==10)   { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
 1.32253 +      if (id==16 || id==17 || id==18) { dims[0] = 3;   dims[1] = height; dims[2] = width;  dims[3] = colorspace; nbdims = 4; }
 1.32254 +      if (id==19 || id==20 || id==21) { dims[0] = 3;   dims[1] = depth;  dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
 1.32255 +      if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width;  nbdims = 2; }
 1.32256 +      if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width;  nbdims=3; }
 1.32257 +      if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
 1.32258 +      return nbdims;
 1.32259 +    }
 1.32260 +
 1.32261 +    const CImg<T>& _save_pandore(cimg_std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
 1.32262 +      typedef unsigned char uchar;
 1.32263 +      typedef unsigned short ushort;
 1.32264 +      typedef unsigned int uint;
 1.32265 +      typedef unsigned long ulong;
 1.32266 +
 1.32267 +#define __cimg_save_pandore_case(dtype) \
 1.32268 +       dtype *buffer = new dtype[size()]; \
 1.32269 +       const T *ptrs = data; \
 1.32270 +       cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
 1.32271 +       buffer-=size(); \
 1.32272 +       cimg::fwrite(buffer,size(),nfile); \
 1.32273 +       delete[] buffer
 1.32274 +
 1.32275 +#define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
 1.32276 +      if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !cimg::strcmp(stype,pixel_type())) { \
 1.32277 +        unsigned int *iheader = (unsigned int*)(header+12); \
 1.32278 +        nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
 1.32279 +        cimg::fwrite(header,36,nfile); \
 1.32280 +        if (sizeof(ulong)==4) { ulong ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
 1.32281 +        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); } \
 1.32282 +        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); } \
 1.32283 +        else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 1.32284 +                                   "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 1.32285 +                                   depth,dim,data); \
 1.32286 +        if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
 1.32287 +          __cimg_save_pandore_case(uchar); \
 1.32288 +        } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
 1.32289 +          if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
 1.32290 +          else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
 1.32291 +          else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
 1.32292 +          else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 1.32293 +                                     "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 1.32294 +                                     depth,dim,data); \
 1.32295 +        } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
 1.32296 +          if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
 1.32297 +          else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
 1.32298 +          else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
 1.32299 +                                     "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
 1.32300 +                                     depth,dim,data); \
 1.32301 +        } \
 1.32302 +        saved = true; \
 1.32303 +      }
 1.32304 +
 1.32305 +      if (is_empty())
 1.32306 +        throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32307 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.32308 +      if (!file && !filename)
 1.32309 +        throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.32310 +                                    pixel_type(),width,height,depth,dim,data);
 1.32311 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.32312 +      unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
 1.32313 +                                   0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
 1.32314 +      unsigned int nbdims, dims[5];
 1.32315 +      bool saved = false;
 1.32316 +      _cimg_save_pandore_case(1,1,1,"unsigned char",2);
 1.32317 +      _cimg_save_pandore_case(1,1,1,"char",3);
 1.32318 +      _cimg_save_pandore_case(1,1,1,"short",3);
 1.32319 +      _cimg_save_pandore_case(1,1,1,"unsigned short",3);
 1.32320 +      _cimg_save_pandore_case(1,1,1,"unsigned int",3);
 1.32321 +      _cimg_save_pandore_case(1,1,1,"int",3);
 1.32322 +      _cimg_save_pandore_case(1,1,1,"unsigned long",4);
 1.32323 +      _cimg_save_pandore_case(1,1,1,"long",3);
 1.32324 +      _cimg_save_pandore_case(1,1,1,"float",4);
 1.32325 +      _cimg_save_pandore_case(1,1,1,"double",4);
 1.32326 +
 1.32327 +      _cimg_save_pandore_case(0,1,1,"unsigned char",5);
 1.32328 +      _cimg_save_pandore_case(0,1,1,"char",6);
 1.32329 +      _cimg_save_pandore_case(0,1,1,"short",6);
 1.32330 +      _cimg_save_pandore_case(0,1,1,"unsigned short",6);
 1.32331 +      _cimg_save_pandore_case(0,1,1,"unsigned int",6);
 1.32332 +      _cimg_save_pandore_case(0,1,1,"int",6);
 1.32333 +      _cimg_save_pandore_case(0,1,1,"unsigned long",7);
 1.32334 +      _cimg_save_pandore_case(0,1,1,"long",6);
 1.32335 +      _cimg_save_pandore_case(0,1,1,"float",7);
 1.32336 +      _cimg_save_pandore_case(0,1,1,"double",7);
 1.32337 +
 1.32338 +      _cimg_save_pandore_case(0,0,1,"unsigned char",8);
 1.32339 +      _cimg_save_pandore_case(0,0,1,"char",9);
 1.32340 +      _cimg_save_pandore_case(0,0,1,"short",9);
 1.32341 +      _cimg_save_pandore_case(0,0,1,"unsigned short",9);
 1.32342 +      _cimg_save_pandore_case(0,0,1,"unsigned int",9);
 1.32343 +      _cimg_save_pandore_case(0,0,1,"int",9);
 1.32344 +      _cimg_save_pandore_case(0,0,1,"unsigned long",10);
 1.32345 +      _cimg_save_pandore_case(0,0,1,"long",9);
 1.32346 +      _cimg_save_pandore_case(0,0,1,"float",10);
 1.32347 +      _cimg_save_pandore_case(0,0,1,"double",10);
 1.32348 +
 1.32349 +      _cimg_save_pandore_case(0,1,3,"unsigned char",16);
 1.32350 +      _cimg_save_pandore_case(0,1,3,"char",17);
 1.32351 +      _cimg_save_pandore_case(0,1,3,"short",17);
 1.32352 +      _cimg_save_pandore_case(0,1,3,"unsigned short",17);
 1.32353 +      _cimg_save_pandore_case(0,1,3,"unsigned int",17);
 1.32354 +      _cimg_save_pandore_case(0,1,3,"int",17);
 1.32355 +      _cimg_save_pandore_case(0,1,3,"unsigned long",18);
 1.32356 +      _cimg_save_pandore_case(0,1,3,"long",17);
 1.32357 +      _cimg_save_pandore_case(0,1,3,"float",18);
 1.32358 +      _cimg_save_pandore_case(0,1,3,"double",18);
 1.32359 +
 1.32360 +      _cimg_save_pandore_case(0,0,3,"unsigned char",19);
 1.32361 +      _cimg_save_pandore_case(0,0,3,"char",20);
 1.32362 +      _cimg_save_pandore_case(0,0,3,"short",20);
 1.32363 +      _cimg_save_pandore_case(0,0,3,"unsigned short",20);
 1.32364 +      _cimg_save_pandore_case(0,0,3,"unsigned int",20);
 1.32365 +      _cimg_save_pandore_case(0,0,3,"int",20);
 1.32366 +      _cimg_save_pandore_case(0,0,3,"unsigned long",21);
 1.32367 +      _cimg_save_pandore_case(0,0,3,"long",20);
 1.32368 +      _cimg_save_pandore_case(0,0,3,"float",21);
 1.32369 +      _cimg_save_pandore_case(0,0,3,"double",21);
 1.32370 +
 1.32371 +      _cimg_save_pandore_case(1,1,0,"unsigned char",22);
 1.32372 +      _cimg_save_pandore_case(1,1,0,"char",23);
 1.32373 +      _cimg_save_pandore_case(1,1,0,"short",23);
 1.32374 +      _cimg_save_pandore_case(1,1,0,"unsigned short",23);
 1.32375 +      _cimg_save_pandore_case(1,1,0,"unsigned int",23);
 1.32376 +      _cimg_save_pandore_case(1,1,0,"int",23);
 1.32377 +      _cimg_save_pandore_case(1,1,0,"unsigned long",25);
 1.32378 +      _cimg_save_pandore_case(1,1,0,"long",23);
 1.32379 +      _cimg_save_pandore_case(1,1,0,"float",25);
 1.32380 +      _cimg_save_pandore_case(1,1,0,"double",25);
 1.32381 +
 1.32382 +      _cimg_save_pandore_case(0,1,0,"unsigned char",26);
 1.32383 +      _cimg_save_pandore_case(0,1,0,"char",27);
 1.32384 +      _cimg_save_pandore_case(0,1,0,"short",27);
 1.32385 +      _cimg_save_pandore_case(0,1,0,"unsigned short",27);
 1.32386 +      _cimg_save_pandore_case(0,1,0,"unsigned int",27);
 1.32387 +      _cimg_save_pandore_case(0,1,0,"int",27);
 1.32388 +      _cimg_save_pandore_case(0,1,0,"unsigned long",29);
 1.32389 +      _cimg_save_pandore_case(0,1,0,"long",27);
 1.32390 +      _cimg_save_pandore_case(0,1,0,"float",29);
 1.32391 +      _cimg_save_pandore_case(0,1,0,"double",29);
 1.32392 +
 1.32393 +      _cimg_save_pandore_case(0,0,0,"unsigned char",30);
 1.32394 +      _cimg_save_pandore_case(0,0,0,"char",31);
 1.32395 +      _cimg_save_pandore_case(0,0,0,"short",31);
 1.32396 +      _cimg_save_pandore_case(0,0,0,"unsigned short",31);
 1.32397 +      _cimg_save_pandore_case(0,0,0,"unsigned int",31);
 1.32398 +      _cimg_save_pandore_case(0,0,0,"int",31);
 1.32399 +      _cimg_save_pandore_case(0,0,0,"unsigned long",33);
 1.32400 +      _cimg_save_pandore_case(0,0,0,"long",31);
 1.32401 +      _cimg_save_pandore_case(0,0,0,"float",33);
 1.32402 +      _cimg_save_pandore_case(0,0,0,"double",33);
 1.32403 +
 1.32404 +      if (!file) cimg::fclose(nfile);
 1.32405 +      return *this;
 1.32406 +    }
 1.32407 +
 1.32408 +    //! Save the image as a PANDORE-5 file.
 1.32409 +    const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
 1.32410 +      return _save_pandore(0,filename,colorspace);
 1.32411 +    }
 1.32412 +
 1.32413 +    //! Save the image as a PANDORE-5 file.
 1.32414 +    const CImg<T>& save_pandore(cimg_std::FILE *const file, const unsigned int colorspace=0) const {
 1.32415 +      return _save_pandore(file,0,colorspace);
 1.32416 +    }
 1.32417 +
 1.32418 +   // Save the image as a RAW file (internal).
 1.32419 +    const CImg<T>& _save_raw(cimg_std::FILE *const file, const char *const filename, const bool multiplexed) const {
 1.32420 +      if (is_empty())
 1.32421 +        throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32422 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.32423 +      if (!file && !filename)
 1.32424 +        throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 1.32425 +                                    pixel_type(),width,height,depth,dim,data);
 1.32426 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.32427 +      if (!multiplexed) cimg::fwrite(data,size(),nfile);
 1.32428 +      else {
 1.32429 +        CImg<T> buf(dim);
 1.32430 +        cimg_forXYZ(*this,x,y,z) {
 1.32431 +          cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
 1.32432 +          cimg::fwrite(buf.data,dim,nfile);
 1.32433 +        }
 1.32434 +      }
 1.32435 +      if (!file) cimg::fclose(nfile);
 1.32436 +      return *this;
 1.32437 +    }
 1.32438 +
 1.32439 +    //! Save the image as a RAW file.
 1.32440 +    const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
 1.32441 +      return _save_raw(0,filename,multiplexed);
 1.32442 +    }
 1.32443 +
 1.32444 +    //! Save the image as a RAW file.
 1.32445 +    const CImg<T>& save_raw(cimg_std::FILE *const file, const bool multiplexed=false) const {
 1.32446 +      return _save_raw(file,0,multiplexed);
 1.32447 +    }
 1.32448 +
 1.32449 +    //! Save the image as a video sequence file, using FFMPEG library.
 1.32450 +    const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.32451 +                               const unsigned int fps=25) const {
 1.32452 +      if (is_empty())
 1.32453 +        throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32454 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32455 +      if (!filename)
 1.32456 +        throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32457 +                                    pixel_type(),width,height,depth,dim,data);
 1.32458 +      if (!fps)
 1.32459 +        throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
 1.32460 +                                    pixel_type(),filename);
 1.32461 +#ifndef cimg_use_ffmpeg
 1.32462 +      return save_ffmpeg_external(filename,first_frame,last_frame);
 1.32463 +#else
 1.32464 +      get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
 1.32465 +#endif
 1.32466 +      return *this;
 1.32467 +    }
 1.32468 +
 1.32469 +    //! Save the image as a YUV video sequence file.
 1.32470 +    const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
 1.32471 +      get_split('z').save_yuv(filename,rgb2yuv);
 1.32472 +      return *this;
 1.32473 +    }
 1.32474 +
 1.32475 +    //! Save the image as a YUV video sequence file.
 1.32476 +    const CImg<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
 1.32477 +      get_split('z').save_yuv(file,rgb2yuv);
 1.32478 +      return *this;
 1.32479 +    }
 1.32480 +
 1.32481 +   // Save OFF files (internal).
 1.32482 +    template<typename tf, typename tc>
 1.32483 +    const CImg<T>& _save_off(cimg_std::FILE *const file, const char *const filename,
 1.32484 +                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
 1.32485 +      if (is_empty())
 1.32486 +        throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32487 +                                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
 1.32488 +      if (!file && !filename)
 1.32489 +        throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
 1.32490 +                                    pixel_type());
 1.32491 +      if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
 1.32492 +      CImgList<tc> _colors;
 1.32493 +      if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
 1.32494 +      const CImgList<tc>& ncolors = colors?colors:_colors;
 1.32495 +
 1.32496 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 1.32497 +      cimg_std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
 1.32498 +      cimg_forX(*this,i) cimg_std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
 1.32499 +      cimglist_for(primitives,l) {
 1.32500 +        const unsigned int prim = primitives[l].size();
 1.32501 +        const bool textured = (prim>4);
 1.32502 +        const CImg<tc>& color = ncolors[l];
 1.32503 +        const unsigned int s = textured?color.dimv():color.size();
 1.32504 +        const float
 1.32505 +          r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
 1.32506 +          g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r)   :(s>1?(float)(color(1)/255.0f):r),
 1.32507 +          b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r)   :(s>2?(float)(color(2)/255.0f):r);
 1.32508 +
 1.32509 +        switch (prim) {
 1.32510 +        case 1 :
 1.32511 +          cimg_std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
 1.32512 +          break;
 1.32513 +        case 2 : case 6 :
 1.32514 +          cimg_std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
 1.32515 +          break;
 1.32516 +        case 3 : case 9 :
 1.32517 +          if (invert_faces)
 1.32518 +            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);
 1.32519 +          else
 1.32520 +            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);
 1.32521 +          break;
 1.32522 +        case 4 : case 12 :
 1.32523 +          if (invert_faces)
 1.32524 +            cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
 1.32525 +                         (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b);
 1.32526 +          else
 1.32527 +            cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
 1.32528 +                         (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
 1.32529 +          break;
 1.32530 +        }
 1.32531 +      }
 1.32532 +      if (!file) cimg::fclose(nfile);
 1.32533 +      return *this;
 1.32534 +    }
 1.32535 +
 1.32536 +    //! Save OFF files.
 1.32537 +    template<typename tf, typename tc>
 1.32538 +    const CImg<T>& save_off(const char *const filename,
 1.32539 +                            const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 1.32540 +      return _save_off(0,filename,primitives,colors,invert_faces);
 1.32541 +    }
 1.32542 +
 1.32543 +    //! Save OFF files.
 1.32544 +    template<typename tf, typename tc>
 1.32545 +    const CImg<T>& save_off(cimg_std::FILE *const file,
 1.32546 +                            const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 1.32547 +      return _save_off(file,0,primitives,colors,invert_faces);
 1.32548 +    }
 1.32549 +
 1.32550 +    //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
 1.32551 +    const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.32552 +                                        const char *const codec="mpeg2video") const {
 1.32553 +      if (is_empty())
 1.32554 +        throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32555 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32556 +      if (!filename)
 1.32557 +        throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32558 +                                    pixel_type(),width,height,depth,dim,data);
 1.32559 +      get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
 1.32560 +      return *this;
 1.32561 +    }
 1.32562 +
 1.32563 +    //! Save the image using GraphicsMagick's gm.
 1.32564 +    /** Function that saves the image for other file formats that are not natively handled by CImg,
 1.32565 +        using the tool 'gm' from the GraphicsMagick package.\n
 1.32566 +        This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 1.32567 +        the GraphicsMagick package in order to get
 1.32568 +        this function working properly (see http://www.graphicsmagick.org ).
 1.32569 +    **/
 1.32570 +    const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
 1.32571 +      if (is_empty())
 1.32572 +        throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32573 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32574 +      if (!filename)
 1.32575 +        throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32576 +                                    pixel_type(),width,height,depth,dim,data);
 1.32577 +      char command[1024],filetmp[512];
 1.32578 +      cimg_std::FILE *file;
 1.32579 +      do {
 1.32580 +        if (dim==1) cimg_std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.32581 +        else cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.32582 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.32583 +      } while (file);
 1.32584 +      save_pnm(filetmp);
 1.32585 +      cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
 1.32586 +      cimg::system(command);
 1.32587 +      file = cimg_std::fopen(filename,"rb");
 1.32588 +      if (!file)
 1.32589 +        throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
 1.32590 +                              "Path of 'gm' : \"%s\"\n"
 1.32591 +                              "Path of temporary filename : \"%s\"\n",
 1.32592 +                              pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 1.32593 +      if (file) cimg::fclose(file);
 1.32594 +      cimg_std::remove(filetmp);
 1.32595 +      return *this;
 1.32596 +    }
 1.32597 +
 1.32598 +    //! Save an image as a gzipped file, using external tool 'gzip'.
 1.32599 +    const CImg<T>& save_gzip_external(const char *const filename) const {
 1.32600 +      if (!filename)
 1.32601 +        throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 1.32602 +                              pixel_type());
 1.32603 +      char command[1024], filetmp[512], body[512];
 1.32604 +      const char
 1.32605 +        *ext = cimg::split_filename(filename,body),
 1.32606 +        *ext2 = cimg::split_filename(body,0);
 1.32607 +      cimg_std::FILE *file;
 1.32608 +      do {
 1.32609 +        if (!cimg::strcasecmp(ext,"gz")) {
 1.32610 +          if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.32611 +                                  cimg::filenamerand(),ext2);
 1.32612 +          else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.32613 +                            cimg::filenamerand());
 1.32614 +        } else {
 1.32615 +          if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.32616 +                                 cimg::filenamerand(),ext);
 1.32617 +          else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.32618 +                                 cimg::filenamerand());
 1.32619 +        }
 1.32620 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.32621 +      } while (file);
 1.32622 +      save(filetmp);
 1.32623 +      cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 1.32624 +      cimg::system(command);
 1.32625 +      file = cimg_std::fopen(filename,"rb");
 1.32626 +      if (!file)
 1.32627 +        throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
 1.32628 +                              pixel_type(),filename);
 1.32629 +      else cimg::fclose(file);
 1.32630 +      cimg_std::remove(filetmp);
 1.32631 +      return *this;
 1.32632 +    }
 1.32633 +
 1.32634 +    //! Save the image using ImageMagick's convert.
 1.32635 +    /** Function that saves the image for other file formats that are not natively handled by CImg,
 1.32636 +        using the tool 'convert' from the ImageMagick package.\n
 1.32637 +        This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 1.32638 +        the ImageMagick package in order to get
 1.32639 +        this function working properly (see http://www.imagemagick.org ).
 1.32640 +    **/
 1.32641 +    const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
 1.32642 +      if (is_empty())
 1.32643 +        throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32644 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32645 +      if (!filename)
 1.32646 +        throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32647 +                                    pixel_type(),width,height,depth,dim,data);
 1.32648 +      char command[1024], filetmp[512];
 1.32649 +      cimg_std::FILE *file;
 1.32650 +      do {
 1.32651 +        cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
 1.32652 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.32653 +      } while (file);
 1.32654 +      save_pnm(filetmp);
 1.32655 +      cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
 1.32656 +      cimg::system(command);
 1.32657 +      file = cimg_std::fopen(filename,"rb");
 1.32658 +      if (!file)
 1.32659 +        throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
 1.32660 +                              "Path of 'convert' : \"%s\"\n"
 1.32661 +                              "Path of temporary filename : \"%s\"\n",
 1.32662 +                              pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 1.32663 +      if (file) cimg::fclose(file);
 1.32664 +      cimg_std::remove(filetmp);
 1.32665 +      return *this;
 1.32666 +    }
 1.32667 +
 1.32668 +    //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
 1.32669 +    const CImg<T>& save_medcon_external(const char *const filename) const {
 1.32670 +      if (is_empty())
 1.32671 +        throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32672 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32673 +      if (!filename)
 1.32674 +        throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32675 +                                    pixel_type(),width,height,depth,dim,data);
 1.32676 +
 1.32677 +      char command[1024], filetmp[512], body[512];
 1.32678 +      cimg_std::FILE *file;
 1.32679 +      do {
 1.32680 +        cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
 1.32681 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.32682 +      } while (file);
 1.32683 +      save_analyze(filetmp);
 1.32684 +      cimg_std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
 1.32685 +      cimg::system(command);
 1.32686 +      cimg_std::remove(filetmp);
 1.32687 +      cimg::split_filename(filetmp,body);
 1.32688 +      cimg_std::sprintf(filetmp,"%s.img",body);
 1.32689 +      cimg_std::remove(filetmp);
 1.32690 +      cimg_std::sprintf(command,"m000-%s",filename);
 1.32691 +      file = cimg_std::fopen(command,"rb");
 1.32692 +      if (!file) {
 1.32693 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.32694 +        throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
 1.32695 +                              "Path of 'medcon' : \"%s\"\n"
 1.32696 +                              "Path of temporary filename : \"%s\"",
 1.32697 +                              pixel_type(),filename,cimg::medcon_path(),filetmp);
 1.32698 +      } else cimg::fclose(file);
 1.32699 +      cimg_std::rename(command,filename);
 1.32700 +      return *this;
 1.32701 +    }
 1.32702 +
 1.32703 +    // Try to save the image if other extension is provided.
 1.32704 +    const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
 1.32705 +      if (is_empty())
 1.32706 +        throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 1.32707 +                                    pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
 1.32708 +      if (!filename)
 1.32709 +        throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 1.32710 +                              pixel_type());
 1.32711 +      const unsigned int odebug = cimg::exception_mode();
 1.32712 +      bool is_saved = true;
 1.32713 +      cimg::exception_mode() = 0;
 1.32714 +      try { save_magick(filename); }
 1.32715 +      catch (CImgException&) {
 1.32716 +        try { save_imagemagick_external(filename,quality); }
 1.32717 +        catch (CImgException&) {
 1.32718 +          try { save_graphicsmagick_external(filename,quality); }
 1.32719 +          catch (CImgException&) {
 1.32720 +            is_saved = false;
 1.32721 +          }
 1.32722 +        }
 1.32723 +      }
 1.32724 +      cimg::exception_mode() = odebug;
 1.32725 +      if (!is_saved)
 1.32726 +        throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
 1.32727 +                              "Check you have either the ImageMagick or GraphicsMagick package installed.",
 1.32728 +                              pixel_type(),filename);
 1.32729 +      return *this;
 1.32730 +    }
 1.32731 +
 1.32732 +    // Get a 40x38 color logo of a 'danger' item (internal).
 1.32733 +    static CImg<T> logo40x38() {
 1.32734 +      static bool first_time = true;
 1.32735 +      static CImg<T> res(40,38,1,3);
 1.32736 +      if (first_time) {
 1.32737 +        const unsigned char *ptrs = cimg::logo40x38;
 1.32738 +        T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
 1.32739 +        for (unsigned int off = 0; off<res.width*res.height;) {
 1.32740 +          const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
 1.32741 +          for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
 1.32742 +        }
 1.32743 +        first_time = false;
 1.32744 +      }
 1.32745 +      return res;
 1.32746 +    }
 1.32747 +
 1.32748 +  };
 1.32749 +
 1.32750 +  /*
 1.32751 +   #-----------------------------------------
 1.32752 +   #
 1.32753 +   #
 1.32754 +   #
 1.32755 +   # Definition of the CImgList<> structure
 1.32756 +   #
 1.32757 +   #
 1.32758 +   #
 1.32759 +   #------------------------------------------
 1.32760 +   */
 1.32761 +
 1.32762 +  //! Class representing list of images CImg<T>.
 1.32763 +  template<typename T>
 1.32764 +  struct CImgList {
 1.32765 +
 1.32766 +    //! Size of the list (number of elements inside).
 1.32767 +    unsigned int size;
 1.32768 +
 1.32769 +    //! Allocation size of the list.
 1.32770 +    unsigned int allocsize;
 1.32771 +
 1.32772 +    //! Pointer to the first list element.
 1.32773 +    CImg<T> *data;
 1.32774 +
 1.32775 +    //! Define a CImgList<T>::iterator.
 1.32776 +    typedef CImg<T>* iterator;
 1.32777 +
 1.32778 +    //! Define a CImgList<T>::const_iterator.
 1.32779 +    typedef const CImg<T>* const_iterator;
 1.32780 +
 1.32781 +    //! Get value type.
 1.32782 +    typedef T value_type;
 1.32783 +
 1.32784 +    // Define common T-dependant types.
 1.32785 +    typedef typename cimg::superset<T,bool>::type Tbool;
 1.32786 +    typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 1.32787 +    typedef typename cimg::superset<T,char>::type Tchar;
 1.32788 +    typedef typename cimg::superset<T,unsigned short>::type Tushort;
 1.32789 +    typedef typename cimg::superset<T,short>::type Tshort;
 1.32790 +    typedef typename cimg::superset<T,unsigned int>::type Tuint;
 1.32791 +    typedef typename cimg::superset<T,int>::type Tint;
 1.32792 +    typedef typename cimg::superset<T,unsigned long>::type Tulong;
 1.32793 +    typedef typename cimg::superset<T,long>::type Tlong;
 1.32794 +    typedef typename cimg::superset<T,float>::type Tfloat;
 1.32795 +    typedef typename cimg::superset<T,double>::type Tdouble;
 1.32796 +    typedef typename cimg::last<T,bool>::type boolT;
 1.32797 +    typedef typename cimg::last<T,unsigned char>::type ucharT;
 1.32798 +    typedef typename cimg::last<T,char>::type charT;
 1.32799 +    typedef typename cimg::last<T,unsigned short>::type ushortT;
 1.32800 +    typedef typename cimg::last<T,short>::type shortT;
 1.32801 +    typedef typename cimg::last<T,unsigned int>::type uintT;
 1.32802 +    typedef typename cimg::last<T,int>::type intT;
 1.32803 +    typedef typename cimg::last<T,unsigned long>::type ulongT;
 1.32804 +    typedef typename cimg::last<T,long>::type longT;
 1.32805 +    typedef typename cimg::last<T,float>::type floatT;
 1.32806 +    typedef typename cimg::last<T,double>::type doubleT;
 1.32807 +
 1.32808 +    //@}
 1.32809 +    //---------------------------
 1.32810 +    //
 1.32811 +    //! \name Plugins
 1.32812 +    //@{
 1.32813 +    //---------------------------
 1.32814 +#ifdef cimglist_plugin
 1.32815 +#include cimglist_plugin
 1.32816 +#endif
 1.32817 +#ifdef cimglist_plugin1
 1.32818 +#include cimglist_plugin1
 1.32819 +#endif
 1.32820 +#ifdef cimglist_plugin2
 1.32821 +#include cimglist_plugin2
 1.32822 +#endif
 1.32823 +#ifdef cimglist_plugin3
 1.32824 +#include cimglist_plugin3
 1.32825 +#endif
 1.32826 +#ifdef cimglist_plugin4
 1.32827 +#include cimglist_plugin4
 1.32828 +#endif
 1.32829 +#ifdef cimglist_plugin5
 1.32830 +#include cimglist_plugin5
 1.32831 +#endif
 1.32832 +#ifdef cimglist_plugin6
 1.32833 +#include cimglist_plugin6
 1.32834 +#endif
 1.32835 +#ifdef cimglist_plugin7
 1.32836 +#include cimglist_plugin7
 1.32837 +#endif
 1.32838 +#ifdef cimglist_plugin8
 1.32839 +#include cimglist_plugin8
 1.32840 +#endif
 1.32841 +    //@}
 1.32842 +
 1.32843 +    //------------------------------------------
 1.32844 +    //
 1.32845 +    //! \name Constructors - Destructor - Copy
 1.32846 +    //@{
 1.32847 +    //------------------------------------------
 1.32848 +
 1.32849 +    //! Destructor.
 1.32850 +    ~CImgList() {
 1.32851 +      if (data) delete[] data;
 1.32852 +    }
 1.32853 +
 1.32854 +    //! Default constructor.
 1.32855 +    CImgList():
 1.32856 +      size(0),allocsize(0),data(0) {}
 1.32857 +
 1.32858 +    //! Construct an image list containing n empty images.
 1.32859 +    explicit CImgList(const unsigned int n):
 1.32860 +      size(n) {
 1.32861 +      data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
 1.32862 +    }
 1.32863 +
 1.32864 +    //! Default copy constructor.
 1.32865 +    template<typename t>
 1.32866 +    CImgList(const CImgList<t>& list):
 1.32867 +      size(0),allocsize(0),data(0) {
 1.32868 +      assign(list.size);
 1.32869 +      cimglist_for(*this,l) data[l].assign(list[l],false);
 1.32870 +    }
 1.32871 +
 1.32872 +    CImgList(const CImgList<T>& list):
 1.32873 +      size(0),allocsize(0),data(0) {
 1.32874 +      assign(list.size);
 1.32875 +      cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
 1.32876 +    }
 1.32877 +
 1.32878 +    //! Advanced copy constructor.
 1.32879 +    template<typename t>
 1.32880 +    CImgList(const CImgList<t>& list, const bool shared):
 1.32881 +      size(0),allocsize(0),data(0) {
 1.32882 +      assign(list.size);
 1.32883 +      if (shared)
 1.32884 +        throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
 1.32885 +                                    "a CImgList<%s> (different pixel types).",
 1.32886 +                                    pixel_type(),CImgList<t>::pixel_type());
 1.32887 +      cimglist_for(*this,l) data[l].assign(list[l],false);
 1.32888 +    }
 1.32889 +
 1.32890 +    CImgList(const CImgList<T>& list, const bool shared):
 1.32891 +      size(0),allocsize(0),data(0) {
 1.32892 +      assign(list.size);
 1.32893 +      cimglist_for(*this,l) data[l].assign(list[l],shared);
 1.32894 +    }
 1.32895 +
 1.32896 +    //! Construct an image list containing n images with specified size.
 1.32897 +    CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
 1.32898 +             const unsigned int depth=1, const unsigned int dim=1):
 1.32899 +      size(0),allocsize(0),data(0) {
 1.32900 +      assign(n);
 1.32901 +      cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 1.32902 +    }
 1.32903 +
 1.32904 +    //! Construct an image list containing n images with specified size, filled with specified value.
 1.32905 +    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 1.32906 +             const unsigned int depth, const unsigned int dim, const T val):
 1.32907 +      size(0),allocsize(0),data(0) {
 1.32908 +      assign(n);
 1.32909 +      cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
 1.32910 +    }
 1.32911 +
 1.32912 +    //! Construct an image list containing n images with specified size and specified pixel values (int version).
 1.32913 +    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 1.32914 +             const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
 1.32915 +      size(0),allocsize(0),data(0) {
 1.32916 +#define _CImgList_stdarg(t) { \
 1.32917 +        assign(n,width,height,depth,dim); \
 1.32918 +        const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
 1.32919 +        T *ptrd = data->data; \
 1.32920 +        va_list ap; \
 1.32921 +        va_start(ap,val1); \
 1.32922 +        for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
 1.32923 +          *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
 1.32924 +          if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
 1.32925 +        } \
 1.32926 +        va_end(ap); \
 1.32927 +      }
 1.32928 +      _CImgList_stdarg(int);
 1.32929 +    }
 1.32930 +
 1.32931 +    //! Construct an image list containing n images with specified size and specified pixel values (double version).
 1.32932 +    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
 1.32933 +             const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
 1.32934 +      size(0),allocsize(0),data(0) {
 1.32935 +      _CImgList_stdarg(double);
 1.32936 +    }
 1.32937 +
 1.32938 +    //! Construct a list containing n copies of the image img.
 1.32939 +    template<typename t>
 1.32940 +    CImgList(const unsigned int n, const CImg<t>& img):
 1.32941 +      size(0),allocsize(0),data(0) {
 1.32942 +      assign(n);
 1.32943 +      cimglist_for(*this,l) data[l].assign(img,img.is_shared);
 1.32944 +    }
 1.32945 +
 1.32946 +    //! Construct a list containing n copies of the image img, forcing the shared state.
 1.32947 +    template<typename t>
 1.32948 +    CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
 1.32949 +      size(0),allocsize(0),data(0) {
 1.32950 +      assign(n);
 1.32951 +      cimglist_for(*this,l) data[l].assign(img,shared);
 1.32952 +    }
 1.32953 +
 1.32954 +    //! Construct an image list from one image.
 1.32955 +    template<typename t>
 1.32956 +    explicit CImgList(const CImg<t>& img):
 1.32957 +      size(0),allocsize(0),data(0) {
 1.32958 +      assign(1);
 1.32959 +      data[0].assign(img,img.is_shared);
 1.32960 +    }
 1.32961 +
 1.32962 +    //! Construct an image list from one image, forcing the shared state.
 1.32963 +    template<typename t>
 1.32964 +    explicit CImgList(const CImg<t>& img, const bool shared):
 1.32965 +      size(0),allocsize(0),data(0) {
 1.32966 +      assign(1);
 1.32967 +      data[0].assign(img,shared);
 1.32968 +    }
 1.32969 +
 1.32970 +    //! Construct an image list from two images.
 1.32971 +    template<typename t1, typename t2>
 1.32972 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
 1.32973 +      size(0),allocsize(0),data(0) {
 1.32974 +      assign(2);
 1.32975 +      data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
 1.32976 +    }
 1.32977 +
 1.32978 +    //! Construct an image list from two images, forcing the shared state.
 1.32979 +    template<typename t1, typename t2>
 1.32980 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
 1.32981 +      size(0),allocsize(0),data(0) {
 1.32982 +      assign(2);
 1.32983 +      data[0].assign(img1,shared); data[1].assign(img2,shared);
 1.32984 +    }
 1.32985 +
 1.32986 +    //! Construct an image list from three images.
 1.32987 +    template<typename t1, typename t2, typename t3>
 1.32988 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
 1.32989 +      size(0),allocsize(0),data(0) {
 1.32990 +      assign(3);
 1.32991 +      data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
 1.32992 +    }
 1.32993 +
 1.32994 +    //! Construct an image list from three images, forcing the shared state.
 1.32995 +    template<typename t1, typename t2, typename t3>
 1.32996 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
 1.32997 +      size(0),allocsize(0),data(0) {
 1.32998 +      assign(3);
 1.32999 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
 1.33000 +    }
 1.33001 +
 1.33002 +    //! Construct an image list from four images.
 1.33003 +    template<typename t1, typename t2, typename t3, typename t4>
 1.33004 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
 1.33005 +      size(0),allocsize(0),data(0) {
 1.33006 +      assign(4);
 1.33007 +      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);
 1.33008 +    }
 1.33009 +
 1.33010 +    //! Construct an image list from four images, forcing the shared state.
 1.33011 +    template<typename t1, typename t2, typename t3, typename t4>
 1.33012 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
 1.33013 +      size(0),allocsize(0),data(0) {
 1.33014 +      assign(4);
 1.33015 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33016 +    }
 1.33017 +
 1.33018 +    //! Construct an image list from five images.
 1.33019 +    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 1.33020 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33021 +             const CImg<t5>& img5):
 1.33022 +      size(0),allocsize(0),data(0) {
 1.33023 +      assign(5);
 1.33024 +      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);
 1.33025 +      data[4].assign(img5,img5.is_shared);
 1.33026 +    }
 1.33027 +
 1.33028 +    //! Construct an image list from five images, forcing the shared state.
 1.33029 +    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 1.33030 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33031 +             const CImg<t5>& img5, const bool shared):
 1.33032 +      size(0),allocsize(0),data(0) {
 1.33033 +      assign(5);
 1.33034 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33035 +      data[4].assign(img5,shared);
 1.33036 +    }
 1.33037 +
 1.33038 +    //! Construct an image list from six images.
 1.33039 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 1.33040 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33041 +             const CImg<t5>& img5, const CImg<t6>& img6):
 1.33042 +      size(0),allocsize(0),data(0) {
 1.33043 +      assign(6);
 1.33044 +      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);
 1.33045 +      data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
 1.33046 +    }
 1.33047 +
 1.33048 +    //! Construct an image list from six images, forcing the shared state.
 1.33049 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 1.33050 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33051 +             const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
 1.33052 +      size(0),allocsize(0),data(0) {
 1.33053 +      assign(6);
 1.33054 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33055 +      data[4].assign(img5,shared); data[5].assign(img6,shared);
 1.33056 +    }
 1.33057 +
 1.33058 +    //! Construct an image list from seven images.
 1.33059 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 1.33060 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33061 +             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
 1.33062 +      size(0),allocsize(0),data(0) {
 1.33063 +      assign(7);
 1.33064 +      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);
 1.33065 +      data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
 1.33066 +    }
 1.33067 +
 1.33068 +    //! Construct an image list from seven images, forcing the shared state.
 1.33069 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 1.33070 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33071 +             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
 1.33072 +      size(0),allocsize(0),data(0) {
 1.33073 +      assign(7);
 1.33074 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33075 +      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
 1.33076 +    }
 1.33077 +
 1.33078 +    //! Construct an image list from eight images.
 1.33079 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 1.33080 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33081 +             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
 1.33082 +      size(0),allocsize(0),data(0) {
 1.33083 +      assign(8);
 1.33084 +      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);
 1.33085 +      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);
 1.33086 +    }
 1.33087 +
 1.33088 +    //! Construct an image list from eight images, forcing the shared state.
 1.33089 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 1.33090 +    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33091 +             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
 1.33092 +      size(0),allocsize(0),data(0) {
 1.33093 +      assign(8);
 1.33094 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33095 +      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
 1.33096 +    }
 1.33097 +
 1.33098 +    //! Construct an image list from a filename.
 1.33099 +    CImgList(const char *const filename):
 1.33100 +      size(0),allocsize(0),data(0) {
 1.33101 +      assign(filename);
 1.33102 +    }
 1.33103 +
 1.33104 +    //! In-place version of the default constructor and default destructor.
 1.33105 +    CImgList<T>& assign() {
 1.33106 +      if (data) delete[] data;
 1.33107 +      size = allocsize = 0;
 1.33108 +      data = 0;
 1.33109 +      return *this;
 1.33110 +    }
 1.33111 +
 1.33112 +    //! Equivalent to assign() (STL-compliant name).
 1.33113 +    CImgList<T>& clear() {
 1.33114 +      return assign();
 1.33115 +    }
 1.33116 +
 1.33117 +    //! In-place version of the corresponding constructor.
 1.33118 +    CImgList<T>& assign(const unsigned int n) {
 1.33119 +      if (n) {
 1.33120 +        if (allocsize<n || allocsize>(n<<2)) {
 1.33121 +          if (data) delete[] data;
 1.33122 +          data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
 1.33123 +        }
 1.33124 +        size = n;
 1.33125 +      } else assign();
 1.33126 +      return *this;
 1.33127 +    }
 1.33128 +
 1.33129 +    //! In-place version of the corresponding constructor.
 1.33130 +    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
 1.33131 +                        const unsigned int depth=1, const unsigned int dim=1) {
 1.33132 +      assign(n);
 1.33133 +      cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 1.33134 +      return *this;
 1.33135 +    }
 1.33136 +
 1.33137 +    //! In-place version of the corresponding constructor.
 1.33138 +    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 1.33139 +                        const unsigned int depth, const unsigned int dim, const T val) {
 1.33140 +      assign(n);
 1.33141 +      cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
 1.33142 +      return *this;
 1.33143 +    }
 1.33144 +
 1.33145 +    //! In-place version of the corresponding constructor.
 1.33146 +    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 1.33147 +                        const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
 1.33148 +      _CImgList_stdarg(int);
 1.33149 +      return *this;
 1.33150 +    }
 1.33151 +
 1.33152 +    //! In-place version of the corresponding constructor.
 1.33153 +    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 1.33154 +                        const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
 1.33155 +      _CImgList_stdarg(double);
 1.33156 +      return *this;
 1.33157 +    }
 1.33158 +
 1.33159 +    //! In-place version of the copy constructor.
 1.33160 +    template<typename t>
 1.33161 +    CImgList<T>& assign(const CImgList<t>& list) {
 1.33162 +      assign(list.size);
 1.33163 +      cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
 1.33164 +      return *this;
 1.33165 +    }
 1.33166 +
 1.33167 +    //! In-place version of the copy constructor.
 1.33168 +    template<typename t>
 1.33169 +    CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
 1.33170 +      assign(list.size);
 1.33171 +      cimglist_for(*this,l) data[l].assign(list[l],shared);
 1.33172 +      return *this;
 1.33173 +    }
 1.33174 +
 1.33175 +    //! In-place version of the corresponding constructor.
 1.33176 +    template<typename t>
 1.33177 +    CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
 1.33178 +      assign(n);
 1.33179 +      cimglist_for(*this,l) data[l].assign(img,shared);
 1.33180 +      return *this;
 1.33181 +    }
 1.33182 +
 1.33183 +    //! In-place version of the corresponding constructor.
 1.33184 +    template<typename t>
 1.33185 +    CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
 1.33186 +      assign(1);
 1.33187 +      data[0].assign(img,shared);
 1.33188 +      return *this;
 1.33189 +    }
 1.33190 +
 1.33191 +    //! In-place version of the corresponding constructor.
 1.33192 +    template<typename t1, typename t2>
 1.33193 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
 1.33194 +      assign(2);
 1.33195 +      data[0].assign(img1,shared); data[1].assign(img2,shared);
 1.33196 +      return *this;
 1.33197 +    }
 1.33198 +
 1.33199 +    //! In-place version of the corresponding constructor.
 1.33200 +    template<typename t1, typename t2, typename t3>
 1.33201 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
 1.33202 +      assign(3);
 1.33203 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
 1.33204 +      return *this;
 1.33205 +    }
 1.33206 +
 1.33207 +    //! In-place version of the corresponding constructor.
 1.33208 +    template<typename t1, typename t2, typename t3, typename t4>
 1.33209 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33210 +                        const bool shared=false) {
 1.33211 +      assign(4);
 1.33212 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33213 +      return *this;
 1.33214 +    }
 1.33215 +
 1.33216 +    //! In-place version of the corresponding constructor.
 1.33217 +    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 1.33218 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33219 +                        const CImg<t5>& img5, const bool shared=false) {
 1.33220 +      assign(5);
 1.33221 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33222 +      data[4].assign(img5,shared);
 1.33223 +      return *this;
 1.33224 +    }
 1.33225 +
 1.33226 +    //! In-place version of the corresponding constructor.
 1.33227 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 1.33228 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33229 +                        const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
 1.33230 +      assign(6);
 1.33231 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33232 +      data[4].assign(img5,shared); data[5].assign(img6,shared);
 1.33233 +      return *this;
 1.33234 +    }
 1.33235 +
 1.33236 +    //! In-place version of the corresponding constructor.
 1.33237 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 1.33238 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33239 +                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
 1.33240 +      assign(7);
 1.33241 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33242 +      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
 1.33243 +      return *this;
 1.33244 +    }
 1.33245 +
 1.33246 +    //! In-place version of the corresponding constructor.
 1.33247 +    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 1.33248 +    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 1.33249 +                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
 1.33250 +      assign(8);
 1.33251 +      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 1.33252 +      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
 1.33253 +      return *this;
 1.33254 +    }
 1.33255 +
 1.33256 +    //! In-place version of the corresponding constructor.
 1.33257 +    CImgList<T>& assign(const char *const filename) {
 1.33258 +      return load(filename);
 1.33259 +    }
 1.33260 +
 1.33261 +    //! Transfer the content of the instance image list into another one.
 1.33262 +    template<typename t>
 1.33263 +    CImgList<T>& transfer_to(CImgList<t>& list) {
 1.33264 +      list.assign(*this);
 1.33265 +      assign();
 1.33266 +      return list;
 1.33267 +    }
 1.33268 +
 1.33269 +    CImgList<T>& transfer_to(CImgList<T>& list) {
 1.33270 +      list.assign();
 1.33271 +      return swap(list);
 1.33272 +    }
 1.33273 +
 1.33274 +    //! Swap all fields of two CImgList instances (use with care !)
 1.33275 +    CImgList<T>& swap(CImgList<T>& list) {
 1.33276 +      cimg::swap(size,list.size);
 1.33277 +      cimg::swap(allocsize,list.allocsize);
 1.33278 +      cimg::swap(data,list.data);
 1.33279 +      return list;
 1.33280 +    }
 1.33281 +
 1.33282 +    //! Return a string describing the type of the image pixels in the list (template parameter \p T).
 1.33283 +    static const char* pixel_type() {
 1.33284 +      return cimg::type<T>::string();
 1.33285 +    }
 1.33286 +
 1.33287 +    //! Return \p true if list is empty.
 1.33288 +    bool is_empty() const {
 1.33289 +      return (!data || !size);
 1.33290 +    }
 1.33291 +
 1.33292 +    //! Return \p true if list is not empty.
 1.33293 +    operator bool() const {
 1.33294 +      return !is_empty();
 1.33295 +    }
 1.33296 +
 1.33297 +    //! Return \p true if list if of specified size.
 1.33298 +    bool is_sameN(const unsigned int n) const {
 1.33299 +      return (size==n);
 1.33300 +    }
 1.33301 +
 1.33302 +    //! Return \p true if list if of specified size.
 1.33303 +    template<typename t>
 1.33304 +    bool is_sameN(const CImgList<t>& list) const {
 1.33305 +      return (size==list.size);
 1.33306 +    }
 1.33307 +
 1.33308 +    // Define useful dimension check functions.
 1.33309 +    // (not documented because they are macro-generated).
 1.33310 +#define _cimglist_def_is_same1(axis) \
 1.33311 +    bool is_same##axis(const unsigned int val) const { \
 1.33312 +      bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(val); return res; \
 1.33313 +    } \
 1.33314 +    bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
 1.33315 +      return is_sameN(n) && is_same##axis(val); \
 1.33316 +    } \
 1.33317 +
 1.33318 +#define _cimglist_def_is_same2(axis1,axis2) \
 1.33319 +    bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
 1.33320 +      bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
 1.33321 +    } \
 1.33322 +    bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
 1.33323 +      return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
 1.33324 +    } \
 1.33325 +
 1.33326 +#define _cimglist_def_is_same3(axis1,axis2,axis3) \
 1.33327 +    bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
 1.33328 +      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; \
 1.33329 +    } \
 1.33330 +    bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
 1.33331 +      return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
 1.33332 +    } \
 1.33333 +
 1.33334 +#define _cimglist_def_is_same(axis) \
 1.33335 +    template<typename t> bool is_same##axis(const CImg<t>& img) const { \
 1.33336 +      bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(img); return res; \
 1.33337 +    } \
 1.33338 +    template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
 1.33339 +      const unsigned int lmin = cimg::min(size,list.size); \
 1.33340 +      bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
 1.33341 +    } \
 1.33342 +    template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
 1.33343 +      return (is_sameN(n) && is_same##axis(img)); \
 1.33344 +    } \
 1.33345 +    template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
 1.33346 +      return (is_sameN(list) && is_same##axis(list)); \
 1.33347 +    }
 1.33348 +
 1.33349 +    _cimglist_def_is_same(XY)
 1.33350 +    _cimglist_def_is_same(XZ)
 1.33351 +    _cimglist_def_is_same(XV)
 1.33352 +    _cimglist_def_is_same(YZ)
 1.33353 +    _cimglist_def_is_same(YV)
 1.33354 +    _cimglist_def_is_same(XYZ)
 1.33355 +    _cimglist_def_is_same(XYV)
 1.33356 +    _cimglist_def_is_same(YZV)
 1.33357 +    _cimglist_def_is_same(XYZV)
 1.33358 +    _cimglist_def_is_same1(X)
 1.33359 +    _cimglist_def_is_same1(Y)
 1.33360 +    _cimglist_def_is_same1(Z)
 1.33361 +    _cimglist_def_is_same1(V)
 1.33362 +    _cimglist_def_is_same2(X,Y)
 1.33363 +    _cimglist_def_is_same2(X,Z)
 1.33364 +    _cimglist_def_is_same2(X,V)
 1.33365 +    _cimglist_def_is_same2(Y,Z)
 1.33366 +    _cimglist_def_is_same2(Y,V)
 1.33367 +    _cimglist_def_is_same2(Z,V)
 1.33368 +    _cimglist_def_is_same3(X,Y,Z)
 1.33369 +    _cimglist_def_is_same3(X,Y,V)
 1.33370 +    _cimglist_def_is_same3(X,Z,V)
 1.33371 +    _cimglist_def_is_same3(Y,Z,V)
 1.33372 +
 1.33373 +    bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 1.33374 +      bool res = true;
 1.33375 +      for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
 1.33376 +      return res;
 1.33377 +    }
 1.33378 +
 1.33379 +    bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
 1.33380 +      return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
 1.33381 +    }
 1.33382 +
 1.33383 +    //! Return \c true if the list contains the pixel (n,x,y,z,v).
 1.33384 +    bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
 1.33385 +      if (is_empty()) return false;
 1.33386 +      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();
 1.33387 +    }
 1.33388 +
 1.33389 +    //! Return \c true if the list contains the image (n).
 1.33390 +    bool containsN(const int n) const {
 1.33391 +      if (is_empty()) return false;
 1.33392 +      return n>=0 && n<(int)size;
 1.33393 +    }
 1.33394 +
 1.33395 +    //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
 1.33396 +    template<typename t>
 1.33397 +    bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
 1.33398 +      if (is_empty()) return false;
 1.33399 +      cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
 1.33400 +      return false;
 1.33401 +    }
 1.33402 +
 1.33403 +    //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
 1.33404 +    template<typename t>
 1.33405 +    bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
 1.33406 +      t v;
 1.33407 +      return contains(pixel,n,x,y,z,v);
 1.33408 +    }
 1.33409 +
 1.33410 +    //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
 1.33411 +    template<typename t>
 1.33412 +    bool contains(const T& pixel, t& n, t& x, t&y) const {
 1.33413 +      t z,v;
 1.33414 +      return contains(pixel,n,x,y,z,v);
 1.33415 +    }
 1.33416 +
 1.33417 +    //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
 1.33418 +    template<typename t>
 1.33419 +    bool contains(const T& pixel, t& n, t& x) const {
 1.33420 +      t y,z,v;
 1.33421 +      return contains(pixel,n,x,y,z,v);
 1.33422 +    }
 1.33423 +
 1.33424 +    //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n).
 1.33425 +    template<typename t>
 1.33426 +    bool contains(const T& pixel, t& n) const {
 1.33427 +      t x,y,z,v;
 1.33428 +      return contains(pixel,n,x,y,z,v);
 1.33429 +    }
 1.33430 +
 1.33431 +    //! Return \c true if one of the image list contains the specified referenced value.
 1.33432 +    bool contains(const T& pixel) const {
 1.33433 +      unsigned int n,x,y,z,v;
 1.33434 +      return contains(pixel,n,x,y,z,v);
 1.33435 +    }
 1.33436 +
 1.33437 +    //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
 1.33438 +    template<typename t>
 1.33439 +    bool contains(const CImg<T>& img, t& n) const {
 1.33440 +      if (is_empty()) return false;
 1.33441 +      const CImg<T> *const ptr = &img;
 1.33442 +      cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
 1.33443 +      return false;
 1.33444 +    }
 1.33445 +
 1.33446 +    //! Return \c true if the list contains the image img.
 1.33447 +    bool contains(const CImg<T>& img) const {
 1.33448 +      unsigned int n;
 1.33449 +      return contains(img,n);
 1.33450 +    }
 1.33451 +
 1.33452 +    //@}
 1.33453 +    //------------------------------
 1.33454 +    //
 1.33455 +    //! \name Arithmetics Operators
 1.33456 +    //@{
 1.33457 +    //------------------------------
 1.33458 +
 1.33459 +    //! Assignment operator
 1.33460 +    template<typename t>
 1.33461 +    CImgList<T>& operator=(const CImgList<t>& list) {
 1.33462 +      return assign(list);
 1.33463 +    }
 1.33464 +
 1.33465 +    CImgList<T>& operator=(const CImgList<T>& list) {
 1.33466 +      return assign(list);
 1.33467 +    }
 1.33468 +
 1.33469 +    //! Assignment operator.
 1.33470 +    template<typename t>
 1.33471 +    CImgList<T>& operator=(const CImg<t>& img) {
 1.33472 +      cimglist_for(*this,l) data[l] = img;
 1.33473 +      return *this;
 1.33474 +    }
 1.33475 +
 1.33476 +    //! Assignment operator.
 1.33477 +    CImgList<T>& operator=(const T val) {
 1.33478 +      cimglist_for(*this,l) data[l].fill(val);
 1.33479 +      return *this;
 1.33480 +    }
 1.33481 +
 1.33482 +    //! Operator+.
 1.33483 +    CImgList<T> operator+() const {
 1.33484 +      return CImgList<T>(*this);
 1.33485 +    }
 1.33486 +
 1.33487 +    //! Operator+=.
 1.33488 +#ifdef cimg_use_visualcpp6
 1.33489 +    CImgList<T>& operator+=(const T val)
 1.33490 +#else
 1.33491 +    template<typename t>
 1.33492 +    CImgList<T>& operator+=(const t val)
 1.33493 +#endif
 1.33494 +    {
 1.33495 +      cimglist_for(*this,l) (*this)[l]+=val;
 1.33496 +      return *this;
 1.33497 +    }
 1.33498 +
 1.33499 +    //! Operator+=.
 1.33500 +    template<typename t>
 1.33501 +    CImgList<T>& operator+=(const CImgList<t>& list) {
 1.33502 +      const unsigned int sizemax = cimg::min(size,list.size);
 1.33503 +      for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
 1.33504 +      return *this;
 1.33505 +    }
 1.33506 +
 1.33507 +    //! Operator++ (prefix).
 1.33508 +    CImgList<T>& operator++() {
 1.33509 +      cimglist_for(*this,l) ++(*this)[l];
 1.33510 +      return *this;
 1.33511 +    }
 1.33512 +
 1.33513 +    //! Operator++ (postfix).
 1.33514 +    CImgList<T> operator++(int) {
 1.33515 +      CImgList<T> copy(*this);
 1.33516 +      ++*this;
 1.33517 +      return copy;
 1.33518 +    }
 1.33519 +
 1.33520 +    //! Operator-.
 1.33521 +    CImgList<T> operator-() const {
 1.33522 +      CImgList<T> res(size);
 1.33523 +      cimglist_for(res,l) res[l].assign(-data[l]);
 1.33524 +      return res;
 1.33525 +    }
 1.33526 +
 1.33527 +    //! Operator-=.
 1.33528 +#ifdef cimg_use_visualcpp6
 1.33529 +    CImgList<T>& operator-=(const T val)
 1.33530 +#else
 1.33531 +      template<typename t>
 1.33532 +    CImgList<T>& operator-=(const t val)
 1.33533 +#endif
 1.33534 +    {
 1.33535 +      cimglist_for(*this,l) (*this)[l]-=val;
 1.33536 +      return *this;
 1.33537 +    }
 1.33538 +
 1.33539 +    //! Operator-=.
 1.33540 +    template<typename t>
 1.33541 +    CImgList<T>& operator-=(const CImgList<t>& list) {
 1.33542 +      const unsigned int sizemax = min(size,list.size);
 1.33543 +      for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
 1.33544 +      return *this;
 1.33545 +    }
 1.33546 +
 1.33547 +    //! Operator-- (prefix).
 1.33548 +    CImgList<T>& operator--() {
 1.33549 +      cimglist_for(*this,l) --(*this)[l];
 1.33550 +      return *this;
 1.33551 +    }
 1.33552 +
 1.33553 +    //! Operator-- (postfix).
 1.33554 +    CImgList<T> operator--(int) {
 1.33555 +      CImgList<T> copy(*this);
 1.33556 +      --*this;
 1.33557 +      return copy;
 1.33558 +    }
 1.33559 +
 1.33560 +    //! Operator*=.
 1.33561 +#ifdef cimg_use_visualcpp6
 1.33562 +    CImgList<T>& operator*=(const double val)
 1.33563 +#else
 1.33564 +    template<typename t>
 1.33565 +    CImgList<T>& operator*=(const t val)
 1.33566 +#endif
 1.33567 +    {
 1.33568 +      cimglist_for(*this,l) (*this)[l]*=val;
 1.33569 +      return *this;
 1.33570 +    }
 1.33571 +
 1.33572 +    //! Operator*=.
 1.33573 +    template<typename t>
 1.33574 +    CImgList<T>& operator*=(const CImgList<t>& list) {
 1.33575 +      const unsigned int N = cimg::min(size,list.size);
 1.33576 +      for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
 1.33577 +      return this;
 1.33578 +    }
 1.33579 +
 1.33580 +    //! Operator/=.
 1.33581 +#ifdef cimg_use_visualcpp6
 1.33582 +    CImgList<T>& operator/=(const double val)
 1.33583 +#else
 1.33584 +    template<typename t>
 1.33585 +    CImgList<T>& operator/=(const t val)
 1.33586 +#endif
 1.33587 +    {
 1.33588 +      cimglist_for(*this,l) (*this)[l]/=val;
 1.33589 +      return *this;
 1.33590 +    }
 1.33591 +
 1.33592 +    //! Operator/=.
 1.33593 +    template<typename t>
 1.33594 +    CImgList<T>& operator/=(const CImgList<t>& list) {
 1.33595 +      const unsigned int N = cimg::min(size,list.size);
 1.33596 +      for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
 1.33597 +      return this;
 1.33598 +    }
 1.33599 +
 1.33600 +    //! Return a reference to the maximum pixel value of the instance list.
 1.33601 +    const T& max() const {
 1.33602 +      if (is_empty())
 1.33603 +        throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
 1.33604 +                                    pixel_type());
 1.33605 +      const T *ptrmax = data->data;
 1.33606 +      T max_value = *ptrmax;
 1.33607 +      cimglist_for(*this,l) {
 1.33608 +        const CImg<T>& img = data[l];
 1.33609 +        cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 1.33610 +      }
 1.33611 +      return *ptrmax;
 1.33612 +    }
 1.33613 +
 1.33614 +    //! Return a reference to the maximum pixel value of the instance list.
 1.33615 +    T& max() {
 1.33616 +      if (is_empty())
 1.33617 +        throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
 1.33618 +                                    pixel_type());
 1.33619 +      T *ptrmax = data->data;
 1.33620 +      T max_value = *ptrmax;
 1.33621 +      cimglist_for(*this,l) {
 1.33622 +        const CImg<T>& img = data[l];
 1.33623 +        cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 1.33624 +      }
 1.33625 +      return *ptrmax;
 1.33626 +    }
 1.33627 +
 1.33628 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33629 +    const T& min() const {
 1.33630 +      if (is_empty())
 1.33631 +        throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
 1.33632 +                                    pixel_type());
 1.33633 +      const T *ptrmin = data->data;
 1.33634 +      T min_value = *ptrmin;
 1.33635 +      cimglist_for(*this,l) {
 1.33636 +        const CImg<T>& img = data[l];
 1.33637 +        cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 1.33638 +      }
 1.33639 +      return *ptrmin;
 1.33640 +    }
 1.33641 +
 1.33642 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33643 +    T& min() {
 1.33644 +      if (is_empty())
 1.33645 +        throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
 1.33646 +                                    pixel_type());
 1.33647 +      T *ptrmin = data->data;
 1.33648 +      T min_value = *ptrmin;
 1.33649 +      cimglist_for(*this,l) {
 1.33650 +        const CImg<T>& img = data[l];
 1.33651 +        cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 1.33652 +      }
 1.33653 +      return *ptrmin;
 1.33654 +    }
 1.33655 +
 1.33656 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33657 +    template<typename t>
 1.33658 +    const T& minmax(t& max_val) const {
 1.33659 +      if (is_empty())
 1.33660 +        throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
 1.33661 +                                    pixel_type());
 1.33662 +      const T *ptrmin = data->data;
 1.33663 +      T min_value = *ptrmin, max_value = min_value;
 1.33664 +      cimglist_for(*this,l) {
 1.33665 +        const CImg<T>& img = data[l];
 1.33666 +        cimg_for(img,ptr,T) {
 1.33667 +          const T val = *ptr;
 1.33668 +          if (val<min_value) { min_value = val; ptrmin = ptr; }
 1.33669 +          if (val>max_value) max_value = val;
 1.33670 +        }
 1.33671 +      }
 1.33672 +      max_val = (t)max_value;
 1.33673 +      return *ptrmin;
 1.33674 +    }
 1.33675 +
 1.33676 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33677 +    template<typename t>
 1.33678 +    T& minmax(t& max_val) {
 1.33679 +      if (is_empty())
 1.33680 +        throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
 1.33681 +                                    pixel_type());
 1.33682 +      T *ptrmin = data->data;
 1.33683 +      T min_value = *ptrmin, max_value = min_value;
 1.33684 +      cimglist_for(*this,l) {
 1.33685 +        const CImg<T>& img = data[l];
 1.33686 +        cimg_for(img,ptr,T) {
 1.33687 +          const T val = *ptr;
 1.33688 +          if (val<min_value) { min_value = val; ptrmin = ptr; }
 1.33689 +          if (val>max_value) max_value = val;
 1.33690 +        }
 1.33691 +      }
 1.33692 +      max_val = (t)max_value;
 1.33693 +      return *ptrmin;
 1.33694 +    }
 1.33695 +
 1.33696 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33697 +    template<typename t>
 1.33698 +    const T& maxmin(t& min_val) const {
 1.33699 +      if (is_empty())
 1.33700 +        throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
 1.33701 +                                    pixel_type());
 1.33702 +      const T *ptrmax = data->data;
 1.33703 +      T min_value = *ptrmax, max_value = min_value;
 1.33704 +      cimglist_for(*this,l) {
 1.33705 +        const CImg<T>& img = data[l];
 1.33706 +        cimg_for(img,ptr,T) {
 1.33707 +          const T val = *ptr;
 1.33708 +          if (val>max_value) { max_value = val; ptrmax = ptr; }
 1.33709 +          if (val<min_value) min_value = val;
 1.33710 +        }
 1.33711 +      }
 1.33712 +      min_val = (t)min_value;
 1.33713 +      return *ptrmax;
 1.33714 +    }
 1.33715 +
 1.33716 +    //! Return a reference to the minimum pixel value of the instance list.
 1.33717 +    template<typename t>
 1.33718 +    T& maxmin(t& min_val) {
 1.33719 +      if (is_empty())
 1.33720 +        throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
 1.33721 +                                    pixel_type());
 1.33722 +      T *ptrmax = data->data;
 1.33723 +      T min_value = *ptrmax, max_value = min_value;
 1.33724 +      cimglist_for(*this,l) {
 1.33725 +        const CImg<T>& img = data[l];
 1.33726 +        cimg_for(img,ptr,T) {
 1.33727 +          const T val = *ptr;
 1.33728 +          if (val>max_value) { max_value = val; ptrmax = ptr; }
 1.33729 +          if (val<min_value) min_value = val;
 1.33730 +        }
 1.33731 +      }
 1.33732 +      min_val = (t)min_value;
 1.33733 +      return *ptrmax;
 1.33734 +    }
 1.33735 +
 1.33736 +    //! Return the mean pixel value of the instance list.
 1.33737 +    double mean() const {
 1.33738 +      if (is_empty())
 1.33739 +        throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",
 1.33740 +                                    pixel_type());
 1.33741 +      double val = 0;
 1.33742 +      unsigned int siz = 0;
 1.33743 +      cimglist_for(*this,l) {
 1.33744 +        const CImg<T>& img = data[l];
 1.33745 +        cimg_for(img,ptr,T) val+=(double)*ptr;
 1.33746 +        siz+=img.size();
 1.33747 +      }
 1.33748 +      return val/siz;
 1.33749 +    }
 1.33750 +
 1.33751 +    //! Return the variance of the instance list.
 1.33752 +    double variance() {
 1.33753 +      if (is_empty())
 1.33754 +        throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",
 1.33755 +                                    pixel_type());
 1.33756 +      double res = 0;
 1.33757 +      unsigned int siz = 0;
 1.33758 +      double S = 0, S2 = 0;
 1.33759 +      cimglist_for(*this,l) {
 1.33760 +        const CImg<T>& img = data[l];
 1.33761 +        cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
 1.33762 +        siz+=img.size();
 1.33763 +      }
 1.33764 +      res = (S2 - S*S/siz)/siz;
 1.33765 +      return res;
 1.33766 +    }
 1.33767 +
 1.33768 +    //! Compute a list of statistics vectors (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
 1.33769 +    CImgList<T>& stats(const unsigned int variance_method=1) {
 1.33770 +      if (is_empty()) return *this;
 1.33771 +      cimglist_for(*this,l) data[l].stats(variance_method);
 1.33772 +      return *this;
 1.33773 +    }
 1.33774 +
 1.33775 +    CImgList<Tfloat> get_stats(const unsigned int variance_method=1) const {
 1.33776 +      CImgList<Tfloat> res(size);
 1.33777 +      cimglist_for(*this,l) res[l] = data[l].get_stats(variance_method);
 1.33778 +      return res;
 1.33779 +    }
 1.33780 +
 1.33781 +    //@}
 1.33782 +    //-------------------------
 1.33783 +    //
 1.33784 +    //! \name List Manipulation
 1.33785 +    //@{
 1.33786 +    //-------------------------
 1.33787 +
 1.33788 +    //! Return a reference to the i-th element of the image list.
 1.33789 +    CImg<T>& operator[](const unsigned int pos) {
 1.33790 +#if cimg_debug>=3
 1.33791 +      if (pos>=size) {
 1.33792 +        cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
 1.33793 +                   pixel_type(),pos,size);
 1.33794 +        return *data;
 1.33795 +      }
 1.33796 +#endif
 1.33797 +      return data[pos];
 1.33798 +    }
 1.33799 +
 1.33800 +    const CImg<T>& operator[](const unsigned int pos) const {
 1.33801 +#if cimg_debug>=3
 1.33802 +      if (pos>=size) {
 1.33803 +        cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
 1.33804 +                   pixel_type(),pos,size);
 1.33805 +        return *data;
 1.33806 +      }
 1.33807 +#endif
 1.33808 +      return data[pos];
 1.33809 +    }
 1.33810 +
 1.33811 +    //! Equivalent to CImgList<T>::operator[]
 1.33812 +    CImg<T>& operator()(const unsigned int pos) {
 1.33813 +      return (*this)[pos];
 1.33814 +    }
 1.33815 +
 1.33816 +    const CImg<T>& operator()(const unsigned int pos) const {
 1.33817 +      return (*this)[pos];
 1.33818 +    }
 1.33819 +
 1.33820 +    //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list
 1.33821 +    T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
 1.33822 +                  const unsigned int z=0, const unsigned int v=0) {
 1.33823 +      return (*this)[pos](x,y,z,v);
 1.33824 +    }
 1.33825 +    const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
 1.33826 +                        const unsigned int z=0, const unsigned int v=0) const {
 1.33827 +      return (*this)[pos](x,y,z,v);
 1.33828 +    }
 1.33829 +
 1.33830 +    // This function is only here for template tricks.
 1.33831 +    T _display_object3d_at2(const int i, const int j) const {
 1.33832 +      return atNXY(i,0,j,0,0,0);
 1.33833 +    }
 1.33834 +
 1.33835 +    //! Read an image in specified position.
 1.33836 +    CImg<T>& at(const int pos) {
 1.33837 +      if (is_empty())
 1.33838 +        throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
 1.33839 +                                    pixel_type());
 1.33840 +      return data[pos<0?0:pos>=(int)size?(int)size-1:pos];
 1.33841 +    }
 1.33842 +
 1.33843 +    //! Read a pixel value with Dirichlet boundary conditions.
 1.33844 +    T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 1.33845 +      return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
 1.33846 +    }
 1.33847 +
 1.33848 +    T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 1.33849 +      return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
 1.33850 +    }
 1.33851 +
 1.33852 +    //! Read a pixel value with Neumann boundary conditions.
 1.33853 +    T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
 1.33854 +      if (is_empty())
 1.33855 +        throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
 1.33856 +                                    pixel_type());
 1.33857 +      return _atNXYZV(pos,x,y,z,v);
 1.33858 +    }
 1.33859 +
 1.33860 +    T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
 1.33861 +      if (is_empty())
 1.33862 +        throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
 1.33863 +                                    pixel_type());
 1.33864 +      return _atNXYZV(pos,x,y,z,v);
 1.33865 +    }
 1.33866 +
 1.33867 +    T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
 1.33868 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
 1.33869 +    }
 1.33870 +
 1.33871 +    T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
 1.33872 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
 1.33873 +    }
 1.33874 +
 1.33875 +    //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
 1.33876 +    T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 1.33877 +      return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
 1.33878 +    }
 1.33879 +
 1.33880 +    T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 1.33881 +      return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
 1.33882 +    }
 1.33883 +
 1.33884 +    //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
 1.33885 +    T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
 1.33886 +      if (is_empty())
 1.33887 +        throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
 1.33888 +                                    pixel_type());
 1.33889 +      return _atNXYZ(pos,x,y,z,v);
 1.33890 +    }
 1.33891 +
 1.33892 +    T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
 1.33893 +      if (is_empty())
 1.33894 +        throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
 1.33895 +                                    pixel_type());
 1.33896 +      return _atNXYZ(pos,x,y,z,v);
 1.33897 +    }
 1.33898 +
 1.33899 +    T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
 1.33900 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
 1.33901 +    }
 1.33902 +
 1.33903 +    T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
 1.33904 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
 1.33905 +    }
 1.33906 +
 1.33907 +    //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y).
 1.33908 +    T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 1.33909 +      return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
 1.33910 +    }
 1.33911 +
 1.33912 +    T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 1.33913 +      return (pos<0 || pos>=(int)size)?out_val:data[pos].atXY(x,y,z,v,out_val);
 1.33914 +    }
 1.33915 +
 1.33916 +    //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y).
 1.33917 +    T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
 1.33918 +      if (is_empty())
 1.33919 +        throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
 1.33920 +                                    pixel_type());
 1.33921 +      return _atNXY(pos,x,y,z,v);
 1.33922 +    }
 1.33923 +
 1.33924 +    T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
 1.33925 +      if (is_empty())
 1.33926 +        throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
 1.33927 +                                    pixel_type());
 1.33928 +      return _atNXY(pos,x,y,z,v);
 1.33929 +    }
 1.33930 +
 1.33931 +    T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
 1.33932 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
 1.33933 +    }
 1.33934 +
 1.33935 +    T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
 1.33936 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
 1.33937 +    }
 1.33938 +
 1.33939 +    //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x).
 1.33940 +    T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 1.33941 +      return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
 1.33942 +    }
 1.33943 +
 1.33944 +    T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 1.33945 +      return (pos<0 || pos>=(int)size)?out_val:data[pos].atX(x,y,z,v,out_val);
 1.33946 +    }
 1.33947 +
 1.33948 +    //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x).
 1.33949 +    T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
 1.33950 +      if (is_empty())
 1.33951 +        throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
 1.33952 +                                    pixel_type());
 1.33953 +      return _atNX(pos,x,y,z,v);
 1.33954 +    }
 1.33955 +
 1.33956 +    T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
 1.33957 +      if (is_empty())
 1.33958 +        throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
 1.33959 +                                    pixel_type());
 1.33960 +      return _atNX(pos,x,y,z,v);
 1.33961 +    }
 1.33962 +
 1.33963 +    T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
 1.33964 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
 1.33965 +    }
 1.33966 +
 1.33967 +    T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
 1.33968 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
 1.33969 +    }
 1.33970 +
 1.33971 +    //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos).
 1.33972 +    T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
 1.33973 +      return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
 1.33974 +    }
 1.33975 +
 1.33976 +    T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
 1.33977 +      return (pos<0 || pos>=(int)size)?out_val:(*this)(pos,x,y,z,v);
 1.33978 +    }
 1.33979 +
 1.33980 +    //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos).
 1.33981 +    T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
 1.33982 +      if (is_empty())
 1.33983 +        throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
 1.33984 +                                    pixel_type());
 1.33985 +      return _atN(pos,x,y,z,v);
 1.33986 +    }
 1.33987 +
 1.33988 +    T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
 1.33989 +      if (is_empty())
 1.33990 +        throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
 1.33991 +                                    pixel_type());
 1.33992 +      return _atN(pos,x,y,z,v);
 1.33993 +    }
 1.33994 +
 1.33995 +    T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
 1.33996 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
 1.33997 +    }
 1.33998 +
 1.33999 +    T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
 1.34000 +      return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
 1.34001 +    }
 1.34002 +
 1.34003 +    //! Returns a reference to the last element.
 1.34004 +    CImg<T>& back() {
 1.34005 +      return (*this)(size-1);
 1.34006 +    }
 1.34007 +
 1.34008 +    const CImg<T>& back() const {
 1.34009 +      return (*this)(size-1);
 1.34010 +    }
 1.34011 +
 1.34012 +    //! Returns a reference to the first element.
 1.34013 +    CImg<T>& front() {
 1.34014 +      return *data;
 1.34015 +    }
 1.34016 +
 1.34017 +    const CImg<T>& front() const {
 1.34018 +      return *data;
 1.34019 +    }
 1.34020 +
 1.34021 +    //! Returns an iterator to the beginning of the vector.
 1.34022 +    iterator begin() {
 1.34023 +      return data;
 1.34024 +    }
 1.34025 +
 1.34026 +    const_iterator begin() const {
 1.34027 +      return data;
 1.34028 +    }
 1.34029 +
 1.34030 +    //! Return a reference to the first image.
 1.34031 +    const CImg<T>& first() const {
 1.34032 +      return *data;
 1.34033 +    }
 1.34034 +
 1.34035 +    CImg<T>& first() {
 1.34036 +      return *data;
 1.34037 +    }
 1.34038 +
 1.34039 +    //! Returns an iterator just past the last element.
 1.34040 +    iterator end() {
 1.34041 +      return data + size;
 1.34042 +    }
 1.34043 +
 1.34044 +    const_iterator end() const {
 1.34045 +      return data + size;
 1.34046 +    }
 1.34047 +
 1.34048 +    //! Return a reference to the last image.
 1.34049 +    const CImg<T>& last() const {
 1.34050 +      return data[size - 1];
 1.34051 +    }
 1.34052 +
 1.34053 +    CImg<T>& last() {
 1.34054 +      return data[size - 1];
 1.34055 +    }
 1.34056 +
 1.34057 +    //! Insert a copy of the image \p img into the current image list, at position \p pos.
 1.34058 +    template<typename t>
 1.34059 +    CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
 1.34060 +      const unsigned int npos = pos==~0U?size:pos;
 1.34061 +      if (npos>size)
 1.34062 +        throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
 1.34063 +                                    pixel_type(),npos,size);
 1.34064 +      if (shared)
 1.34065 +        throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
 1.34066 +                                    pixel_type(),img.pixel_type(),pixel_type());
 1.34067 +      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
 1.34068 +      if (!size || !data) {
 1.34069 +        data = new_data;
 1.34070 +        *data = img;
 1.34071 +      } else {
 1.34072 +        if (new_data) {
 1.34073 +          if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
 1.34074 +          if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 1.34075 +          cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
 1.34076 +          delete[] data;
 1.34077 +          data = new_data;
 1.34078 +        }
 1.34079 +        else if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 1.34080 +        data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
 1.34081 +        data[npos] = img;
 1.34082 +      }
 1.34083 +      return *this;
 1.34084 +    }
 1.34085 +
 1.34086 +    CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
 1.34087 +      const unsigned int npos = pos==~0U?size:pos;
 1.34088 +      if (npos>size)
 1.34089 +        throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
 1.34090 +                                    pixel_type(),npos,size);
 1.34091 +      if (&img>=data && &img<data+size) return insert(+img,pos,shared);
 1.34092 +      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
 1.34093 +      if (!size || !data) {
 1.34094 +        data = new_data;
 1.34095 +        if (shared && img) {
 1.34096 +          data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
 1.34097 +          data->is_shared = true; data->data = img.data;
 1.34098 +        } else *data = img;
 1.34099 +      }
 1.34100 +      else {
 1.34101 +        if (new_data) {
 1.34102 +          if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
 1.34103 +          if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 1.34104 +          if (shared && img) {
 1.34105 +            new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
 1.34106 +            new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
 1.34107 +          } else {
 1.34108 +            new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
 1.34109 +            new_data[npos] = img;
 1.34110 +          }
 1.34111 +          cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
 1.34112 +          delete[] data;
 1.34113 +          data = new_data;
 1.34114 +        } else {
 1.34115 +          if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
 1.34116 +          if (shared && img) {
 1.34117 +            data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
 1.34118 +            data[npos].is_shared = true; data[npos].data = img.data;
 1.34119 +          } else {
 1.34120 +            data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
 1.34121 +            data[npos] = img;
 1.34122 +          }
 1.34123 +        }
 1.34124 +      }
 1.34125 +      return *this;
 1.34126 +    }
 1.34127 +
 1.34128 +    // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
 1.34129 +    // default parameters are used in function signatures.
 1.34130 +    template<typename t>
 1.34131 +    CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
 1.34132 +      return insert(img,pos,false);
 1.34133 +    }
 1.34134 +
 1.34135 +    //! Insert a copy of the image \p img into the current image list, at position \p pos.
 1.34136 +    template<typename t>
 1.34137 +    CImgList<T>& insert(const CImg<t>& img) {
 1.34138 +      return insert(img,~0U,false);
 1.34139 +    }
 1.34140 +
 1.34141 +    template<typename t>
 1.34142 +    CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 1.34143 +      return (+*this).insert(img,pos,shared);
 1.34144 +    }
 1.34145 +
 1.34146 +    //! Insert n empty images img into the current image list, at position \p pos.
 1.34147 +    CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
 1.34148 +      CImg<T> foo;
 1.34149 +      if (!n) return *this;
 1.34150 +      const unsigned int npos = pos==~0U?size:pos;
 1.34151 +      for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
 1.34152 +      return *this;
 1.34153 +    }
 1.34154 +
 1.34155 +    CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
 1.34156 +      return (+*this).insert(n,pos);
 1.34157 +    }
 1.34158 +
 1.34159 +    //! Insert n copies of the image \p img into the current image list, at position \p pos.
 1.34160 +    template<typename t>
 1.34161 +    CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
 1.34162 +      if (!n) return *this;
 1.34163 +      const unsigned int npos = pos==~0U?size:pos;
 1.34164 +      insert(img,npos,shared);
 1.34165 +      for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
 1.34166 +      return *this;
 1.34167 +    }
 1.34168 +
 1.34169 +    template<typename t>
 1.34170 +    CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 1.34171 +      return (+*this).insert(n,img,pos,shared);
 1.34172 +    }
 1.34173 +
 1.34174 +    //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
 1.34175 +    template<typename t>
 1.34176 +    CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
 1.34177 +      const unsigned int npos = pos==~0U?size:pos;
 1.34178 +      if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
 1.34179 +      else insert(CImgList<T>(list),npos,shared);
 1.34180 +      return *this;
 1.34181 +    }
 1.34182 +
 1.34183 +    template<typename t>
 1.34184 +    CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 1.34185 +      return (+*this).insert(list,pos,shared);
 1.34186 +    }
 1.34187 +
 1.34188 +    //! Insert n copies of the list \p list at position \p pos of the current list.
 1.34189 +    template<typename t>
 1.34190 +    CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
 1.34191 +      if (!n) return *this;
 1.34192 +      const unsigned int npos = pos==~0U?size:pos;
 1.34193 +      for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
 1.34194 +      return *this;
 1.34195 +    }
 1.34196 +
 1.34197 +    template<typename t>
 1.34198 +    CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 1.34199 +      return (+*this).insert(n,list,pos,shared);
 1.34200 +    }
 1.34201 +
 1.34202 +    //! Insert a copy of the image \p img at the end of the current image list.
 1.34203 +    template<typename t>
 1.34204 +    CImgList<T>& operator<<(const CImg<t>& img) {
 1.34205 +      return insert(img);
 1.34206 +    }
 1.34207 +
 1.34208 +    //! Insert a copy of the image list \p list at the end of the current image list.
 1.34209 +    template<typename t>
 1.34210 +    CImgList<T>& operator<<(const CImgList<t>& list) {
 1.34211 +      return insert(list);
 1.34212 +    }
 1.34213 +
 1.34214 +    //! Return a copy of the current image list, where the image \p img has been inserted at the end.
 1.34215 +    template<typename t>
 1.34216 +    CImgList<T>& operator>>(CImg<t>& img) const {
 1.34217 +      typedef typename cimg::superset<T,t>::type Tt;
 1.34218 +      return CImgList<Tt>(*this).insert(img);
 1.34219 +    }
 1.34220 +
 1.34221 +    //! Insert a copy of the current image list at the beginning of the image list \p list.
 1.34222 +    template<typename t>
 1.34223 +    CImgList<T>& operator>>(CImgList<t>& list) const {
 1.34224 +      return list.insert(*this,0);
 1.34225 +    }
 1.34226 +
 1.34227 +    //! Remove the images at positions \p pos1 to \p pos2 from the image list.
 1.34228 +    CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
 1.34229 +      const unsigned int
 1.34230 +        npos1 = pos1<pos2?pos1:pos2,
 1.34231 +        tpos2 = pos1<pos2?pos2:pos1,
 1.34232 +        npos2 = tpos2<size?tpos2:size-1;
 1.34233 +      if (npos1>=size)
 1.34234 +        cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
 1.34235 +                   pixel_type(),data,size,npos1,tpos2);
 1.34236 +      else {
 1.34237 +        if (tpos2>=size)
 1.34238 +          cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
 1.34239 +                     pixel_type(),data,size,npos1,tpos2);
 1.34240 +        for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
 1.34241 +        const unsigned int nb = 1 + npos2 - npos1;
 1.34242 +        if (!(size-=nb)) return assign();
 1.34243 +        if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
 1.34244 +          if (npos1!=size) cimg_std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 1.34245 +          cimg_std::memset(data+size,0,sizeof(CImg<T>)*nb);
 1.34246 +        } else { // Removing items with reallocation.
 1.34247 +          allocsize>>=2;
 1.34248 +          while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
 1.34249 +          CImg<T> *new_data = new CImg<T>[allocsize];
 1.34250 +          if (npos1) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
 1.34251 +          if (npos1!=size) cimg_std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 1.34252 +          if (size!=allocsize) cimg_std::memset(new_data+size,0,sizeof(allocsize-size));
 1.34253 +          cimg_std::memset(data,0,sizeof(CImg<T>)*(size+nb));
 1.34254 +          delete[] data;
 1.34255 +          data = new_data;
 1.34256 +        }
 1.34257 +      }
 1.34258 +      return *this;
 1.34259 +    }
 1.34260 +
 1.34261 +    CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
 1.34262 +      return (+*this).remove(pos1,pos2);
 1.34263 +    }
 1.34264 +
 1.34265 +    //! Remove the image at position \p pos from the image list.
 1.34266 +    CImgList<T>& remove(const unsigned int pos) {
 1.34267 +      return remove(pos,pos);
 1.34268 +    }
 1.34269 +
 1.34270 +    CImgList<T> get_remove(const unsigned int pos) const {
 1.34271 +      return (+*this).remove(pos);
 1.34272 +    }
 1.34273 +
 1.34274 +    //! Remove the last image from the image list.
 1.34275 +    CImgList<T>& remove() {
 1.34276 +      if (size) return remove(size-1);
 1.34277 +      else cimg::warn("CImgList<%s>::remove() : List is empty",
 1.34278 +                      pixel_type());
 1.34279 +      return *this;
 1.34280 +    }
 1.34281 +
 1.34282 +    CImgList<T> get_remove() const {
 1.34283 +      return (+*this).remove();
 1.34284 +    }
 1.34285 +
 1.34286 +    //! Reverse list order.
 1.34287 +    CImgList<T>& reverse() {
 1.34288 +      for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
 1.34289 +      return *this;
 1.34290 +    }
 1.34291 +
 1.34292 +    CImgList<T> get_reverse() const {
 1.34293 +      return (+*this).reverse();
 1.34294 +    }
 1.34295 +
 1.34296 +    //! Get a sub-list.
 1.34297 +    CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
 1.34298 +      return get_crop(i0,i1,shared).transfer_to(*this);
 1.34299 +    }
 1.34300 +
 1.34301 +    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
 1.34302 +      if (i0>i1 || i1>=size)
 1.34303 +        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 1.34304 +                                    pixel_type(),i0,i1,size,data);
 1.34305 +      CImgList<T> res(i1-i0+1);
 1.34306 +      cimglist_for(res,l) res[l].assign((*this)[i0+l],shared);
 1.34307 +      return res;
 1.34308 +    }
 1.34309 +
 1.34310 +    //! Get sub-images of a sublist.
 1.34311 +    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 1.34312 +                      const int x0, const int y0, const int z0, const int v0,
 1.34313 +                      const int x1, const int y1, const int z1, const int v1) {
 1.34314 +      return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
 1.34315 +    }
 1.34316 +
 1.34317 +    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 1.34318 +                         const int x0, const int y0, const int z0, const int v0,
 1.34319 +                         const int x1, const int y1, const int z1, const int v1) const {
 1.34320 +      if (i0>i1 || i1>=size)
 1.34321 +        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 1.34322 +                                    pixel_type(),i0,i1,size,data);
 1.34323 +      CImgList<T> res(i1-i0+1);
 1.34324 +      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
 1.34325 +      return res;
 1.34326 +    }
 1.34327 +
 1.34328 +    //! Get sub-images of a sublist.
 1.34329 +    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 1.34330 +                      const int x0, const int y0, const int z0,
 1.34331 +                      const int x1, const int y1, const int z1) {
 1.34332 +      return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
 1.34333 +    }
 1.34334 +
 1.34335 +    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 1.34336 +                         const int x0, const int y0, const int z0,
 1.34337 +                         const int x1, const int y1, const int z1) const {
 1.34338 +      if (i0>i1 || i1>=size)
 1.34339 +        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 1.34340 +                                    pixel_type(),i0,i1,size,data);
 1.34341 +      CImgList<T> res(i1-i0+1);
 1.34342 +      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
 1.34343 +      return res;
 1.34344 +    }
 1.34345 +
 1.34346 +    //! Get sub-images of a sublist.
 1.34347 +    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 1.34348 +                      const int x0, const int y0,
 1.34349 +                      const int x1, const int y1) {
 1.34350 +      return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
 1.34351 +    }
 1.34352 +
 1.34353 +    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 1.34354 +                         const int x0, const int y0,
 1.34355 +                         const int x1, const int y1) const {
 1.34356 +      if (i0>i1 || i1>=size)
 1.34357 +        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 1.34358 +                                    pixel_type(),i0,i1,size,data);
 1.34359 +      CImgList<T> res(i1-i0+1);
 1.34360 +      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
 1.34361 +      return res;
 1.34362 +    }
 1.34363 +
 1.34364 +    //! Get sub-images of a sublist.
 1.34365 +    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 1.34366 +                      const int x0, const int x1) {
 1.34367 +      return get_crop(i0,i1,x0,x1).transfer_to(*this);
 1.34368 +    }
 1.34369 +
 1.34370 +    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 1.34371 +                         const int x0, const int x1) const {
 1.34372 +      if (i0>i1 || i1>=size)
 1.34373 +        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 1.34374 +                                    pixel_type(),i0,i1,size,data);
 1.34375 +      CImgList<T> res(i1-i0+1);
 1.34376 +      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,x1);
 1.34377 +      return res;
 1.34378 +    }
 1.34379 +
 1.34380 +    //! Display an image list into a CImgDisplay.
 1.34381 +    const CImgList<T>& operator>>(CImgDisplay& disp) const {
 1.34382 +      return display(disp);
 1.34383 +    }
 1.34384 +
 1.34385 +    //! Insert image \p img at the end of the list.
 1.34386 +    template<typename t>
 1.34387 +    CImgList<T>& push_back(const CImg<t>& img) {
 1.34388 +      return insert(img);
 1.34389 +    }
 1.34390 +
 1.34391 +    //! Insert image \p img at the front of the list.
 1.34392 +    template<typename t>
 1.34393 +    CImgList<T>& push_front(const CImg<t>& img) {
 1.34394 +      return insert(img,0);
 1.34395 +    }
 1.34396 +
 1.34397 +    //! Insert list \p list at the end of the current list.
 1.34398 +    template<typename t>
 1.34399 +    CImgList<T>& push_back(const CImgList<t>& list) {
 1.34400 +      return insert(list);
 1.34401 +    }
 1.34402 +
 1.34403 +    //! Insert list \p list at the front of the current list.
 1.34404 +    template<typename t>
 1.34405 +    CImgList<T>& push_front(const CImgList<t>& list) {
 1.34406 +      return insert(list,0);
 1.34407 +    }
 1.34408 +
 1.34409 +    //! Remove last element of the list.
 1.34410 +    CImgList<T>& pop_back() {
 1.34411 +      return remove(size-1);
 1.34412 +    }
 1.34413 +
 1.34414 +    //! Remove first element of the list.
 1.34415 +    CImgList<T>& pop_front() {
 1.34416 +      return remove(0);
 1.34417 +    }
 1.34418 +
 1.34419 +    //! Remove the element pointed by iterator \p iter.
 1.34420 +    CImgList<T>& erase(const iterator iter) {
 1.34421 +      return remove(iter-data);
 1.34422 +    }
 1.34423 +
 1.34424 +    //@}
 1.34425 +    //----------------------------
 1.34426 +    //
 1.34427 +    //! \name Fourier Transforms
 1.34428 +    //@{
 1.34429 +    //----------------------------
 1.34430 +
 1.34431 +    //! Compute the Fast Fourier Transform (along the specified axis).
 1.34432 +    CImgList<T>& FFT(const char axis, const bool invert=false) {
 1.34433 +      if (is_empty())
 1.34434 +        throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
 1.34435 +                                    pixel_type(),size,data);
 1.34436 +      if (!data[0])
 1.34437 +        throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
 1.34438 +                                                pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
 1.34439 +      if (size>2)
 1.34440 +        cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
 1.34441 +                   pixel_type(),size,data);
 1.34442 +      if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
 1.34443 +      CImg<T> &Ir = data[0], &Ii = data[1];
 1.34444 +      if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
 1.34445 +        throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)"
 1.34446 +                                    "have different dimensions",
 1.34447 +                                    pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
 1.34448 +
 1.34449 +#ifdef cimg_use_fftw3
 1.34450 +      fftw_complex *data_in;
 1.34451 +      fftw_plan data_plan;
 1.34452 +
 1.34453 +      switch (cimg::uncase(axis)) {
 1.34454 +      case 'x' : {
 1.34455 +        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Ir.width);
 1.34456 +        data_plan = fftw_plan_dft_1d(Ir.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 1.34457 +        cimg_forYZV(Ir,y,z,k) {
 1.34458 +          T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
 1.34459 +          double *ptrd = (double*)data_in;
 1.34460 +          cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
 1.34461 +          fftw_execute(data_plan);
 1.34462 +          const unsigned int fact = Ir.width;
 1.34463 +          if (invert) { cimg_forX(Ir,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }}
 1.34464 +          else { cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }}
 1.34465 +        }
 1.34466 +      } break;
 1.34467 +
 1.34468 +      case 'y' : {
 1.34469 +        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
 1.34470 +        data_plan = fftw_plan_dft_1d(Ir.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 1.34471 +        const unsigned int off = Ir.width;
 1.34472 +        cimg_forXZV(Ir,x,z,k) {
 1.34473 +          T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
 1.34474 +          double *ptrd = (double*)data_in;
 1.34475 +          cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 1.34476 +          fftw_execute(data_plan);
 1.34477 +          const unsigned int fact = Ir.height;
 1.34478 +          if (invert) { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 1.34479 +          else { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 1.34480 +        }
 1.34481 +      } break;
 1.34482 +
 1.34483 +      case 'z' : {
 1.34484 +        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
 1.34485 +        data_plan = fftw_plan_dft_1d(Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 1.34486 +        const unsigned int off = Ir.width*Ir.height;
 1.34487 +        cimg_forXYV(Ir,x,y,k) {
 1.34488 +          T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
 1.34489 +          double *ptrd = (double*)data_in;
 1.34490 +          cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 1.34491 +          fftw_execute(data_plan);
 1.34492 +          const unsigned int fact = Ir.depth;
 1.34493 +          if (invert) { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 1.34494 +          else { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 1.34495 +        }
 1.34496 +      } break;
 1.34497 +
 1.34498 +      case 'v' : {
 1.34499 +        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
 1.34500 +        data_plan = fftw_plan_dft_1d(Ir.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 1.34501 +        const unsigned int off = Ir.width*Ir.height*Ir.depth;
 1.34502 +        cimg_forXYZ(Ir,x,y,z) {
 1.34503 +          T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
 1.34504 +          double *ptrd = (double*)data_in;
 1.34505 +          cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
 1.34506 +          fftw_execute(data_plan);
 1.34507 +          const unsigned int fact = Ir.dim;
 1.34508 +          if (invert) { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
 1.34509 +          else { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
 1.34510 +        }
 1.34511 +      } break;
 1.34512 +      }
 1.34513 +
 1.34514 +      fftw_destroy_plan(data_plan);
 1.34515 +      fftw_free(data_in);
 1.34516 +#else
 1.34517 +      switch (cimg::uncase(axis)) {
 1.34518 +      case 'x' : { // Fourier along X
 1.34519 +        const unsigned int N = Ir.width, N2 = (N>>1);
 1.34520 +        if (((N-1)&N) && N!=1)
 1.34521 +          throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
 1.34522 +                                      pixel_type(),N);
 1.34523 +        for (unsigned int i=0, j=0; i<N2; ++i) {
 1.34524 +          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));
 1.34525 +          if (j<N2) {
 1.34526 +            const unsigned int ri = N-1-i, rj = N-1-j;
 1.34527 +            cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
 1.34528 +          }}
 1.34529 +          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 1.34530 +        }
 1.34531 +        for (unsigned int delta=2; delta<=N; delta<<=1) {
 1.34532 +          const unsigned int delta2 = (delta>>1);
 1.34533 +          for (unsigned int i=0; i<N; i+=delta) {
 1.34534 +            float wr = 1, wi = 0;
 1.34535 +            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 1.34536 +                        ca = (float)cimg_std::cos(angle),
 1.34537 +                        sa = (float)cimg_std::sin(angle);
 1.34538 +            for (unsigned int k=0; k<delta2; ++k) {
 1.34539 +              const unsigned int j = i + k, nj = j + delta2;
 1.34540 +              cimg_forYZV(Ir,y,z,k) {
 1.34541 +                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);
 1.34542 +                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 1.34543 +                nir = (T)(ir - tmpr);
 1.34544 +                nii = (T)(ii - tmpi);
 1.34545 +                ir += (T)tmpr;
 1.34546 +                ii += (T)tmpi;
 1.34547 +              }
 1.34548 +              const float nwr = wr*ca-wi*sa;
 1.34549 +              wi = wi*ca + wr*sa;
 1.34550 +              wr = nwr;
 1.34551 +            }
 1.34552 +          }
 1.34553 +        }
 1.34554 +        if (invert) (*this)/=N;
 1.34555 +      } break;
 1.34556 +
 1.34557 +      case 'y' : { // Fourier along Y
 1.34558 +        const unsigned int N = Ir.height, N2 = (N>>1);
 1.34559 +        if (((N-1)&N) && N!=1)
 1.34560 +          throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
 1.34561 +                                      pixel_type(),N);
 1.34562 +        for (unsigned int i=0, j=0; i<N2; ++i) {
 1.34563 +          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));
 1.34564 +          if (j<N2) {
 1.34565 +            const unsigned int ri = N-1-i, rj = N-1-j;
 1.34566 +            cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
 1.34567 +          }}
 1.34568 +          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 1.34569 +        }
 1.34570 +        for (unsigned int delta=2; delta<=N; delta<<=1) {
 1.34571 +          const unsigned int delta2 = (delta>>1);
 1.34572 +          for (unsigned int i=0; i<N; i+=delta) {
 1.34573 +            float wr = 1, wi = 0;
 1.34574 +            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 1.34575 +                        ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
 1.34576 +            for (unsigned int k=0; k<delta2; ++k) {
 1.34577 +              const unsigned int j = i + k, nj = j + delta2;
 1.34578 +              cimg_forXZV(Ir,x,z,k) {
 1.34579 +                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);
 1.34580 +                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 1.34581 +                nir = (T)(ir - tmpr);
 1.34582 +                nii = (T)(ii - tmpi);
 1.34583 +                ir += (T)tmpr;
 1.34584 +                ii += (T)tmpi;
 1.34585 +              }
 1.34586 +              const float nwr = wr*ca-wi*sa;
 1.34587 +              wi = wi*ca + wr*sa;
 1.34588 +              wr = nwr;
 1.34589 +            }
 1.34590 +          }
 1.34591 +        }
 1.34592 +        if (invert) (*this)/=N;
 1.34593 +      } break;
 1.34594 +
 1.34595 +      case 'z' : { // Fourier along Z
 1.34596 +        const unsigned int N = Ir.depth, N2 = (N>>1);
 1.34597 +        if (((N-1)&N) && N!=1)
 1.34598 +          throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
 1.34599 +                                      pixel_type(),N);
 1.34600 +        for (unsigned int i=0, j=0; i<N2; ++i) {
 1.34601 +          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));
 1.34602 +          if (j<N2) {
 1.34603 +            const unsigned int ri = N-1-i, rj = N-1-j;
 1.34604 +            cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
 1.34605 +          }}
 1.34606 +          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
 1.34607 +        }
 1.34608 +        for (unsigned int delta=2; delta<=N; delta<<=1) {
 1.34609 +          const unsigned int delta2 = (delta>>1);
 1.34610 +          for (unsigned int i=0; i<N; i+=delta) {
 1.34611 +            float wr = 1, wi = 0;
 1.34612 +            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
 1.34613 +                        ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
 1.34614 +            for (unsigned int k=0; k<delta2; ++k) {
 1.34615 +              const unsigned int j = i + k, nj = j + delta2;
 1.34616 +              cimg_forXYV(Ir,x,y,k) {
 1.34617 +                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);
 1.34618 +                const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
 1.34619 +                nir = (T)(ir - tmpr);
 1.34620 +                nii = (T)(ii - tmpi);
 1.34621 +                ir += (T)tmpr;
 1.34622 +                ii += (T)tmpi;
 1.34623 +              }
 1.34624 +              const float nwr = wr*ca-wi*sa;
 1.34625 +              wi = wi*ca + wr*sa;
 1.34626 +              wr = nwr;
 1.34627 +            }
 1.34628 +          }
 1.34629 +        }
 1.34630 +        if (invert) (*this)/=N;
 1.34631 +      } break;
 1.34632 +
 1.34633 +      default :
 1.34634 +        throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
 1.34635 +      }
 1.34636 +#endif
 1.34637 +      return *this;
 1.34638 +    }
 1.34639 +
 1.34640 +    CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
 1.34641 +      return CImgList<Tfloat>(*this).FFT(axis,invert);
 1.34642 +    }
 1.34643 +
 1.34644 +    //! Compute the Fast Fourier Transform of a complex image.
 1.34645 +    CImgList<T>& FFT(const bool invert=false) {
 1.34646 +      if (is_empty())
 1.34647 +        throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
 1.34648 +                                    pixel_type(),size,data);
 1.34649 +      if (size>2)
 1.34650 +        cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
 1.34651 +                   pixel_type(),size,data);
 1.34652 +      if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
 1.34653 +      CImg<T> &Ir = data[0], &Ii = data[1];
 1.34654 +      if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
 1.34655 +        throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
 1.34656 +                                    "of the instance image have different dimensions",
 1.34657 +                                    pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
 1.34658 +                                    Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
 1.34659 +#ifdef cimg_use_fftw3
 1.34660 +      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
 1.34661 +      fftw_plan data_plan;
 1.34662 +      const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
 1.34663 +      data_plan = fftw_plan_dft_3d(Ir.width,Ir.height,Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
 1.34664 +      cimg_forV(Ir,k) {
 1.34665 +        T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
 1.34666 +        double *ptrd = (double*)data_in;
 1.34667 +        for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 1.34668 +          for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 1.34669 +            for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 1.34670 +              *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
 1.34671 +            }
 1.34672 +        fftw_execute(data_plan);
 1.34673 +        ptrd = (double*)data_in;
 1.34674 +        ptrr = Ir.ptr(0,0,0,k);
 1.34675 +        ptri = Ii.ptr(0,0,0,k);
 1.34676 +        if (!invert) for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 1.34677 +          for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 1.34678 +            for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 1.34679 +              *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
 1.34680 +            }
 1.34681 +        else for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
 1.34682 +          for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
 1.34683 +            for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
 1.34684 +              *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
 1.34685 +            }
 1.34686 +      }
 1.34687 +      fftw_destroy_plan(data_plan);
 1.34688 +      fftw_free(data_in);
 1.34689 +#else
 1.34690 +      if (Ir.depth>1)  FFT('z',invert);
 1.34691 +      if (Ir.height>1) FFT('y',invert);
 1.34692 +      if (Ir.width>1)  FFT('x',invert);
 1.34693 +#endif
 1.34694 +      return *this;
 1.34695 +    }
 1.34696 +
 1.34697 +    CImgList<Tfloat> get_FFT(const bool invert=false) const {
 1.34698 +      return CImgList<Tfloat>(*this).FFT(invert);
 1.34699 +    }
 1.34700 +
 1.34701 +    // Return a list where each image has been split along the specified axis.
 1.34702 +    CImgList<T>& split(const char axis) {
 1.34703 +      return get_split(axis).transfer_to(*this);
 1.34704 +    }
 1.34705 +
 1.34706 +    CImgList<T> get_split(const char axis) const {
 1.34707 +      CImgList<T> res;
 1.34708 +      cimglist_for(*this,l) {
 1.34709 +        CImgList<T> tmp = data[l].get_split(axis);
 1.34710 +        const unsigned int pos = res.size;
 1.34711 +        res.insert(tmp.size);
 1.34712 +        cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
 1.34713 +      }
 1.34714 +      return res;
 1.34715 +    }
 1.34716 +
 1.34717 +    //! Return a single image which is the concatenation of all images of the current CImgList instance.
 1.34718 +    /**
 1.34719 +       \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 1.34720 +       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 1.34721 +       \return A CImg<T> image corresponding to the concatenation is returned.
 1.34722 +    **/
 1.34723 +    CImg<T> get_append(const char axis, const char align='p') const {
 1.34724 +      if (is_empty()) return CImg<T>();
 1.34725 +      if (size==1) return +((*this)[0]);
 1.34726 +      unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
 1.34727 +      CImg<T> res;
 1.34728 +      switch (cimg::uncase(axis)) {
 1.34729 +      case 'x' : {
 1.34730 +        switch (cimg::uncase(align)) {
 1.34731 +        case 'x' : { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
 1.34732 +        case 'y' : { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
 1.34733 +        case 'z' : { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 1.34734 +        case 'v' : { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 1.34735 +        default :
 1.34736 +          cimglist_for(*this,l) {
 1.34737 +            const CImg<T>& img = (*this)[l];
 1.34738 +            dx += img.width;
 1.34739 +            dy = cimg::max(dy,img.height);
 1.34740 +            dz = cimg::max(dz,img.depth);
 1.34741 +            dv = cimg::max(dv,img.dim);
 1.34742 +          }
 1.34743 +        }
 1.34744 +        res.assign(dx,dy,dz,dv,0);
 1.34745 +        switch (cimg::uncase(align)) {
 1.34746 +        case 'x' : {
 1.34747 +          cimglist_for(*this,l) {
 1.34748 +            res.draw_image(pos,CImg<T>((*this)[l],true).unroll('x'));
 1.34749 +            pos+=(*this)[l].size();
 1.34750 +          }
 1.34751 +        } break;
 1.34752 +        case 'y' : {
 1.34753 +          cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('y'));
 1.34754 +        } break;
 1.34755 +        case 'z' : {
 1.34756 +          cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('z'));
 1.34757 +        } break;
 1.34758 +        case 'v' : {
 1.34759 +          cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('v'));
 1.34760 +        } break;
 1.34761 +        case 'p' : {
 1.34762 +          cimglist_for(*this,l) { res.draw_image(pos,(*this)[l]); pos+=(*this)[l].width; }
 1.34763 +        } break;
 1.34764 +        case 'n' : {
 1.34765 +          cimglist_for(*this,l) {
 1.34766 +            res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
 1.34767 +            pos+=(*this)[l].width;
 1.34768 +          }
 1.34769 +        } break;
 1.34770 +        default : {
 1.34771 +          cimglist_for(*this,l) {
 1.34772 +            res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
 1.34773 +            pos+=(*this)[l].width;
 1.34774 +          }
 1.34775 +        } break;
 1.34776 +        }
 1.34777 +      } break;
 1.34778 +
 1.34779 +      case 'y' : {
 1.34780 +        switch (cimg::uncase(align)) {
 1.34781 +        case 'x' : { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 1.34782 +        case 'y' : { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
 1.34783 +        case 'z' : { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 1.34784 +        case 'v' : { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 1.34785 +        default :
 1.34786 +          cimglist_for(*this,l) {
 1.34787 +            const CImg<T>& img = (*this)[l];
 1.34788 +            dx = cimg::max(dx,img.width);
 1.34789 +            dy += img.height;
 1.34790 +            dz = cimg::max(dz,img.depth);
 1.34791 +            dv = cimg::max(dv,img.dim);
 1.34792 +          }
 1.34793 +        }
 1.34794 +        res.assign(dx,dy,dz,dv,0);
 1.34795 +        switch (cimg::uncase(align)) {
 1.34796 +        case 'x' : {
 1.34797 +          cimglist_for(*this,l) res.draw_image(0,++pos,CImg<T>((*this)[l],true).unroll('x'));
 1.34798 +        } break;
 1.34799 +        case 'y' : {
 1.34800 +          cimglist_for(*this,l) {
 1.34801 +            res.draw_image(0,pos,CImg<T>((*this)[l],true).unroll('y'));
 1.34802 +            pos+=(*this)[l].size();
 1.34803 +          }
 1.34804 +        } break;
 1.34805 +        case 'z' : {
 1.34806 +          cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('z'));
 1.34807 +        } break;
 1.34808 +        case 'v' : {
 1.34809 +          cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 1.34810 +        } break;
 1.34811 +        case 'p' : {
 1.34812 +          cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
 1.34813 +        } break;
 1.34814 +        case 'n' : {
 1.34815 +          cimglist_for(*this,l) {
 1.34816 +            res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
 1.34817 +            pos+=(*this)[l].height;
 1.34818 +          }
 1.34819 +        } break;
 1.34820 +        default : {
 1.34821 +          cimglist_for(*this,l) {
 1.34822 +            res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
 1.34823 +          pos+=(*this)[l].height;
 1.34824 +          }
 1.34825 +        } break;
 1.34826 +        }
 1.34827 +      } break;
 1.34828 +
 1.34829 +      case 'z' : {
 1.34830 +        switch (cimg::uncase(align)) {
 1.34831 +        case 'x' : { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 1.34832 +        case 'y' : { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 1.34833 +        case 'z' : { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
 1.34834 +        case 'v' : { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 1.34835 +        default :
 1.34836 +          cimglist_for(*this,l) {
 1.34837 +            const CImg<T>& img = (*this)[l];
 1.34838 +            dx = cimg::max(dx,img.width);
 1.34839 +            dy = cimg::max(dy,img.height);
 1.34840 +            dz += img.depth;
 1.34841 +            dv = cimg::max(dv,img.dim);
 1.34842 +          }
 1.34843 +        }
 1.34844 +        res.assign(dx,dy,dz,dv,0);
 1.34845 +        switch (cimg::uncase(align)) {
 1.34846 +        case 'x' : {
 1.34847 +          cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
 1.34848 +        } break;
 1.34849 +        case 'y' : {
 1.34850 +          cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
 1.34851 +        } break;
 1.34852 +        case 'z' : {
 1.34853 +          cimglist_for(*this,l) {
 1.34854 +            res.draw_image(0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
 1.34855 +            pos+=(*this)[l].size();
 1.34856 +          }
 1.34857 +        } break;
 1.34858 +        case 'v' : {
 1.34859 +          cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 1.34860 +        } break;
 1.34861 +        case 'p' : {
 1.34862 +          cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
 1.34863 +        } break;
 1.34864 +        case 'n' : {
 1.34865 +          cimglist_for(*this,l) {
 1.34866 +            res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
 1.34867 +            pos+=(*this)[l].depth;
 1.34868 +          }
 1.34869 +        } break;
 1.34870 +        case 'c' : {
 1.34871 +          cimglist_for(*this,l) {
 1.34872 +            res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
 1.34873 +            pos+=(*this)[l].depth;
 1.34874 +          }
 1.34875 +        } break;
 1.34876 +        }
 1.34877 +      } break;
 1.34878 +
 1.34879 +      case 'v' : {
 1.34880 +        switch (cimg::uncase(align)) {
 1.34881 +        case 'x' : { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 1.34882 +        case 'y' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 1.34883 +        case 'z' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 1.34884 +        case 'v' : { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
 1.34885 +        default :
 1.34886 +          cimglist_for(*this,l) {
 1.34887 +            const CImg<T>& img = (*this)[l];
 1.34888 +            dx = cimg::max(dx,img.width);
 1.34889 +            dy = cimg::max(dy,img.height);
 1.34890 +            dz = cimg::max(dz,img.depth);
 1.34891 +            dv += img.dim;
 1.34892 +          }
 1.34893 +        }
 1.34894 +        res.assign(dx,dy,dz,dv,0);
 1.34895 +        switch (cimg::uncase(align)) {
 1.34896 +        case 'x' : {
 1.34897 +          cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
 1.34898 +        } break;
 1.34899 +        case 'y' : {
 1.34900 +          cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
 1.34901 +        } break;
 1.34902 +        case 'z' : {
 1.34903 +          cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
 1.34904 +        } break;
 1.34905 +        case 'v' : {
 1.34906 +          cimglist_for(*this,l) {
 1.34907 +            res.draw_image(0,0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
 1.34908 +            pos+=(*this)[l].size();
 1.34909 +          }
 1.34910 +        } break;
 1.34911 +        case 'p' : {
 1.34912 +          cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
 1.34913 +        } break;
 1.34914 +        case 'n' : {
 1.34915 +          cimglist_for(*this,l) {
 1.34916 +            res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
 1.34917 +            pos+=(*this)[l].dim;
 1.34918 +          }
 1.34919 +        } break;
 1.34920 +        case 'c' : {
 1.34921 +          cimglist_for(*this,l) {
 1.34922 +            res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
 1.34923 +            pos+=(*this)[l].dim;
 1.34924 +          }
 1.34925 +        } break;
 1.34926 +        }
 1.34927 +      } break;
 1.34928 +      default :
 1.34929 +        throw CImgArgumentException("CImgList<%s>::get_append() : unknow axis '%c', must be 'x','y','z' or 'v'",
 1.34930 +                                    pixel_type(),axis);
 1.34931 +      }
 1.34932 +      return res;
 1.34933 +    }
 1.34934 +
 1.34935 +    //! Create an auto-cropped font (along the X axis) from a input font \p font.
 1.34936 +    CImgList<T>& crop_font() {
 1.34937 +      return get_crop_font().transfer_to(*this);
 1.34938 +    }
 1.34939 +
 1.34940 +    CImgList<T> get_crop_font() const {
 1.34941 +      CImgList<T> res;
 1.34942 +      cimglist_for(*this,l) {
 1.34943 +        const CImg<T>& letter = (*this)[l];
 1.34944 +        int xmin = letter.width, xmax = 0;
 1.34945 +        cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
 1.34946 +        if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
 1.34947 +        else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
 1.34948 +      }
 1.34949 +      res[' '].resize(res['f'].width);
 1.34950 +      res[' '+256].resize(res['f'].width);
 1.34951 +      return res;
 1.34952 +    }
 1.34953 +
 1.34954 +    //! Invert primitives orientation of a 3D object.
 1.34955 +    CImgList<T>& invert_object3d() {
 1.34956 +      cimglist_for(*this,l) {
 1.34957 +        CImg<T>& p = data[l];
 1.34958 +        const unsigned int siz = p.size();
 1.34959 +        if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
 1.34960 +        else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
 1.34961 +      }
 1.34962 +      return *this;
 1.34963 +    }
 1.34964 +
 1.34965 +    CImgList<T> get_invert_object3d() const {
 1.34966 +      return (+*this).invert_object3d();
 1.34967 +    }
 1.34968 +
 1.34969 +    //! Return a CImg pre-defined font with desired size.
 1.34970 +    /**
 1.34971 +       \param font_height = height of the desired font (can be 11,13,24,38 or 57)
 1.34972 +       \param fixed_size = tell if the font has a fixed or variable width.
 1.34973 +    **/
 1.34974 +    static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
 1.34975 +      if (font_width<=11) {
 1.34976 +        static CImgList<T> font7x11, nfont7x11;
 1.34977 +        if (!variable_size && !font7x11)  font7x11 = _font(cimg::font7x11,7,11,1,0,false);
 1.34978 +        if (variable_size  && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
 1.34979 +        return variable_size?nfont7x11:font7x11;
 1.34980 +      }
 1.34981 +      if (font_width<=13) {
 1.34982 +        static CImgList<T> font10x13, nfont10x13;
 1.34983 +        if (!variable_size && !font10x13)  font10x13 = _font(cimg::font10x13,10,13,1,0,false);
 1.34984 +        if (variable_size  && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
 1.34985 +        return variable_size?nfont10x13:font10x13;
 1.34986 +      }
 1.34987 +      if (font_width<=17) {
 1.34988 +        static CImgList<T> font8x17, nfont8x17;
 1.34989 +        if (!variable_size && !font8x17)  font8x17 = _font(cimg::font8x17,8,17,1,0,false);
 1.34990 +        if (variable_size  && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
 1.34991 +        return variable_size?nfont8x17:font8x17;
 1.34992 +      }
 1.34993 +      if (font_width<=19) {
 1.34994 +        static CImgList<T> font10x19, nfont10x19;
 1.34995 +        if (!variable_size && !font10x19)  font10x19 = _font(cimg::font10x19,10,19,2,0,false);
 1.34996 +        if (variable_size  && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
 1.34997 +        return variable_size?nfont10x19:font10x19;
 1.34998 +      }
 1.34999 +      if (font_width<=24) {
 1.35000 +        static CImgList<T> font12x24, nfont12x24;
 1.35001 +        if (!variable_size && !font12x24)  font12x24 = _font(cimg::font12x24,12,24,2,0,false);
 1.35002 +        if (variable_size  && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
 1.35003 +        return variable_size?nfont12x24:font12x24;
 1.35004 +      }
 1.35005 +      if (font_width<=32) {
 1.35006 +        static CImgList<T> font16x32, nfont16x32;
 1.35007 +        if (!variable_size && !font16x32)  font16x32 = _font(cimg::font16x32,16,32,2,0,false);
 1.35008 +        if (variable_size  && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
 1.35009 +        return variable_size?nfont16x32:font16x32;
 1.35010 +      }
 1.35011 +      if (font_width<=38) {
 1.35012 +        static CImgList<T> font19x38, nfont19x38;
 1.35013 +        if (!variable_size && !font19x38)  font19x38 = _font(cimg::font19x38,19,38,3,0,false);
 1.35014 +        if (variable_size  && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
 1.35015 +        return variable_size?nfont19x38:font19x38;
 1.35016 +      }
 1.35017 +      static CImgList<T> font29x57, nfont29x57;
 1.35018 +      if (!variable_size && !font29x57)  font29x57 = _font(cimg::font29x57,29,57,5,0,false);
 1.35019 +      if (variable_size  && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
 1.35020 +      return variable_size?nfont29x57:font29x57;
 1.35021 +    }
 1.35022 +
 1.35023 +    static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
 1.35024 +                             const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
 1.35025 +      CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
 1.35026 +      const unsigned int *ptr = font;
 1.35027 +      unsigned int m = 0, val = 0;
 1.35028 +      for (unsigned int y=0; y<h; ++y)
 1.35029 +        for (unsigned int x=0; x<256*w; ++x) {
 1.35030 +          m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
 1.35031 +          CImg<T>& img = res[x/w], &mask = res[x/w+256];
 1.35032 +          unsigned int xm = x%w;
 1.35033 +          img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
 1.35034 +        }
 1.35035 +      if (variable_size) res.crop_font();
 1.35036 +      if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
 1.35037 +      return res;
 1.35038 +    }
 1.35039 +
 1.35040 +    //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
 1.35041 +    /**
 1.35042 +       This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
 1.35043 +       Images of the list are concatenated in a single temporarly image for visualization purposes.
 1.35044 +       The function returns immediately.
 1.35045 +       \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
 1.35046 +       \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 1.35047 +       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 1.35048 +       \return A reference to the current CImgList instance is returned.
 1.35049 +    **/
 1.35050 +    const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
 1.35051 +      get_append(axis,align).display(disp);
 1.35052 +      return *this;
 1.35053 +    }
 1.35054 +
 1.35055 +    //! Display the current CImgList instance in a new display window.
 1.35056 +    /**
 1.35057 +       This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
 1.35058 +       Images of the list are concatenated in a single temporarly image for visualization purposes.
 1.35059 +       The function returns when a key is pressed or the display window is closed by the user.
 1.35060 +       \param title : specify the title of the opening display window.
 1.35061 +       \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
 1.35062 +       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 1.35063 +       \return A reference to the current CImgList instance is returned.
 1.35064 +    **/
 1.35065 +    const CImgList<T>& display(CImgDisplay &disp,
 1.35066 +                               const bool display_info, const char axis='x', const char align='p') const {
 1.35067 +      if (is_empty())
 1.35068 +        throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
 1.35069 +                                    pixel_type(),size,data);
 1.35070 +      const CImg<T> visu = get_append(axis,align);
 1.35071 +      if (display_info) print(disp.title);
 1.35072 +      visu.display(disp,false);
 1.35073 +      return *this;
 1.35074 +    }
 1.35075 +
 1.35076 +    //! Display the current CImgList instance in a new display window.
 1.35077 +    const CImgList<T>& display(const char *const title=0,
 1.35078 +                               const bool display_info=true, const char axis='x', const char align='p') const {
 1.35079 +      const CImg<T> visu = get_append(axis,align);
 1.35080 +      char ntitle[64] = { 0 };
 1.35081 +      if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 1.35082 +      if (display_info) print(title?title:ntitle);
 1.35083 +      visu.display(title?title:ntitle,false);
 1.35084 +      return *this;
 1.35085 +    }
 1.35086 +
 1.35087 +    //@}
 1.35088 +    //----------------------------------
 1.35089 +    //
 1.35090 +    //! \name Input-Output
 1.35091 +    //@{
 1.35092 +    //----------------------------------
 1.35093 +
 1.35094 +    //! Return a C-string containing the values of all images in the instance list.
 1.35095 +    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
 1.35096 +      if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
 1.35097 +      CImgList<charT> items;
 1.35098 +      for (unsigned int l = 0; l<size-1; ++l) {
 1.35099 +        CImg<charT> item = data[l].value_string(separator,0);
 1.35100 +        item[item.size()-1] = separator;
 1.35101 +        items.insert(item);
 1.35102 +      }
 1.35103 +      items.insert(data[size-1].value_string(separator,0));
 1.35104 +      CImg<charT> res = items.get_append('x');
 1.35105 +      if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
 1.35106 +      return res;
 1.35107 +    }
 1.35108 +
 1.35109 +    //! Print informations about the list on the standard output.
 1.35110 +    const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
 1.35111 +      unsigned long msiz = 0;
 1.35112 +      cimglist_for(*this,l) msiz += data[l].size();
 1.35113 +      msiz*=sizeof(T);
 1.35114 +      const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
 1.35115 +      char ntitle[64] = { 0 };
 1.35116 +      if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 1.35117 +      cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
 1.35118 +                   title?title:ntitle,(void*)this,size,
 1.35119 +                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 1.35120 +                   mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 1.35121 +                   pixel_type(),(void*)data);
 1.35122 +      char tmp[16] = { 0 };
 1.35123 +      cimglist_for(*this,ll) {
 1.35124 +        cimg_std::sprintf(tmp,"[%d]",ll);
 1.35125 +        cimg_std::fprintf(cimg_stdout,"  ");
 1.35126 +        data[ll].print(tmp,display_stats);
 1.35127 +        if (ll==3 && size>8) { ll = size-5; cimg_std::fprintf(cimg_stdout,"  ...\n"); }
 1.35128 +      }
 1.35129 +      return *this;
 1.35130 +    }
 1.35131 +
 1.35132 +    //! Load an image list from a file.
 1.35133 +    CImgList<T>& load(const char *const filename) {
 1.35134 +      const char *ext = cimg::split_filename(filename);
 1.35135 +      const unsigned int odebug = cimg::exception_mode();
 1.35136 +      cimg::exception_mode() = 0;
 1.35137 +      assign();
 1.35138 +      try {
 1.35139 +#ifdef cimglist_load_plugin
 1.35140 +        cimglist_load_plugin(filename);
 1.35141 +#endif
 1.35142 +#ifdef cimglist_load_plugin1
 1.35143 +        cimglist_load_plugin1(filename);
 1.35144 +#endif
 1.35145 +#ifdef cimglist_load_plugin2
 1.35146 +        cimglist_load_plugin2(filename);
 1.35147 +#endif
 1.35148 +#ifdef cimglist_load_plugin3
 1.35149 +        cimglist_load_plugin3(filename);
 1.35150 +#endif
 1.35151 +#ifdef cimglist_load_plugin4
 1.35152 +        cimglist_load_plugin4(filename);
 1.35153 +#endif
 1.35154 +#ifdef cimglist_load_plugin5
 1.35155 +        cimglist_load_plugin5(filename);
 1.35156 +#endif
 1.35157 +#ifdef cimglist_load_plugin6
 1.35158 +        cimglist_load_plugin6(filename);
 1.35159 +#endif
 1.35160 +#ifdef cimglist_load_plugin7
 1.35161 +        cimglist_load_plugin7(filename);
 1.35162 +#endif
 1.35163 +#ifdef cimglist_load_plugin8
 1.35164 +        cimglist_load_plugin8(filename);
 1.35165 +#endif
 1.35166 +        if (!cimg::strcasecmp(ext,"tif") ||
 1.35167 +            !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
 1.35168 +        if (!cimg::strcasecmp(ext,"cimg") ||
 1.35169 +            !cimg::strcasecmp(ext,"cimgz") ||
 1.35170 +            !ext[0]) load_cimg(filename);
 1.35171 +        if (!cimg::strcasecmp(ext,"rec") ||
 1.35172 +            !cimg::strcasecmp(ext,"par")) load_parrec(filename);
 1.35173 +        if (!cimg::strcasecmp(ext,"avi") ||
 1.35174 +            !cimg::strcasecmp(ext,"mov") ||
 1.35175 +            !cimg::strcasecmp(ext,"asf") ||
 1.35176 +            !cimg::strcasecmp(ext,"divx") ||
 1.35177 +            !cimg::strcasecmp(ext,"flv") ||
 1.35178 +            !cimg::strcasecmp(ext,"mpg") ||
 1.35179 +            !cimg::strcasecmp(ext,"m1v") ||
 1.35180 +            !cimg::strcasecmp(ext,"m2v") ||
 1.35181 +            !cimg::strcasecmp(ext,"m4v") ||
 1.35182 +            !cimg::strcasecmp(ext,"mjp") ||
 1.35183 +            !cimg::strcasecmp(ext,"mkv") ||
 1.35184 +            !cimg::strcasecmp(ext,"mpe") ||
 1.35185 +            !cimg::strcasecmp(ext,"movie") ||
 1.35186 +            !cimg::strcasecmp(ext,"ogm") ||
 1.35187 +            !cimg::strcasecmp(ext,"qt") ||
 1.35188 +            !cimg::strcasecmp(ext,"rm") ||
 1.35189 +            !cimg::strcasecmp(ext,"vob") ||
 1.35190 +            !cimg::strcasecmp(ext,"wmv") ||
 1.35191 +            !cimg::strcasecmp(ext,"xvid") ||
 1.35192 +            !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
 1.35193 +        if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
 1.35194 +        if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
 1.35195 +      } catch (CImgIOException& e) {
 1.35196 +        if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
 1.35197 +          cimg::exception_mode() = odebug;
 1.35198 +          throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
 1.35199 +        } else try {
 1.35200 +          assign(1);
 1.35201 +          data->load(filename);
 1.35202 +        } catch (CImgException&) {
 1.35203 +          assign();
 1.35204 +        }
 1.35205 +      }
 1.35206 +      cimg::exception_mode() = odebug;
 1.35207 +      if (is_empty())
 1.35208 +        throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
 1.35209 +      return *this;
 1.35210 +    }
 1.35211 +
 1.35212 +    static CImgList<T> get_load(const char *const filename) {
 1.35213 +      return CImgList<T>().load(filename);
 1.35214 +    }
 1.35215 +
 1.35216 +    //! Load an image list from a .cimg file.
 1.35217 +    CImgList<T>& load_cimg(const char *const filename) {
 1.35218 +      return _load_cimg(0,filename);
 1.35219 +    }
 1.35220 +
 1.35221 +    static CImgList<T> get_load_cimg(const char *const filename) {
 1.35222 +      return CImgList<T>().load_cimg(filename);
 1.35223 +    }
 1.35224 +
 1.35225 +    //! Load an image list from a .cimg file.
 1.35226 +    CImgList<T>& load_cimg(cimg_std::FILE *const file) {
 1.35227 +      return _load_cimg(file,0);
 1.35228 +    }
 1.35229 +
 1.35230 +    static CImgList<T> get_load_cimg(cimg_std::FILE *const file) {
 1.35231 +      return CImgList<T>().load_cimg(file);
 1.35232 +    }
 1.35233 +
 1.35234 +    CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename) {
 1.35235 +#ifdef cimg_use_zlib
 1.35236 +#define _cimgz_load_cimg_case(Tss) { \
 1.35237 +   Bytef *const cbuf = new Bytef[csiz]; \
 1.35238 +   cimg::fread(cbuf,csiz,nfile); \
 1.35239 +   raw.assign(W,H,D,V); \
 1.35240 +   unsigned long destlen = raw.size()*sizeof(T); \
 1.35241 +   uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
 1.35242 +   delete[] cbuf; \
 1.35243 +   const Tss *ptrs = raw.data; \
 1.35244 +   for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
 1.35245 +}
 1.35246 +#else
 1.35247 +#define _cimgz_load_cimg_case(Tss) \
 1.35248 +   throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
 1.35249 +                         pixel_type(),filename?filename:"(FILE*)");
 1.35250 +#endif
 1.35251 +
 1.35252 +#define _cimg_load_cimg_case(Ts,Tss) \
 1.35253 +      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 1.35254 +        for (unsigned int l = 0; l<N; ++l) { \
 1.35255 +          j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
 1.35256 +          W = H = D = V = 0; csiz = 0; \
 1.35257 +          if ((err = cimg_std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
 1.35258 +            throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 1.35259 +                                  pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
 1.35260 +          if (W*H*D*V>0) { \
 1.35261 +            CImg<Tss> raw; \
 1.35262 +            CImg<T> &img = data[l]; \
 1.35263 +            img.assign(W,H,D,V); \
 1.35264 +            T *ptrd = img.data; \
 1.35265 +            if (err==5) _cimgz_load_cimg_case(Tss) \
 1.35266 +            else for (int toread = (int)img.size(); toread>0; ) { \
 1.35267 +              raw.assign(cimg::min(toread,cimg_iobuffer)); \
 1.35268 +              cimg::fread(raw.data,raw.width,nfile); \
 1.35269 +              if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
 1.35270 +              toread-=raw.width; \
 1.35271 +              const Tss *ptrs = raw.data; \
 1.35272 +              for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
 1.35273 +            } \
 1.35274 +          } \
 1.35275 +        } \
 1.35276 +        loaded = true; \
 1.35277 +      }
 1.35278 +
 1.35279 +      if (!filename && !file)
 1.35280 +        throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 1.35281 +                                    pixel_type());
 1.35282 +      typedef unsigned char uchar;
 1.35283 +      typedef unsigned short ushort;
 1.35284 +      typedef unsigned int uint;
 1.35285 +      typedef unsigned long ulong;
 1.35286 +      const int cimg_iobuffer = 12*1024*1024;
 1.35287 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.35288 +      bool loaded = false, endian = cimg::endianness();
 1.35289 +      char tmp[256], str_pixeltype[256], str_endian[256];
 1.35290 +      unsigned int j, err, N = 0, W, H, D, V, csiz;
 1.35291 +      int i;
 1.35292 +      j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 1.35293 +      err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 1.35294 +      if (err<2) {
 1.35295 +        if (!file) cimg::fclose(nfile);
 1.35296 +        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
 1.35297 +                              pixel_type(),filename?filename:"(FILE*)");
 1.35298 +      }
 1.35299 +      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 1.35300 +      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 1.35301 +      assign(N);
 1.35302 +      _cimg_load_cimg_case("bool",bool);
 1.35303 +      _cimg_load_cimg_case("unsigned_char",uchar);
 1.35304 +      _cimg_load_cimg_case("uchar",uchar);
 1.35305 +      _cimg_load_cimg_case("char",char);
 1.35306 +      _cimg_load_cimg_case("unsigned_short",ushort);
 1.35307 +      _cimg_load_cimg_case("ushort",ushort);
 1.35308 +      _cimg_load_cimg_case("short",short);
 1.35309 +      _cimg_load_cimg_case("unsigned_int",uint);
 1.35310 +      _cimg_load_cimg_case("uint",uint);
 1.35311 +      _cimg_load_cimg_case("int",int);
 1.35312 +      _cimg_load_cimg_case("unsigned_long",ulong);
 1.35313 +      _cimg_load_cimg_case("ulong",ulong);
 1.35314 +      _cimg_load_cimg_case("long",long);
 1.35315 +      _cimg_load_cimg_case("float",float);
 1.35316 +      _cimg_load_cimg_case("double",double);
 1.35317 +      if (!loaded) {
 1.35318 +        if (!file) cimg::fclose(nfile);
 1.35319 +        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
 1.35320 +                              pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 1.35321 +      }
 1.35322 +      if (!file) cimg::fclose(nfile);
 1.35323 +      return *this;
 1.35324 +    }
 1.35325 +
 1.35326 +    //! Load a sub-image list from a non compressed .cimg file.
 1.35327 +    CImgList<T>& load_cimg(const char *const filename,
 1.35328 +                           const unsigned int n0, const unsigned int n1,
 1.35329 +                           const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.35330 +                           const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 1.35331 +      return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.35332 +    }
 1.35333 +
 1.35334 +    static CImgList<T> get_load_cimg(const char *const filename,
 1.35335 +                                     const unsigned int n0, const unsigned int n1,
 1.35336 +                                     const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.35337 +                                     const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 1.35338 +      return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.35339 +    }
 1.35340 +
 1.35341 +    //! Load a sub-image list from a non compressed .cimg file.
 1.35342 +    CImgList<T>& load_cimg(cimg_std::FILE *const file,
 1.35343 +                           const unsigned int n0, const unsigned int n1,
 1.35344 +                           const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.35345 +                           const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 1.35346 +      return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.35347 +    }
 1.35348 +
 1.35349 +    static CImgList<T> get_load_cimg(cimg_std::FILE *const file,
 1.35350 +                                     const unsigned int n0, const unsigned int n1,
 1.35351 +                                     const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.35352 +                                     const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 1.35353 +      return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.35354 +    }
 1.35355 +
 1.35356 +    CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename,
 1.35357 +                            const unsigned int n0, const unsigned int n1,
 1.35358 +                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 1.35359 +                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 1.35360 +#define _cimg_load_cimg_case2(Ts,Tss) \
 1.35361 +      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 1.35362 +        for (unsigned int l = 0; l<=nn1; ++l) { \
 1.35363 +          j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
 1.35364 +          W = H = D = V = 0; \
 1.35365 +          if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
 1.35366 +            throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 1.35367 +                                  pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
 1.35368 +          if (W*H*D*V>0) { \
 1.35369 +            if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
 1.35370 +            else { \
 1.35371 +              const unsigned int \
 1.35372 +                nx1 = x1>=W?W-1:x1, \
 1.35373 +                ny1 = y1>=H?H-1:y1, \
 1.35374 +                nz1 = z1>=D?D-1:z1, \
 1.35375 +                nv1 = v1>=V?V-1:v1; \
 1.35376 +              CImg<Tss> raw(1+nx1-x0); \
 1.35377 +              CImg<T> &img = data[l-n0]; \
 1.35378 +              img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
 1.35379 +              T *ptrd = img.data; \
 1.35380 +              const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
 1.35381 +              if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
 1.35382 +              for (unsigned int v=1+nv1-v0; v; --v) { \
 1.35383 +                const unsigned int skipzb = z0*W*H*sizeof(Tss); \
 1.35384 +                if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
 1.35385 +                for (unsigned int z=1+nz1-z0; z; --z) { \
 1.35386 +                  const unsigned int skipyb = y0*W*sizeof(Tss); \
 1.35387 +                  if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
 1.35388 +                  for (unsigned int y=1+ny1-y0; y; --y) { \
 1.35389 +                    const unsigned int skipxb = x0*sizeof(Tss); \
 1.35390 +                    if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
 1.35391 +                    cimg::fread(raw.data,raw.width,nfile); \
 1.35392 +                    if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
 1.35393 +                    const Tss *ptrs = raw.data; \
 1.35394 +                    for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
 1.35395 +                    const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
 1.35396 +                    if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
 1.35397 +                  } \
 1.35398 +                  const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
 1.35399 +                  if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
 1.35400 +                } \
 1.35401 +                const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
 1.35402 +                if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
 1.35403 +              } \
 1.35404 +              const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
 1.35405 +              if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
 1.35406 +            } \
 1.35407 +          } \
 1.35408 +        } \
 1.35409 +        loaded = true; \
 1.35410 +      }
 1.35411 +
 1.35412 +      if (!filename && !file)
 1.35413 +        throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 1.35414 +                                    pixel_type());
 1.35415 +      typedef unsigned char uchar;
 1.35416 +      typedef unsigned short ushort;
 1.35417 +      typedef unsigned int uint;
 1.35418 +      typedef unsigned long ulong;
 1.35419 +      if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
 1.35420 +        throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
 1.35421 +                                    "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
 1.35422 +                                    pixel_type(),filename?filename:"(FILE*)",
 1.35423 +                                    n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 1.35424 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.35425 +      bool loaded = false, endian = cimg::endianness();
 1.35426 +      char tmp[256], str_pixeltype[256], str_endian[256];
 1.35427 +      unsigned int j, err, N, W, H, D, V;
 1.35428 +      int i;
 1.35429 +      j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 1.35430 +      err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 1.35431 +      if (err<2) {
 1.35432 +        if (!file) cimg::fclose(nfile);
 1.35433 +        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
 1.35434 +                              pixel_type(),filename?filename:"(FILE*)");
 1.35435 +      }
 1.35436 +      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 1.35437 +      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 1.35438 +      const unsigned int nn1 = n1>=N?N-1:n1;
 1.35439 +      assign(1+nn1-n0);
 1.35440 +      _cimg_load_cimg_case2("bool",bool);
 1.35441 +      _cimg_load_cimg_case2("unsigned_char",uchar);
 1.35442 +      _cimg_load_cimg_case2("uchar",uchar);
 1.35443 +      _cimg_load_cimg_case2("char",char);
 1.35444 +      _cimg_load_cimg_case2("unsigned_short",ushort);
 1.35445 +      _cimg_load_cimg_case2("ushort",ushort);
 1.35446 +      _cimg_load_cimg_case2("short",short);
 1.35447 +      _cimg_load_cimg_case2("unsigned_int",uint);
 1.35448 +      _cimg_load_cimg_case2("uint",uint);
 1.35449 +      _cimg_load_cimg_case2("int",int);
 1.35450 +      _cimg_load_cimg_case2("unsigned_long",ulong);
 1.35451 +      _cimg_load_cimg_case2("ulong",ulong);
 1.35452 +      _cimg_load_cimg_case2("long",long);
 1.35453 +      _cimg_load_cimg_case2("float",float);
 1.35454 +      _cimg_load_cimg_case2("double",double);
 1.35455 +      if (!loaded) {
 1.35456 +        if (!file) cimg::fclose(nfile);
 1.35457 +        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
 1.35458 +                              pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 1.35459 +      }
 1.35460 +      if (!file) cimg::fclose(nfile);
 1.35461 +      return *this;
 1.35462 +    }
 1.35463 +
 1.35464 +    //! Load an image list from a PAR/REC (Philips) file.
 1.35465 +    CImgList<T>& load_parrec(const char *const filename) {
 1.35466 +      if (!filename)
 1.35467 +        throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
 1.35468 +                                    pixel_type());
 1.35469 +      char body[1024], filenamepar[1024], filenamerec[1024];
 1.35470 +      const char *ext = cimg::split_filename(filename,body);
 1.35471 +      if (!cimg::strcmp(ext,"par")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.rec",body); }
 1.35472 +      if (!cimg::strcmp(ext,"PAR")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.REC",body); }
 1.35473 +      if (!cimg::strcmp(ext,"rec")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.par",body); }
 1.35474 +      if (!cimg::strcmp(ext,"REC")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.PAR",body); }
 1.35475 +      cimg_std::FILE *file = cimg::fopen(filenamepar,"r");
 1.35476 +
 1.35477 +      // Parse header file
 1.35478 +      CImgList<floatT> st_slices;
 1.35479 +      CImgList<uintT> st_global;
 1.35480 +      int err;
 1.35481 +      char line[256] = { 0 };
 1.35482 +      do { err=cimg_std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
 1.35483 +      do {
 1.35484 +        unsigned int sn,sizex,sizey,pixsize;
 1.35485 +        float rs,ri,ss;
 1.35486 +        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);
 1.35487 +        if (err==7) {
 1.35488 +          st_slices.insert(CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
 1.35489 +                                               ri,rs,ss,0));
 1.35490 +          unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
 1.35491 +          if (i==st_global.size) st_global.insert(CImg<uintT>::vector(sizex,sizey,sn));
 1.35492 +          else {
 1.35493 +            CImg<uintT> &vec = st_global[i];
 1.35494 +            if (sizex>vec[0]) vec[0] = sizex;
 1.35495 +            if (sizey>vec[1]) vec[1] = sizey;
 1.35496 +            vec[2] = sn;
 1.35497 +          }
 1.35498 +          st_slices[st_slices.size-1][7] = (float)i;
 1.35499 +        }
 1.35500 +      } while (err==7);
 1.35501 +
 1.35502 +      // Read data
 1.35503 +      cimg_std::FILE *file2 = cimg::fopen(filenamerec,"rb");
 1.35504 +      { cimglist_for(st_global,l) {
 1.35505 +        const CImg<uintT>& vec = st_global[l];
 1.35506 +        insert(CImg<T>(vec[0],vec[1],vec[2]));
 1.35507 +      }}
 1.35508 +
 1.35509 +      cimglist_for(st_slices,l) {
 1.35510 +        const CImg<floatT>& vec = st_slices[l];
 1.35511 +        const unsigned int
 1.35512 +          sn = (unsigned int)vec[0]-1,
 1.35513 +          pixsize = (unsigned int)vec[1],
 1.35514 +          sizex = (unsigned int)vec[2],
 1.35515 +          sizey = (unsigned int)vec[3],
 1.35516 +          imn = (unsigned int)vec[7];
 1.35517 +        const float ri = vec[4], rs = vec[5], ss = vec[6];
 1.35518 +        switch (pixsize) {
 1.35519 +        case 8 : {
 1.35520 +          CImg<ucharT> buf(sizex,sizey);
 1.35521 +          cimg::fread(buf.data,sizex*sizey,file2);
 1.35522 +          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 1.35523 +          CImg<T>& img = (*this)[imn];
 1.35524 +          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 1.35525 +        } break;
 1.35526 +        case 16 : {
 1.35527 +          CImg<ushortT> buf(sizex,sizey);
 1.35528 +          cimg::fread(buf.data,sizex*sizey,file2);
 1.35529 +          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 1.35530 +          CImg<T>& img = (*this)[imn];
 1.35531 +          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 1.35532 +        } break;
 1.35533 +        case 32 : {
 1.35534 +          CImg<uintT> buf(sizex,sizey);
 1.35535 +          cimg::fread(buf.data,sizex*sizey,file2);
 1.35536 +          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
 1.35537 +          CImg<T>& img = (*this)[imn];
 1.35538 +          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
 1.35539 +        } break;
 1.35540 +        default :
 1.35541 +          cimg::fclose(file);
 1.35542 +          cimg::fclose(file2);
 1.35543 +          throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
 1.35544 +                                pixel_type(),filename,pixsize);
 1.35545 +        }
 1.35546 +      }
 1.35547 +      cimg::fclose(file);
 1.35548 +      cimg::fclose(file2);
 1.35549 +      if (!size)
 1.35550 +        throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
 1.35551 +                              pixel_type(),filename);
 1.35552 +      return *this;
 1.35553 +    }
 1.35554 +
 1.35555 +    static CImgList<T> get_load_parrec(const char *const filename) {
 1.35556 +      return CImgList<T>().load_parrec(filename);
 1.35557 +    }
 1.35558 +
 1.35559 +    //! Load an image sequence from a YUV file.
 1.35560 +    CImgList<T>& load_yuv(const char *const filename,
 1.35561 +                          const unsigned int sizex, const unsigned int sizey,
 1.35562 +                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35563 +                          const unsigned int step_frame=1, const bool yuv2rgb=true) {
 1.35564 +      return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 1.35565 +    }
 1.35566 +
 1.35567 +    static CImgList<T> get_load_yuv(const char *const filename,
 1.35568 +                                    const unsigned int sizex, const unsigned int sizey=1,
 1.35569 +                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35570 +                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {
 1.35571 +      return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 1.35572 +    }
 1.35573 +
 1.35574 +    //! Load an image sequence from a YUV file.
 1.35575 +    CImgList<T>& load_yuv(cimg_std::FILE *const file,
 1.35576 +                          const unsigned int sizex, const unsigned int sizey,
 1.35577 +                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35578 +                          const unsigned int step_frame=1, const bool yuv2rgb=true) {
 1.35579 +      return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 1.35580 +    }
 1.35581 +
 1.35582 +    static CImgList<T> get_load_yuv(cimg_std::FILE *const file,
 1.35583 +                                    const unsigned int sizex, const unsigned int sizey=1,
 1.35584 +                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35585 +                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {
 1.35586 +      return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 1.35587 +    }
 1.35588 +
 1.35589 +    CImgList<T>& _load_yuv(cimg_std::FILE *const file, const char *const filename,
 1.35590 +                           const unsigned int sizex, const unsigned int sizey,
 1.35591 +                           const unsigned int first_frame, const unsigned int last_frame,
 1.35592 +                           const unsigned int step_frame, const bool yuv2rgb) {
 1.35593 +      if (!filename && !file)
 1.35594 +        throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
 1.35595 +                                    pixel_type());
 1.35596 +      if (sizex%2 || sizey%2)
 1.35597 +        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
 1.35598 +                                    "even numbers (given are %ux%u)\n",
 1.35599 +                                    pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 1.35600 +      if (!sizex || !sizey)
 1.35601 +        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
 1.35602 +                                    pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 1.35603 +
 1.35604 +      const unsigned int
 1.35605 +        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 1.35606 +        nlast_frame = first_frame<last_frame?last_frame:first_frame,
 1.35607 +        nstep_frame = step_frame?step_frame:1;
 1.35608 +
 1.35609 +      CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
 1.35610 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 1.35611 +      bool stopflag = false;
 1.35612 +      int err;
 1.35613 +      if (nfirst_frame) {
 1.35614 +        err = cimg_std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
 1.35615 +        if (err) {
 1.35616 +          if (!file) cimg::fclose(nfile);
 1.35617 +          throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
 1.35618 +                                "(out of range error).",
 1.35619 +                                pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
 1.35620 +        }
 1.35621 +      }
 1.35622 +      unsigned int frame;
 1.35623 +      for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
 1.35624 +        tmp.fill(0);
 1.35625 +        // *TRY* to read the luminance part, do not replace by cimg::fread !
 1.35626 +        err = (int)cimg_std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
 1.35627 +        if (err!=(int)(tmp.width*tmp.height)) {
 1.35628 +          stopflag = true;
 1.35629 +          if (err>0)
 1.35630 +            cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
 1.35631 +                       " or given image dimensions (%u,%u) are incorrect.",
 1.35632 +                       pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 1.35633 +        } else {
 1.35634 +          UV.fill(0);
 1.35635 +          // *TRY* to read the luminance part, do not replace by cimg::fread !
 1.35636 +          err = (int)cimg_std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
 1.35637 +          if (err!=(int)(UV.size())) {
 1.35638 +            stopflag = true;
 1.35639 +            if (err>0)
 1.35640 +              cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
 1.35641 +                         " or given image dimensions (%u,%u) are incorrect.",
 1.35642 +                         pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
 1.35643 +          } else {
 1.35644 +            cimg_forXY(UV,x,y) {
 1.35645 +              const int x2 = x*2, y2 = y*2;
 1.35646 +              tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
 1.35647 +              tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
 1.35648 +            }
 1.35649 +            if (yuv2rgb) tmp.YCbCrtoRGB();
 1.35650 +            insert(tmp);
 1.35651 +            if (nstep_frame>1) cimg_std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
 1.35652 +          }
 1.35653 +        }
 1.35654 +      }
 1.35655 +      if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
 1.35656 +        cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
 1.35657 +                   pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
 1.35658 +      if (!file) cimg::fclose(nfile);
 1.35659 +      return *this;
 1.35660 +    }
 1.35661 +
 1.35662 +    //! Load an image from a video file, using ffmpeg libraries.
 1.35663 +    // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
 1.35664 +    // I modified it afterwards for direct inclusion in the library core.
 1.35665 +    CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35666 +                             const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
 1.35667 +      if (!filename)
 1.35668 +        throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
 1.35669 +                                    pixel_type());
 1.35670 +      const unsigned int
 1.35671 +        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 1.35672 +        nlast_frame = first_frame<last_frame?last_frame:first_frame,
 1.35673 +        nstep_frame = step_frame?step_frame:1;
 1.35674 +      assign();
 1.35675 +
 1.35676 +#ifndef cimg_use_ffmpeg
 1.35677 +      if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
 1.35678 +        throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
 1.35679 +                                    "('cimg_use_ffmpeg' must be defined).",
 1.35680 +                                    pixel_type(),filename);
 1.35681 +      return load_ffmpeg_external(filename);
 1.35682 +#else
 1.35683 +      const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
 1.35684 +      avcodec_register_all();
 1.35685 +      av_register_all();
 1.35686 +      static AVFormatContext *format_ctx = 0;
 1.35687 +      static AVCodecContext *codec_ctx = 0;
 1.35688 +      static AVCodec *codec = 0;
 1.35689 +      static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
 1.35690 +      static int vstream = 0;
 1.35691 +
 1.35692 +      if (resume) {
 1.35693 +        if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
 1.35694 +          throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
 1.35695 +                                      pixel_type(),filename);
 1.35696 +      } else {
 1.35697 +        // Open video file, find main video stream and codec.
 1.35698 +        if (format_ctx) av_close_input_file(format_ctx);
 1.35699 +        if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
 1.35700 +          throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
 1.35701 +                                pixel_type(),filename);
 1.35702 +        if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
 1.35703 +          av_close_input_file(format_ctx); format_ctx = 0;
 1.35704 +          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
 1.35705 +                     "Trying with external ffmpeg executable.",
 1.35706 +                     pixel_type(),filename);
 1.35707 +          return load_ffmpeg_external(filename);
 1.35708 +        }
 1.35709 +#if cimg_debug>=3
 1.35710 +        dump_format(format_ctx,0,0,0);
 1.35711 +#endif
 1.35712 +
 1.35713 +        // Special command : Return informations on main video stream.
 1.35714 +        // as a vector 1x4 containing : (nb_frames,width,height,fps).
 1.35715 +        if (!first_frame && !last_frame && !step_frame) {
 1.35716 +          for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
 1.35717 +            if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
 1.35718 +          if (vstream==(int)format_ctx->nb_streams) assign();
 1.35719 +          else {
 1.35720 +            CImgList<doubleT> timestamps;
 1.35721 +            int nb_frames;
 1.35722 +            AVPacket packet;
 1.35723 +            // Count frames and store timestamps.
 1.35724 +            for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
 1.35725 +              if (packet.stream_index==vstream) {
 1.35726 +                timestamps.insert(CImg<doubleT>::vector((double)packet.pts));
 1.35727 +                ++nb_frames;
 1.35728 +              }
 1.35729 +            // Get frame with, height and fps.
 1.35730 +            const int
 1.35731 +              framew = format_ctx->streams[vstream]->codec->width,
 1.35732 +              frameh = format_ctx->streams[vstream]->codec->height;
 1.35733 +            const float
 1.35734 +              num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
 1.35735 +              den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
 1.35736 +              fps = num/den;
 1.35737 +            // Return infos as a list.
 1.35738 +            assign(2);
 1.35739 +            (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
 1.35740 +            (*this)[1] = timestamps.get_append('y');
 1.35741 +          }
 1.35742 +          av_close_input_file(format_ctx); format_ctx = 0;
 1.35743 +          return *this;
 1.35744 +        }
 1.35745 +
 1.35746 +        for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
 1.35747 +               format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
 1.35748 +        if (vstream==(int)format_ctx->nb_streams) {
 1.35749 +          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
 1.35750 +                     "Trying with external ffmpeg executable.",
 1.35751 +                     pixel_type(),filename);
 1.35752 +          av_close_input_file(format_ctx); format_ctx = 0;
 1.35753 +          return load_ffmpeg_external(filename);
 1.35754 +        }
 1.35755 +        codec_ctx = format_ctx->streams[vstream]->codec;
 1.35756 +        codec = avcodec_find_decoder(codec_ctx->codec_id);
 1.35757 +        if (!codec) {
 1.35758 +          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
 1.35759 +                     "Trying with external ffmpeg executable.",
 1.35760 +                     pixel_type(),filename);
 1.35761 +          return load_ffmpeg_external(filename);
 1.35762 +        }
 1.35763 +        if (avcodec_open(codec_ctx,codec)<0) { // Open codec
 1.35764 +          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
 1.35765 +                     "Trying with external ffmpeg executable.",
 1.35766 +                     pixel_type(),filename);
 1.35767 +          return load_ffmpeg_external(filename);
 1.35768 +        }
 1.35769 +      }
 1.35770 +
 1.35771 +      // Read video frames
 1.35772 +      const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 1.35773 +      uint8_t *const buffer = new uint8_t[numBytes];
 1.35774 +      avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 1.35775 +      const T foo = (T)0;
 1.35776 +      AVPacket packet;
 1.35777 +      for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
 1.35778 +        if (packet.stream_index==(int)vstream) {
 1.35779 +          int decoded = 0;
 1.35780 +          avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
 1.35781 +          if (decoded) {
 1.35782 +            if (frame==next_frame) {
 1.35783 +              SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
 1.35784 +                                             codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
 1.35785 +              sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
 1.35786 +              if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
 1.35787 +                CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
 1.35788 +                insert(next_image._get_permute_axes("yzvx",foo));
 1.35789 +              } else {
 1.35790 +                CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
 1.35791 +                insert(next_image._get_permute_axes("yzvx",foo));
 1.35792 +              }
 1.35793 +              next_frame+=nstep_frame;
 1.35794 +            }
 1.35795 +            ++frame;
 1.35796 +          }
 1.35797 +          av_free_packet(&packet);
 1.35798 +          if (next_frame>nlast_frame) break;
 1.35799 +        }
 1.35800 +      }
 1.35801 +      delete[] buffer;
 1.35802 +#endif
 1.35803 +      return *this;
 1.35804 +    }
 1.35805 +
 1.35806 +    static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35807 +                                       const unsigned int step_frame=1, const bool pixel_format=true) {
 1.35808 +      return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
 1.35809 +    }
 1.35810 +
 1.35811 +    //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
 1.35812 +    CImgList<T>& load_ffmpeg_external(const char *const filename) {
 1.35813 +      if (!filename)
 1.35814 +        throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
 1.35815 +                                    pixel_type());
 1.35816 +      char command[1024], filetmp[512], filetmp2[512];
 1.35817 +      cimg_std::FILE *file = 0;
 1.35818 +      do {
 1.35819 +        cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.35820 +        cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 1.35821 +        if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
 1.35822 +      } while (file);
 1.35823 +      cimg_std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
 1.35824 +#if cimg_OS!=2
 1.35825 +      cimg_std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
 1.35826 +#else
 1.35827 +      cimg_std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
 1.35828 +#endif
 1.35829 +      cimg::system(command,0);
 1.35830 +      const unsigned int odebug = cimg::exception_mode();
 1.35831 +      cimg::exception_mode() = 0;
 1.35832 +      assign();
 1.35833 +      unsigned int i = 1;
 1.35834 +      for (bool stopflag = false; !stopflag; ++i) {
 1.35835 +        cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
 1.35836 +        CImg<T> img;
 1.35837 +        try { img.load_pnm(filetmp2); }
 1.35838 +        catch (CImgException&) { stopflag = true; }
 1.35839 +        if (img) { insert(img); cimg_std::remove(filetmp2); }
 1.35840 +      }
 1.35841 +      cimg::exception_mode() = odebug;
 1.35842 +      if (is_empty())
 1.35843 +        throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
 1.35844 +                              "Check the filename and if the 'ffmpeg' tool is installed on your system.",
 1.35845 +                              pixel_type(),filename);
 1.35846 +      return *this;
 1.35847 +    }
 1.35848 +
 1.35849 +    static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
 1.35850 +      return CImgList<T>().load_ffmpeg_external(filename);
 1.35851 +    }
 1.35852 +
 1.35853 +    //! Load a gzipped list, using external tool 'gunzip'.
 1.35854 +    CImgList<T>& load_gzip_external(const char *const filename) {
 1.35855 +      if (!filename)
 1.35856 +        throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
 1.35857 +                              pixel_type());
 1.35858 +      char command[1024], filetmp[512], body[512];
 1.35859 +      const char
 1.35860 +        *ext = cimg::split_filename(filename,body),
 1.35861 +        *ext2 = cimg::split_filename(body,0);
 1.35862 +      cimg_std::FILE *file = 0;
 1.35863 +      do {
 1.35864 +        if (!cimg::strcasecmp(ext,"gz")) {
 1.35865 +          if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.35866 +                                  cimg::filenamerand(),ext2);
 1.35867 +          else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.35868 +                                  cimg::filenamerand());
 1.35869 +        } else {
 1.35870 +           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.35871 +                                  cimg::filenamerand(),ext);
 1.35872 +           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.35873 +                             cimg::filenamerand());
 1.35874 +        }
 1.35875 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.35876 +      } while (file);
 1.35877 +      cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 1.35878 +      cimg::system(command);
 1.35879 +      if (!(file = cimg_std::fopen(filetmp,"rb"))) {
 1.35880 +        cimg::fclose(cimg::fopen(filename,"r"));
 1.35881 +        throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
 1.35882 +                              pixel_type(),filename);
 1.35883 +      } else cimg::fclose(file);
 1.35884 +      load(filetmp);
 1.35885 +      cimg_std::remove(filetmp);
 1.35886 +      return *this;
 1.35887 +    }
 1.35888 +
 1.35889 +    static CImgList<T> get_load_gzip_external(const char *const filename) {
 1.35890 +      return CImgList<T>().load_gzip_external(filename);
 1.35891 +    }
 1.35892 +
 1.35893 +    //! Load a 3D object from a .OFF file.
 1.35894 +    template<typename tf, typename tc>
 1.35895 +    CImgList<T>& load_off(const char *const filename,
 1.35896 +                          CImgList<tf>& primitives, CImgList<tc>& colors,
 1.35897 +                          const bool invert_faces=false) {
 1.35898 +      return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
 1.35899 +    }
 1.35900 +
 1.35901 +    template<typename tf, typename tc>
 1.35902 +      static CImgList<T> get_load_off(const char *const filename,
 1.35903 +                                      CImgList<tf>& primitives, CImgList<tc>& colors,
 1.35904 +                                      const bool invert_faces=false) {
 1.35905 +      return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
 1.35906 +    }
 1.35907 +
 1.35908 +    //! Load a TIFF file.
 1.35909 +    CImgList<T>& load_tiff(const char *const filename,
 1.35910 +                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35911 +                           const unsigned int step_frame=1) {
 1.35912 +      const unsigned int
 1.35913 +        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 1.35914 +        nstep_frame = step_frame?step_frame:1;
 1.35915 +      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 1.35916 +#ifndef cimg_use_tiff
 1.35917 +      if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
 1.35918 +        throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 1.35919 +                                    "('cimg_use_tiff' must be defined).",
 1.35920 +                                    pixel_type(),filename);
 1.35921 +      return assign(CImg<T>::get_load_tiff(filename));
 1.35922 +#else
 1.35923 +      TIFF *tif = TIFFOpen(filename,"r");
 1.35924 +      if (tif) {
 1.35925 +        unsigned int nb_images = 0;
 1.35926 +        do ++nb_images; while (TIFFReadDirectory(tif));
 1.35927 +        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 1.35928 +          cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 1.35929 +                     pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 1.35930 +        if (nfirst_frame>=nb_images) return assign();
 1.35931 +        if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 1.35932 +        assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
 1.35933 +        TIFFSetDirectory(tif,0);
 1.35934 +#if cimg_debug>=3
 1.35935 +        TIFFSetWarningHandler(0);
 1.35936 +        TIFFSetErrorHandler(0);
 1.35937 +#endif
 1.35938 +        cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
 1.35939 +        TIFFClose(tif);
 1.35940 +      } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
 1.35941 +                                 pixel_type(),filename);
 1.35942 +      return *this;
 1.35943 +#endif
 1.35944 +    }
 1.35945 +
 1.35946 +    static CImgList<T> get_load_tiff(const char *const filename,
 1.35947 +                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.35948 +                                     const unsigned int step_frame=1) {
 1.35949 +      return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 1.35950 +    }
 1.35951 +
 1.35952 +    //! Save an image list into a file.
 1.35953 +    /**
 1.35954 +       Depending on the extension of the given filename, a file format is chosen for the output file.
 1.35955 +    **/
 1.35956 +    const CImgList<T>& save(const char *const filename, const int number=-1) const {
 1.35957 +      if (is_empty())
 1.35958 +        throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
 1.35959 +                                    pixel_type(),filename?filename:"(null)",size,data);
 1.35960 +      if (!filename)
 1.35961 +        throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
 1.35962 +                                    pixel_type(),size,data);
 1.35963 +      const char *ext = cimg::split_filename(filename);
 1.35964 +      char nfilename[1024];
 1.35965 +      const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
 1.35966 +#ifdef cimglist_save_plugin
 1.35967 +      cimglist_save_plugin(fn);
 1.35968 +#endif
 1.35969 +#ifdef cimglist_save_plugin1
 1.35970 +      cimglist_save_plugin1(fn);
 1.35971 +#endif
 1.35972 +#ifdef cimglist_save_plugin2
 1.35973 +      cimglist_save_plugin2(fn);
 1.35974 +#endif
 1.35975 +#ifdef cimglist_save_plugin3
 1.35976 +      cimglist_save_plugin3(fn);
 1.35977 +#endif
 1.35978 +#ifdef cimglist_save_plugin4
 1.35979 +      cimglist_save_plugin4(fn);
 1.35980 +#endif
 1.35981 +#ifdef cimglist_save_plugin5
 1.35982 +      cimglist_save_plugin5(fn);
 1.35983 +#endif
 1.35984 +#ifdef cimglist_save_plugin6
 1.35985 +      cimglist_save_plugin6(fn);
 1.35986 +#endif
 1.35987 +#ifdef cimglist_save_plugin7
 1.35988 +      cimglist_save_plugin7(fn);
 1.35989 +#endif
 1.35990 +#ifdef cimglist_save_plugin8
 1.35991 +      cimglist_save_plugin8(fn);
 1.35992 +#endif
 1.35993 +#ifdef cimg_use_tiff
 1.35994 +      if (!cimg::strcasecmp(ext,"tif") ||
 1.35995 +          !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
 1.35996 +#endif
 1.35997 +      if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 1.35998 +      if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
 1.35999 +      if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 1.36000 +      if (!cimg::strcasecmp(ext,"avi") ||
 1.36001 +          !cimg::strcasecmp(ext,"mov") ||
 1.36002 +          !cimg::strcasecmp(ext,"asf") ||
 1.36003 +          !cimg::strcasecmp(ext,"divx") ||
 1.36004 +          !cimg::strcasecmp(ext,"flv") ||
 1.36005 +          !cimg::strcasecmp(ext,"mpg") ||
 1.36006 +          !cimg::strcasecmp(ext,"m1v") ||
 1.36007 +          !cimg::strcasecmp(ext,"m2v") ||
 1.36008 +          !cimg::strcasecmp(ext,"m4v") ||
 1.36009 +          !cimg::strcasecmp(ext,"mjp") ||
 1.36010 +          !cimg::strcasecmp(ext,"mkv") ||
 1.36011 +          !cimg::strcasecmp(ext,"mpe") ||
 1.36012 +          !cimg::strcasecmp(ext,"movie") ||
 1.36013 +          !cimg::strcasecmp(ext,"ogm") ||
 1.36014 +          !cimg::strcasecmp(ext,"qt") ||
 1.36015 +          !cimg::strcasecmp(ext,"rm") ||
 1.36016 +          !cimg::strcasecmp(ext,"vob") ||
 1.36017 +          !cimg::strcasecmp(ext,"wmv") ||
 1.36018 +          !cimg::strcasecmp(ext,"xvid") ||
 1.36019 +          !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
 1.36020 +      if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 1.36021 +      if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
 1.36022 +      return *this;
 1.36023 +    }
 1.36024 +
 1.36025 +    //! Save an image sequence, using FFMPEG library.
 1.36026 +    // This piece of code has been originally written by David. G. Starkweather.
 1.36027 +    const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.36028 +                                   const unsigned int fps=25) const {
 1.36029 +      if (is_empty())
 1.36030 +        throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
 1.36031 +                                    pixel_type(),filename?filename:"(null)",size,data);
 1.36032 +      if (!filename)
 1.36033 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
 1.36034 +                                    pixel_type(),size,data);
 1.36035 +      if (!fps)
 1.36036 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
 1.36037 +                                    pixel_type(),filename);
 1.36038 +      const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
 1.36039 +      if (first_frame>=size || nlast_frame>=size)
 1.36040 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
 1.36041 +                                    pixel_type(),filename,first_frame,last_frame,size);
 1.36042 +      for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
 1.36043 +        throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
 1.36044 +                                    pixel_type(),filename);
 1.36045 +
 1.36046 +#ifndef cimg_use_ffmpeg
 1.36047 +      return save_ffmpeg_external(filename,first_frame,last_frame);
 1.36048 +#else
 1.36049 +      avcodec_register_all();
 1.36050 +      av_register_all();
 1.36051 +      const int
 1.36052 +        frame_dimx = data[first_frame].dimx(),
 1.36053 +        frame_dimy = data[first_frame].dimy(),
 1.36054 +        frame_dimv = data[first_frame].dimv();
 1.36055 +      if (frame_dimv!=1 && frame_dimv!=3)
 1.36056 +        throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
 1.36057 +                                    pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
 1.36058 +
 1.36059 +      PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
 1.36060 +      PixelFormat src_pxl_fmt  = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
 1.36061 +
 1.36062 +      int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
 1.36063 +      AVOutputFormat *fmt = 0;
 1.36064 +      fmt = guess_format(0,filename,0);
 1.36065 +      if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
 1.36066 +      if (!fmt)
 1.36067 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
 1.36068 +                                    pixel_type(),filename);
 1.36069 +
 1.36070 +      AVFormatContext *oc = 0;
 1.36071 +      oc = av_alloc_format_context();
 1.36072 +      if (!oc) // Failed to allocate format context.
 1.36073 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
 1.36074 +                              pixel_type(),filename);
 1.36075 +
 1.36076 +      AVCodec *codec = 0;
 1.36077 +      AVFrame *picture = 0;
 1.36078 +      AVFrame *tmp_pict = 0;
 1.36079 +      oc->oformat = fmt;
 1.36080 +      cimg_std::sprintf(oc->filename,"%s",filename);
 1.36081 +
 1.36082 +      // Add video stream.
 1.36083 +      int stream_index = 0;
 1.36084 +      AVStream *video_str = 0;
 1.36085 +      if (fmt->video_codec!=CODEC_ID_NONE) {
 1.36086 +        video_str = av_new_stream(oc,stream_index);
 1.36087 +        if (!video_str) { // Failed to allocate stream.
 1.36088 +          av_free(oc);
 1.36089 +          throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
 1.36090 +                                pixel_type(),filename);
 1.36091 +        }
 1.36092 +      } else { // No codec identified.
 1.36093 +        av_free(oc);
 1.36094 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
 1.36095 +                              pixel_type(),filename);
 1.36096 +      }
 1.36097 +
 1.36098 +      AVCodecContext *c = video_str->codec;
 1.36099 +      c->codec_id = fmt->video_codec;
 1.36100 +      c->codec_type = CODEC_TYPE_VIDEO;
 1.36101 +      c->bit_rate = 400000;
 1.36102 +      c->width = frame_dimx;
 1.36103 +      c->height = frame_dimy;
 1.36104 +      c->time_base.num = 1;
 1.36105 +      c->time_base.den = fps;
 1.36106 +      c->gop_size = 12;
 1.36107 +      c->pix_fmt = dest_pxl_fmt;
 1.36108 +      if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
 1.36109 +      if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
 1.36110 +
 1.36111 +      if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
 1.36112 +        av_free(oc);
 1.36113 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
 1.36114 +                              pixel_type(),filename);
 1.36115 +      }
 1.36116 +
 1.36117 +      // Open codecs and alloc buffers.
 1.36118 +      codec = avcodec_find_encoder(c->codec_id);
 1.36119 +      if (!codec) { // Failed to find codec.
 1.36120 +        av_free(oc);
 1.36121 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
 1.36122 +                              pixel_type(),filename);
 1.36123 +      }
 1.36124 +      if (avcodec_open(c,codec)<0) // Failed to open codec.
 1.36125 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
 1.36126 +                              pixel_type(),filename);
 1.36127 +      tmp_pict = avcodec_alloc_frame();
 1.36128 +      if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
 1.36129 +        avcodec_close(video_str->codec);
 1.36130 +        av_free(oc);
 1.36131 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
 1.36132 +                              pixel_type(),filename);
 1.36133 +      }
 1.36134 +      tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
 1.36135 +      tmp_pict->type = FF_BUFFER_TYPE_USER;
 1.36136 +      int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
 1.36137 +      uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
 1.36138 +      if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
 1.36139 +        av_free(tmp_pict);
 1.36140 +        avcodec_close(video_str->codec);
 1.36141 +        av_free(oc);
 1.36142 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
 1.36143 +                              pixel_type(),filename);
 1.36144 +      }
 1.36145 +
 1.36146 +      // Associate buffer with tmp_pict.
 1.36147 +      avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
 1.36148 +      picture = avcodec_alloc_frame();
 1.36149 +      if (!picture) { // Failed to allocate picture frame.
 1.36150 +        av_free(tmp_pict->data[0]);
 1.36151 +        av_free(tmp_pict);
 1.36152 +        avcodec_close(video_str->codec);
 1.36153 +        av_free(oc);
 1.36154 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
 1.36155 +                              pixel_type(),filename);
 1.36156 +      }
 1.36157 +
 1.36158 +      int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
 1.36159 +      uint8_t *buffer = (uint8_t*)av_malloc(size);
 1.36160 +      if (!buffer) { // Failed to allocate picture frame buffer.
 1.36161 +        av_free(picture);
 1.36162 +        av_free(tmp_pict->data[0]);
 1.36163 +        av_free(tmp_pict);
 1.36164 +        avcodec_close(video_str->codec);
 1.36165 +        av_free(oc);
 1.36166 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
 1.36167 +                              pixel_type(),filename);
 1.36168 +      }
 1.36169 +
 1.36170 +      // Associate the buffer with picture.
 1.36171 +      avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
 1.36172 +
 1.36173 +      // Open file.
 1.36174 +      if (!(fmt->flags&AVFMT_NOFILE)) {
 1.36175 +        if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
 1.36176 +          throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
 1.36177 +                                pixel_type(),filename);
 1.36178 +      }
 1.36179 +
 1.36180 +      if (av_write_header(oc)<0)
 1.36181 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
 1.36182 +                              pixel_type(),filename);
 1.36183 +      double video_pts;
 1.36184 +      SwsContext *img_convert_context = 0;
 1.36185 +      img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
 1.36186 +                                           c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
 1.36187 +      if (!img_convert_context) { // Failed to get swscale context.
 1.36188 +        // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
 1.36189 +        av_free(picture->data);
 1.36190 +        av_free(picture);
 1.36191 +        av_free(tmp_pict->data[0]);
 1.36192 +        av_free(tmp_pict);
 1.36193 +        avcodec_close(video_str->codec);
 1.36194 +        av_free(oc);
 1.36195 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
 1.36196 +                              pixel_type(),filename);
 1.36197 +      }
 1.36198 +      int ret = 0, out_size;
 1.36199 +      uint8_t *video_outbuf = 0;
 1.36200 +      int video_outbuf_size = 1000000;
 1.36201 +      video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
 1.36202 +      if (!video_outbuf) {
 1.36203 +        // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
 1.36204 +        av_free(picture->data);
 1.36205 +        av_free(picture);
 1.36206 +        av_free(tmp_pict->data[0]);
 1.36207 +        av_free(tmp_pict);
 1.36208 +        avcodec_close(video_str->codec);
 1.36209 +        av_free(oc);
 1.36210 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
 1.36211 +                              pixel_type(),filename);
 1.36212 +      }
 1.36213 +
 1.36214 +      // Loop through each desired image in list.
 1.36215 +      for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
 1.36216 +        CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
 1.36217 +        if (src_pxl_fmt == PIX_FMT_RGB24) {
 1.36218 +          red = currentIm.get_shared_channel(0);
 1.36219 +          green = currentIm.get_shared_channel(1);
 1.36220 +          blue = currentIm.get_shared_channel(2);
 1.36221 +          cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
 1.36222 +            tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X]     = red(X,Y);
 1.36223 +            tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
 1.36224 +            tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
 1.36225 +          }
 1.36226 +        } else {
 1.36227 +          gray = currentIm.get_shared_channel(0);
 1.36228 +          cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
 1.36229 +        }
 1.36230 +
 1.36231 +        if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
 1.36232 +        else video_pts = 0.0;
 1.36233 +        if (!video_str) break;
 1.36234 +        if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
 1.36235 +        out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
 1.36236 +        if (out_size>0) {
 1.36237 +          AVPacket pkt;
 1.36238 +          av_init_packet(&pkt);
 1.36239 +          pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
 1.36240 +          if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
 1.36241 +          pkt.stream_index = video_str->index;
 1.36242 +          pkt.data = video_outbuf;
 1.36243 +          pkt.size = out_size;
 1.36244 +          ret = av_write_frame(oc,&pkt);
 1.36245 +        } else if (out_size<0) break;
 1.36246 +        if (ret) break; // Error occured in writing frame.
 1.36247 +      }
 1.36248 +
 1.36249 +      // Close codec.
 1.36250 +      if (video_str) {
 1.36251 +        avcodec_close(video_str->codec);
 1.36252 +        av_free(picture->data[0]);
 1.36253 +        av_free(picture);
 1.36254 +        av_free(tmp_pict->data[0]);
 1.36255 +        av_free(tmp_pict);
 1.36256 +      }
 1.36257 +      if (av_write_trailer(oc)<0)
 1.36258 +        throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
 1.36259 +                              pixel_type(),filename);
 1.36260 +      av_freep(&oc->streams[stream_index]->codec);
 1.36261 +      av_freep(&oc->streams[stream_index]);
 1.36262 +      if (!(fmt->flags&AVFMT_NOFILE)) {
 1.36263 +        /*if (url_fclose(oc->pb)<0)
 1.36264 +          throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
 1.36265 +          pixel_type(),filename);
 1.36266 +        */
 1.36267 +      }
 1.36268 +      av_free(oc);
 1.36269 +      av_free(video_outbuf);
 1.36270 +#endif
 1.36271 +      return *this;
 1.36272 +    }
 1.36273 +
 1.36274 +    // Save an image sequence into a YUV file (internal).
 1.36275 +    const CImgList<T>& _save_yuv(cimg_std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
 1.36276 +      if (is_empty())
 1.36277 +        throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
 1.36278 +                                    pixel_type(),filename?filename:"(FILE*)",size,data);
 1.36279 +      if (!file && !filename)
 1.36280 +        throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
 1.36281 +                                    pixel_type(),size,data);
 1.36282 +      if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
 1.36283 +        throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
 1.36284 +                                    pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
 1.36285 +
 1.36286 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.36287 +      cimglist_for(*this,l) {
 1.36288 +        CImg<ucharT> YCbCr((*this)[l]);
 1.36289 +        if (rgb2yuv) YCbCr.RGBtoYCbCr();
 1.36290 +        cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
 1.36291 +        cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
 1.36292 +                     YCbCr.width*YCbCr.height/2,nfile);
 1.36293 +      }
 1.36294 +      if (!file) cimg::fclose(nfile);
 1.36295 +      return *this;
 1.36296 +    }
 1.36297 +
 1.36298 +    //! Save an image sequence into a YUV file.
 1.36299 +    const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
 1.36300 +      return _save_yuv(0,filename,rgb2yuv);
 1.36301 +    }
 1.36302 +
 1.36303 +    //! Save an image sequence into a YUV file.
 1.36304 +    const CImgList<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
 1.36305 +      return _save_yuv(file,0,rgb2yuv);
 1.36306 +    }
 1.36307 +
 1.36308 +    //! Save an image list into a .cimg file.
 1.36309 +    /**
 1.36310 +       A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images.
 1.36311 +       \param filename : name of the output file.
 1.36312 +       \return A reference to the current CImgList instance is returned.
 1.36313 +    **/
 1.36314 +    const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename, const bool compression) const {
 1.36315 +      if (is_empty())
 1.36316 +        throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
 1.36317 +                                    pixel_type(),filename?filename:"(FILE*)",size,data);
 1.36318 +      if (!file && !filename)
 1.36319 +        throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
 1.36320 +                                    pixel_type(),size,data);
 1.36321 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.36322 +      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
 1.36323 +      if (cimg_std::strstr(ptype,"unsigned")==ptype) cimg_std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
 1.36324 +      else cimg_std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
 1.36325 +      cimglist_for(*this,l) {
 1.36326 +        const CImg<T>& img = data[l];
 1.36327 +        cimg_std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
 1.36328 +        if (img.data) {
 1.36329 +          CImg<T> tmp;
 1.36330 +          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
 1.36331 +          const CImg<T>& ref = cimg::endianness()?tmp:img;
 1.36332 +          bool compressed = false;
 1.36333 +          if (compression) {
 1.36334 +#ifdef cimg_use_zlib
 1.36335 +            const unsigned long siz = sizeof(T)*ref.size();
 1.36336 +            unsigned long csiz = siz + siz/10 + 16;
 1.36337 +            Bytef *const cbuf = new Bytef[csiz];
 1.36338 +            if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
 1.36339 +              cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
 1.36340 +                       pixel_type(),filename?filename:"(FILE*)");
 1.36341 +              compressed = false;
 1.36342 +            } else {
 1.36343 +              cimg_std::fprintf(nfile," #%lu\n",csiz);
 1.36344 +              cimg::fwrite(cbuf,csiz,nfile);
 1.36345 +              delete[] cbuf;
 1.36346 +              compressed = true;
 1.36347 +            }
 1.36348 +#else
 1.36349 +            cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
 1.36350 +                       "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
 1.36351 +                       pixel_type(),filename?filename:"(FILE*)");
 1.36352 +            compressed = false;
 1.36353 +#endif
 1.36354 +          }
 1.36355 +          if (!compressed) {
 1.36356 +            cimg_std::fputc('\n',nfile);
 1.36357 +            cimg::fwrite(ref.data,ref.size(),nfile);
 1.36358 +          }
 1.36359 +        } else cimg_std::fputc('\n',nfile);
 1.36360 +      }
 1.36361 +      if (!file) cimg::fclose(nfile);
 1.36362 +      return *this;
 1.36363 +    }
 1.36364 +
 1.36365 +    //! Save an image list into a CImg file (RAW binary file + simple header)
 1.36366 +    const CImgList<T>& save_cimg(cimg_std::FILE *file, const bool compress=false) const {
 1.36367 +      return _save_cimg(file,0,compress);
 1.36368 +    }
 1.36369 +
 1.36370 +    //! Save an image list into a CImg file (RAW binary file + simple header)
 1.36371 +    const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
 1.36372 +      return _save_cimg(0,filename,compress);
 1.36373 +    }
 1.36374 +
 1.36375 +    // Insert the instance image into into an existing .cimg file, at specified coordinates.
 1.36376 +    const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename,
 1.36377 +                                 const unsigned int n0,
 1.36378 +                                 const unsigned int x0, const unsigned int y0,
 1.36379 +                                 const unsigned int z0, const unsigned int v0) const {
 1.36380 +#define _cimg_save_cimg_case(Ts,Tss) \
 1.36381 +      if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
 1.36382 +        for (unsigned int l=0; l<lmax; ++l) { \
 1.36383 +          j = 0; while((i=cimg_std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
 1.36384 +          W = H = D = V = 0; \
 1.36385 +          if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
 1.36386 +            throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
 1.36387 +                                  pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
 1.36388 +          if (W*H*D*V>0) { \
 1.36389 +            if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
 1.36390 +            else { \
 1.36391 +              const CImg<T>& img = (*this)[l-n0]; \
 1.36392 +              const T *ptrs = img.data; \
 1.36393 +              const unsigned int \
 1.36394 +                x1 = x0 + img.width - 1, \
 1.36395 +                y1 = y0 + img.height - 1, \
 1.36396 +                z1 = z0 + img.depth - 1, \
 1.36397 +                v1 = v0 + img.dim - 1, \
 1.36398 +                nx1 = x1>=W?W-1:x1, \
 1.36399 +                ny1 = y1>=H?H-1:y1, \
 1.36400 +                nz1 = z1>=D?D-1:z1, \
 1.36401 +                nv1 = v1>=V?V-1:v1; \
 1.36402 +              CImg<Tss> raw(1+nx1-x0); \
 1.36403 +              const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
 1.36404 +              if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
 1.36405 +              for (unsigned int v=1+nv1-v0; v; --v) { \
 1.36406 +                const unsigned int skipzb = z0*W*H*sizeof(Tss); \
 1.36407 +                if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
 1.36408 +                for (unsigned int z=1+nz1-z0; z; --z) { \
 1.36409 +                  const unsigned int skipyb = y0*W*sizeof(Tss); \
 1.36410 +                  if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
 1.36411 +                  for (unsigned int y=1+ny1-y0; y; --y) { \
 1.36412 +                    const unsigned int skipxb = x0*sizeof(Tss); \
 1.36413 +                    if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
 1.36414 +                    raw.assign(ptrs, raw.width); \
 1.36415 +                    ptrs+=img.width; \
 1.36416 +                    if (endian) cimg::invert_endianness(raw.data,raw.width); \
 1.36417 +                    cimg::fwrite(raw.data,raw.width,nfile); \
 1.36418 +                    const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
 1.36419 +                    if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
 1.36420 +                  } \
 1.36421 +                  const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
 1.36422 +                  if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
 1.36423 +                } \
 1.36424 +                const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
 1.36425 +                if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
 1.36426 +              } \
 1.36427 +              const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
 1.36428 +              if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
 1.36429 +            } \
 1.36430 +          } \
 1.36431 +        } \
 1.36432 +        saved = true; \
 1.36433 +      }
 1.36434 +      if (is_empty())
 1.36435 +        throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
 1.36436 +                                    pixel_type(),filename?filename:"(FILE*)",size,data);
 1.36437 +      if (!file && !filename)
 1.36438 +        throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
 1.36439 +                                    pixel_type(),size,data);
 1.36440 +      typedef unsigned char uchar;
 1.36441 +      typedef unsigned short ushort;
 1.36442 +      typedef unsigned int uint;
 1.36443 +      typedef unsigned long ulong;
 1.36444 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
 1.36445 +      bool saved = false, endian = cimg::endianness();
 1.36446 +      char tmp[256], str_pixeltype[256], str_endian[256];
 1.36447 +      unsigned int j, err, N, W, H, D, V;
 1.36448 +      int i;
 1.36449 +      j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
 1.36450 +      err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
 1.36451 +      if (err<2) {
 1.36452 +        if (!file) cimg::fclose(nfile);
 1.36453 +        throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
 1.36454 +                              pixel_type(),filename?filename:"(FILE*)");
 1.36455 +      }
 1.36456 +      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
 1.36457 +      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
 1.36458 +      const unsigned int lmax = cimg::min(N,n0+size);
 1.36459 +      _cimg_save_cimg_case("bool",bool);
 1.36460 +      _cimg_save_cimg_case("unsigned_char",uchar);
 1.36461 +      _cimg_save_cimg_case("uchar",uchar);
 1.36462 +      _cimg_save_cimg_case("char",char);
 1.36463 +      _cimg_save_cimg_case("unsigned_short",ushort);
 1.36464 +      _cimg_save_cimg_case("ushort",ushort);
 1.36465 +      _cimg_save_cimg_case("short",short);
 1.36466 +      _cimg_save_cimg_case("unsigned_int",uint);
 1.36467 +      _cimg_save_cimg_case("uint",uint);
 1.36468 +      _cimg_save_cimg_case("int",int);
 1.36469 +      _cimg_save_cimg_case("unsigned_long",ulong);
 1.36470 +      _cimg_save_cimg_case("ulong",ulong);
 1.36471 +      _cimg_save_cimg_case("long",long);
 1.36472 +      _cimg_save_cimg_case("float",float);
 1.36473 +      _cimg_save_cimg_case("double",double);
 1.36474 +      if (!saved) {
 1.36475 +        if (!file) cimg::fclose(nfile);
 1.36476 +        throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
 1.36477 +                              pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
 1.36478 +      }
 1.36479 +      if (!file) cimg::fclose(nfile);
 1.36480 +      return *this;
 1.36481 +    }
 1.36482 +
 1.36483 +    //! Insert the instance image into into an existing .cimg file, at specified coordinates.
 1.36484 +    const CImgList<T>& save_cimg(const char *const filename,
 1.36485 +                                 const unsigned int n0,
 1.36486 +                                 const unsigned int x0, const unsigned int y0,
 1.36487 +                                 const unsigned int z0, const unsigned int v0) const {
 1.36488 +      return _save_cimg(0,filename,n0,x0,y0,z0,v0);
 1.36489 +    }
 1.36490 +
 1.36491 +    //! Insert the instance image into into an existing .cimg file, at specified coordinates.
 1.36492 +    const CImgList<T>& save_cimg(cimg_std::FILE *const file,
 1.36493 +                                 const unsigned int n0,
 1.36494 +                                 const unsigned int x0, const unsigned int y0,
 1.36495 +                                 const unsigned int z0, const unsigned int v0) const {
 1.36496 +      return _save_cimg(file,0,n0,x0,y0,z0,v0);
 1.36497 +    }
 1.36498 +
 1.36499 +    // Create an empty .cimg file with specified dimensions (internal)
 1.36500 +    static void _save_empty_cimg(cimg_std::FILE *const file, const char *const filename,
 1.36501 +                                const unsigned int nb,
 1.36502 +                                const unsigned int dx, const unsigned int dy,
 1.36503 +                                const unsigned int dz, const unsigned int dv) {
 1.36504 +      cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 1.36505 +      const unsigned int siz = dx*dy*dz*dv*sizeof(T);
 1.36506 +      cimg_std::fprintf(nfile,"%u %s\n",nb,pixel_type());
 1.36507 +      for (unsigned int i=nb; i; --i) {
 1.36508 +        cimg_std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
 1.36509 +        for (unsigned int off=siz; off; --off) cimg_std::fputc(0,nfile);
 1.36510 +      }
 1.36511 +      if (!file) cimg::fclose(nfile);
 1.36512 +    }
 1.36513 +
 1.36514 +    //! Create an empty .cimg file with specified dimensions.
 1.36515 +    static void save_empty_cimg(const char *const filename,
 1.36516 +                                const unsigned int nb,
 1.36517 +                                const unsigned int dx, const unsigned int dy=1,
 1.36518 +                                const unsigned int dz=1, const unsigned int dv=1) {
 1.36519 +      return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
 1.36520 +    }
 1.36521 +
 1.36522 +    //! Create an empty .cimg file with specified dimensions.
 1.36523 +    static void save_empty_cimg(cimg_std::FILE *const file,
 1.36524 +                                const unsigned int nb,
 1.36525 +                                const unsigned int dx, const unsigned int dy=1,
 1.36526 +                                const unsigned int dz=1, const unsigned int dv=1) {
 1.36527 +      return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
 1.36528 +    }
 1.36529 +
 1.36530 +    //! Save a file in TIFF format.
 1.36531 +#ifdef cimg_use_tiff
 1.36532 +    const CImgList<T>& save_tiff(const char *const filename) const {
 1.36533 +      if (is_empty())
 1.36534 +        throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
 1.36535 +                                    pixel_type(),filename?filename:"(null)",size,data);
 1.36536 +      if (!filename)
 1.36537 +        throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
 1.36538 +                                    pixel_type(),size,data);
 1.36539 +      TIFF *tif = TIFFOpen(filename,"w");
 1.36540 +      if (tif) {
 1.36541 +        for (unsigned int dir=0, l=0; l<size; ++l) {
 1.36542 +          const CImg<T>& img = (*this)[l];
 1.36543 +          if (img) {
 1.36544 +            if (img.depth==1) img._save_tiff(tif,dir++);
 1.36545 +            else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
 1.36546 +          }
 1.36547 +        }
 1.36548 +        TIFFClose(tif);
 1.36549 +      } else
 1.36550 +        throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
 1.36551 +                            pixel_type(),filename);
 1.36552 +      return *this;
 1.36553 +    }
 1.36554 +#endif
 1.36555 +
 1.36556 +    //! Save an image list as a gzipped file, using external tool 'gzip'.
 1.36557 +    const CImgList<T>& save_gzip_external(const char *const filename) const {
 1.36558 +      if (!filename)
 1.36559 +        throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 1.36560 +                              pixel_type());
 1.36561 +      char command[1024], filetmp[512], body[512];
 1.36562 +      const char
 1.36563 +        *ext = cimg::split_filename(filename,body),
 1.36564 +        *ext2 = cimg::split_filename(body,0);
 1.36565 +      cimg_std::FILE *file;
 1.36566 +      do {
 1.36567 +        if (!cimg::strcasecmp(ext,"gz")) {
 1.36568 +          if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.36569 +                                  cimg::filenamerand(),ext2);
 1.36570 +          else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.36571 +                            cimg::filenamerand());
 1.36572 +        } else {
 1.36573 +          if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.36574 +                                 cimg::filenamerand(),ext);
 1.36575 +          else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 1.36576 +                                 cimg::filenamerand());
 1.36577 +        }
 1.36578 +        if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
 1.36579 +      } while (file);
 1.36580 +      save(filetmp);
 1.36581 +      cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 1.36582 +      cimg::system(command);
 1.36583 +      file = cimg_std::fopen(filename,"rb");
 1.36584 +      if (!file)
 1.36585 +        throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
 1.36586 +                              pixel_type(),filename);
 1.36587 +      else cimg::fclose(file);
 1.36588 +      cimg_std::remove(filetmp);
 1.36589 +      return *this;
 1.36590 +    }
 1.36591 +
 1.36592 +    //! Save an image list into a OFF file.
 1.36593 +    template<typename tf, typename tc>
 1.36594 +    const CImgList<T>& save_off(const char *const filename,
 1.36595 +                                const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 1.36596 +      get_append('x','y').save_off(filename,primitives,colors,invert_faces);
 1.36597 +      return *this;
 1.36598 +    }
 1.36599 +
 1.36600 +    //! Save an image list into a OFF file.
 1.36601 +    template<typename tf, typename tc>
 1.36602 +    const CImgList<T>& save_off(cimg_std::FILE *const file,
 1.36603 +                                const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 1.36604 +      get_append('x','y').save_off(file,primitives,colors,invert_faces);
 1.36605 +      return *this;
 1.36606 +    }
 1.36607 +
 1.36608 +    //! Save an image sequence using the external tool 'ffmpeg'.
 1.36609 +    const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 1.36610 +                                            const char *const codec="mpeg2video") const {
 1.36611 +      if (is_empty())
 1.36612 +        throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
 1.36613 +                                    pixel_type(),filename?filename:"(null)",size,data);
 1.36614 +      if (!filename)
 1.36615 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
 1.36616 +                                    pixel_type(),size,data);
 1.36617 +      char command[1024], filetmp[512], filetmp2[512];
 1.36618 +      cimg_std::FILE *file = 0;
 1.36619 +      const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
 1.36620 +      if (first_frame>=size || nlast_frame>=size)
 1.36621 +        throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
 1.36622 +                                    pixel_type(),filename,first_frame,last_frame,size);
 1.36623 +      for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
 1.36624 +        throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
 1.36625 +                                    pixel_type(),filename);
 1.36626 +      do {
 1.36627 +        cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 1.36628 +        cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 1.36629 +        if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
 1.36630 +      } while (file);
 1.36631 +      for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
 1.36632 +        cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
 1.36633 +        if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
 1.36634 +        else data[l].save_pnm(filetmp2);
 1.36635 +      }
 1.36636 +#if cimg_OS!=2
 1.36637 +      cimg_std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
 1.36638 +#else
 1.36639 +      cimg_std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
 1.36640 +#endif
 1.36641 +      cimg::system(command);
 1.36642 +      file = cimg_std::fopen(filename,"rb");
 1.36643 +      if (!file)
 1.36644 +        throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
 1.36645 +                              pixel_type(),filename);
 1.36646 +      else cimg::fclose(file);
 1.36647 +      cimglist_for(*this,lll) { cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); cimg_std::remove(filetmp2); }
 1.36648 +      return *this;
 1.36649 +    }
 1.36650 +
 1.36651 +   };
 1.36652 +
 1.36653 +  /*
 1.36654 +   #---------------------------------------------
 1.36655 +   #
 1.36656 +   # Completion of previously declared functions
 1.36657 +   #
 1.36658 +   #----------------------------------------------
 1.36659 +  */
 1.36660 +
 1.36661 +namespace cimg {
 1.36662 +
 1.36663 +  //! Display a dialog box, where a user can click standard buttons.
 1.36664 +  /**
 1.36665 +     Up to 6 buttons can be defined in the dialog window.
 1.36666 +     This function returns when a user clicked one of the button or closed the dialog window.
 1.36667 +     \param title = Title of the dialog window.
 1.36668 +     \param msg = Main message displayed inside the dialog window.
 1.36669 +     \param button1_txt = Label of the 1st button.
 1.36670 +     \param button2_txt = Label of the 2nd button.
 1.36671 +     \param button3_txt = Label of the 3rd button.
 1.36672 +     \param button4_txt = Label of the 4th button.
 1.36673 +     \param button5_txt = Label of the 5th button.
 1.36674 +     \param button6_txt = Label of the 6th button.
 1.36675 +     \param logo = Logo image displayed at the left of the main message. This parameter is optional.
 1.36676 +     \param centering = Tell to center the dialog window on the screen.
 1.36677 +     \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user.
 1.36678 +     \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in
 1.36679 +     the dialog box. At least one button is necessary.
 1.36680 +  **/
 1.36681 +
 1.36682 +  template<typename t>
 1.36683 +  inline int dialog(const char *title, const char *msg,
 1.36684 +                    const char *button1_txt, const char *button2_txt,
 1.36685 +                    const char *button3_txt, const char *button4_txt,
 1.36686 +                    const char *button5_txt, const char *button6_txt,
 1.36687 +                    const CImg<t>& logo, const bool centering = false) {
 1.36688 +#if cimg_display!=0
 1.36689 +    const unsigned char
 1.36690 +      black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
 1.36691 +
 1.36692 +      // Create buttons and canvas graphics
 1.36693 +      CImgList<unsigned char> buttons, cbuttons, sbuttons;
 1.36694 +      if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13));
 1.36695 +      if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13));
 1.36696 +      if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13));
 1.36697 +      if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13));
 1.36698 +      if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13));
 1.36699 +      if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13));
 1.36700 +      }}}}}}
 1.36701 +      if (!buttons.size)
 1.36702 +        throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
 1.36703 +
 1.36704 +      unsigned int bw = 0, bh = 0;
 1.36705 +      cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
 1.36706 +      bw+=8; bh+=8;
 1.36707 +      if (bw<64) bw=64;
 1.36708 +      if (bw>128) bw=128;
 1.36709 +      if (bh<24) bh=24;
 1.36710 +      if (bh>48) bh=48;
 1.36711 +
 1.36712 +      CImg<unsigned char> button(bw,bh,1,3);
 1.36713 +      button.draw_rectangle(0,0,bw-1,bh-1,gray);
 1.36714 +      button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
 1.36715 +      button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
 1.36716 +      button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
 1.36717 +      CImg<unsigned char> sbutton(bw,bh,1,3);
 1.36718 +      sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
 1.36719 +      sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
 1.36720 +      sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
 1.36721 +      sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
 1.36722 +      sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
 1.36723 +      sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
 1.36724 +      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);
 1.36725 +      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);
 1.36726 +      CImg<unsigned char> cbutton(bw,bh,1,3);
 1.36727 +      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);
 1.36728 +      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);
 1.36729 +      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);
 1.36730 +
 1.36731 +      cimglist_for(buttons,ll) {
 1.36732 +        cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]));
 1.36733 +        sbuttons.insert(CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]));
 1.36734 +        buttons[ll] = CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]);
 1.36735 +      }
 1.36736 +
 1.36737 +      CImg<unsigned char> canvas;
 1.36738 +      if (msg) canvas = CImg<unsigned char>().draw_text(0,0,msg,black,gray,1,13);
 1.36739 +      const unsigned int
 1.36740 +        bwall = (buttons.size-1)*(12+bw) + bw,
 1.36741 +        w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
 1.36742 +        h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
 1.36743 +        lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
 1.36744 +        ly = (h-12-bh-logo.height)/2,
 1.36745 +        tx = lx+logo.width+12,
 1.36746 +        ty = (h-12-bh-canvas.height)/2,
 1.36747 +        bx = (w-bwall)/2,
 1.36748 +        by = h-12-bh;
 1.36749 +
 1.36750 +      if (canvas.data)
 1.36751 +        canvas = CImg<unsigned char>(w,h,1,3).
 1.36752 +          draw_rectangle(0,0,w-1,h-1,gray).
 1.36753 +          draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
 1.36754 +          draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
 1.36755 +          draw_image(tx,ty,canvas);
 1.36756 +      else
 1.36757 +        canvas = CImg<unsigned char>(w,h,1,3).
 1.36758 +          draw_rectangle(0,0,w-1,h-1,gray).
 1.36759 +          draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
 1.36760 +          draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
 1.36761 +      if (logo.data) canvas.draw_image(lx,ly,logo);
 1.36762 +
 1.36763 +      unsigned int xbuttons[6];
 1.36764 +      cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
 1.36765 +
 1.36766 +      // Open window and enter events loop
 1.36767 +      CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
 1.36768 +      if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
 1.36769 +                               (CImgDisplay::screen_dimy()-disp.dimy())/2);
 1.36770 +      bool stopflag = false, refresh = false;
 1.36771 +      int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
 1.36772 +      while (!disp.is_closed && !stopflag) {
 1.36773 +        if (refresh) {
 1.36774 +          if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
 1.36775 +          else {
 1.36776 +            if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
 1.36777 +            else canvas.display(disp);
 1.36778 +          }
 1.36779 +          refresh = false;
 1.36780 +        }
 1.36781 +        disp.wait(15);
 1.36782 +        if (disp.is_resized) disp.resize(disp);
 1.36783 +
 1.36784 +        if (disp.button&1)  {
 1.36785 +          oclicked = clicked;
 1.36786 +          clicked = -1;
 1.36787 +          cimglist_for(buttons,l)
 1.36788 +            if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
 1.36789 +                disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
 1.36790 +              clicked = selected = l;
 1.36791 +              refresh = true;
 1.36792 +            }
 1.36793 +          if (clicked!=oclicked) refresh = true;
 1.36794 +        } else if (clicked>=0) stopflag = true;
 1.36795 +
 1.36796 +        if (disp.key) {
 1.36797 +          oselected = selected;
 1.36798 +          switch (disp.key) {
 1.36799 +          case cimg::keyESC : selected=-1; stopflag=true; break;
 1.36800 +          case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
 1.36801 +          case cimg::keyTAB :
 1.36802 +          case cimg::keyARROWRIGHT :
 1.36803 +          case cimg::keyARROWDOWN : selected = (selected+1)%buttons.size; break;
 1.36804 +          case cimg::keyARROWLEFT :
 1.36805 +          case cimg::keyARROWUP : selected = (selected+buttons.size-1)%buttons.size; break;
 1.36806 +          }
 1.36807 +          disp.key = 0;
 1.36808 +          if (selected!=oselected) refresh = true;
 1.36809 +        }
 1.36810 +      }
 1.36811 +      if (!disp) selected = -1;
 1.36812 +      return selected;
 1.36813 +#else
 1.36814 +      cimg_std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
 1.36815 +      return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
 1.36816 +#endif
 1.36817 +  }
 1.36818 +
 1.36819 +  inline int dialog(const char *title, const char *msg,
 1.36820 +                    const char *button1_txt, const char *button2_txt, const char *button3_txt,
 1.36821 +                    const char *button4_txt, const char *button5_txt, const char *button6_txt,
 1.36822 +                    const bool centering) {
 1.36823 +    return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
 1.36824 +                  CImg<unsigned char>::logo40x38(),centering);
 1.36825 +  }
 1.36826 +
 1.36827 +  // End of cimg:: namespace
 1.36828 +}
 1.36829 +
 1.36830 +  // End of cimg_library:: namespace
 1.36831 +}
 1.36832 +
 1.36833 +#ifdef _cimg_redefine_min
 1.36834 +#define min(a,b) (((a)<(b))?(a):(b))
 1.36835 +#endif
 1.36836 +#ifdef _cimg_redefine_max
 1.36837 +#define max(a,b) (((a)>(b))?(a):(b))
 1.36838 +#endif
 1.36839 +
 1.36840 +#endif
 1.36841 +// Local Variables:
 1.36842 +// mode: c++
 1.36843 +// End: